package name.abuchen.portfolio.ui.views.dataseries;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.ui.AbstractFinanceView;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.dialogs.ListSelectionDialog;
import name.abuchen.portfolio.ui.util.ConfigurationStore;
import name.abuchen.portfolio.ui.util.ConfigurationStore.ConfigurationStoreOwner;
import name.abuchen.portfolio.ui.util.SimpleAction;
/**
* The DataSeriesConfigurator manages the currently available set of data
* series.
*/
public class DataSeriesConfigurator implements ConfigurationStoreOwner
{
/**
* Listener for updates on data series.
*/
@FunctionalInterface
public interface Listener
{
/**
* Handles the update of data series.
*/
void onUpdate();
}
public static final String IDENTIFIER_POSTFIX = "-PICKER"; //$NON-NLS-1$
private final String identifier;
private final Client client;
private final IPreferenceStore preferences;
private final ConfigurationStore store;
private final List<DataSeriesConfigurator.Listener> listeners = new ArrayList<>();
private DataSeriesSet dataSeriesSet;
private List<DataSeries> selectedSeries = new ArrayList<>();
private Menu configContextMenu;
public DataSeriesConfigurator(AbstractFinanceView view, DataSeries.UseCase useCase)
{
this.identifier = view.getClass().getSimpleName() + IDENTIFIER_POSTFIX;
this.client = view.getClient();
this.preferences = view.getPreferenceStore();
this.store = new ConfigurationStore(identifier, client, preferences, this);
this.dataSeriesSet = new DataSeriesSet(client, preferences, useCase);
this.selectedSeries = new DataSeriesSerializer().fromString(dataSeriesSet, store.getActive());
view.getControl().addDisposeListener(e -> DataSeriesConfigurator.this.widgetDisposed());
}
public void addListener(DataSeriesConfigurator.Listener listener)
{
this.listeners.add(listener);
}
/* protected */ void fireUpdate()
{
listeners.forEach(l -> l.onUpdate());
store.updateActive(new DataSeriesSerializer().toString(selectedSeries));
}
public String getConfigurationName()
{
return store.getActiveName();
}
/**
* Shows the menu to add and remove data series from the current set of data
* series.
*
* @param shell
*/
public void showMenu(Shell shell)
{
if (configContextMenu == null)
configContextMenu = createMenu(shell, this::configMenuAboutToShow);
configContextMenu.setVisible(true);
}
/**
* Shows the menu to manage sets of data series, e.g. add, create, delete
* sets.
*
* @param shell
*/
public void showSaveMenu(Shell shell)
{
store.showMenu(shell);
}
private Menu createMenu(Shell shell, IMenuListener listener)
{
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(listener);
return menuMgr.createContextMenu(shell);
}
public List<DataSeries> getSelectedDataSeries()
{
return selectedSeries;
}
private void widgetDisposed()
{
if (configContextMenu != null && !configContextMenu.isDisposed())
configContextMenu.dispose();
store.dispose();
}
private void configMenuAboutToShow(IMenuManager manager) // NOSONAR
{
for (final DataSeries series : selectedSeries)
{
Action action = new SimpleAction(series.getLabel(), a -> doDeleteSeries(series));
action.setChecked(true);
manager.add(action);
}
manager.add(new Separator());
manager.add(new SimpleAction(Messages.ChartSeriesPickerAddItem, a -> doAddSeries(false)));
if (dataSeriesSet.getUseCase() != DataSeries.UseCase.STATEMENT_OF_ASSETS)
manager.add(new SimpleAction(Messages.ChartSeriesPickerAddBenchmark, a -> doAddSeries(true)));
manager.add(new SimpleAction(Messages.MenuResetChartSeries, a -> doResetSeries(null)));
}
private void doAddSeries(boolean showOnlyBenchmark)
{
List<DataSeries> list = new ArrayList<>(dataSeriesSet.getAvailableSeries());
// remove items if that do not match the benchmark flag
Iterator<DataSeries> iter = list.iterator();
while (iter.hasNext())
if (iter.next().isBenchmark() != showOnlyBenchmark)
iter.remove();
// remove already selected items
for (DataSeries s : selectedSeries)
list.remove(s);
ListSelectionDialog dialog = new ListSelectionDialog(Display.getDefault().getActiveShell(),
new DataSeriesLabelProvider());
dialog.setTitle(Messages.ChartSeriesPickerTitle);
dialog.setMessage(Messages.ChartSeriesPickerTitle);
dialog.setElements(list);
if (dialog.open() != ListSelectionDialog.OK)
return;
Object[] result = dialog.getResult();
if (result == null || result.length == 0)
return;
for (Object object : result)
selectedSeries.add((DataSeries) object);
fireUpdate();
}
private void doResetSeries(String config)
{
dataSeriesSet = new DataSeriesSet(client, preferences, dataSeriesSet.getUseCase());
selectedSeries = new DataSeriesSerializer().fromString(dataSeriesSet, config);
fireUpdate();
}
/* package */ void doDeleteSeries(DataSeries series)
{
selectedSeries.remove(series);
fireUpdate();
}
@Override
public void beforeConfigurationPicked()
{
// do nothing - all configuration changes are stored via #updateActive
}
@Override
public void onConfigurationPicked(String data)
{
this.doResetSeries(data);
}
}