package name.abuchen.portfolio.ui.views;
import java.time.LocalDate;
import java.util.StringJoiner;
import javax.inject.Inject;
import org.apache.commons.lang3.StringEscapeUtils;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.BrowserFunction;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.ToolBar;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.money.CurrencyConverter;
import name.abuchen.portfolio.money.CurrencyConverterImpl;
import name.abuchen.portfolio.money.ExchangeRateProviderFactory;
import name.abuchen.portfolio.money.Values;
import name.abuchen.portfolio.snapshot.ClientSnapshot;
import name.abuchen.portfolio.ui.AbstractFinanceView;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.PortfolioPlugin;
import name.abuchen.portfolio.ui.util.ClientFilterDropDown;
import name.abuchen.portfolio.ui.util.EmbeddedBrowser;
import name.abuchen.portfolio.util.ColorConversion;
public class HoldingsPieChartView extends AbstractFinanceView
{
@Inject
private ExchangeRateProviderFactory factory;
private EmbeddedBrowser browser;
private ClientFilterDropDown clientFilter;
@Override
protected String getDefaultTitle()
{
return Messages.LabelStatementOfAssetsHoldings;
}
@Override
public void notifyModelUpdated()
{
browser.refresh();
}
@Override
protected void addButtons(ToolBar toolBar)
{
this.clientFilter = new ClientFilterDropDown(toolBar, getClient(), getPreferenceStore(),
filter -> notifyModelUpdated());
}
@Override
protected Control createBody(Composite parent)
{
browser = new EmbeddedBrowser("/META-INF/html/pie.html"); //$NON-NLS-1$
return browser.createControl(parent, b -> new LoadDataFunction(b, "loadData")); //$NON-NLS-1$
}
private static final class JSColors
{
private static final int SIZE = 11;
private static final float STEP = 360.0f / (float) SIZE;
private static final float HUE = 262.3f;
private static final float SATURATION = 0.464f;
private static final float BRIGHTNESS = 0.886f;
private int nextSlice = 0;
public String next()
{
float brightness = Math.min(1.0f, BRIGHTNESS + (0.05f * (nextSlice / SIZE)));
return ColorConversion.toHex((HUE + (STEP * nextSlice++)) % 360f, SATURATION, brightness);
}
}
private final class LoadDataFunction extends BrowserFunction
{
private static final String ENTRY = "{\"label\":\"%s\"," //$NON-NLS-1$
+ "\"value\":%s," //$NON-NLS-1$
+ "\"color\":\"%s\"," //$NON-NLS-1$
+ "\"caption\":\"%s %s (%s)\"," //$NON-NLS-1$
+ "\"valueLabel\":\"%s\"" //$NON-NLS-1$
+ "}"; //$NON-NLS-1$
private LoadDataFunction(Browser browser, String name)
{
super(browser, name);
}
@Override
public Object function(Object[] arguments)
{
try
{
CurrencyConverter converter = new CurrencyConverterImpl(factory, getClient().getBaseCurrency());
Client filteredClient = clientFilter.getSelectedFilter().filter(getClient());
ClientSnapshot snapshot = ClientSnapshot.create(filteredClient, converter, LocalDate.now());
StringJoiner joiner = new StringJoiner(",", "[", "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
JSColors colors = new JSColors();
snapshot.getAssetPositions() //
.filter(p -> p.getValuation().getAmount() > 0) //
.sorted((l, r) -> Long.compare(r.getValuation().getAmount(),
l.getValuation().getAmount())) //
.forEach(p -> {
String name = StringEscapeUtils.escapeJson(p.getDescription());
String percentage = Values.Percent2.format(p.getShare());
joiner.add(String.format(ENTRY, name, //
p.getValuation().getAmount(), //
colors.next(), //
name, Values.Money.format(p.getValuation()), percentage, //
percentage));
});
return joiner.toString();
}
catch (Throwable e) // NOSONAR
{
PortfolioPlugin.log(e);
return "[]"; //$NON-NLS-1$
}
}
}
}