Java tutorial
/** * Copyright 2014-2016 LIST (Luxembourg Institute of Science and Technology), all right reserved. * Authorship : Olivier PARISOT, Yoanne DIDRY * Licensed under GNU General Public License version 3 */ package lu.lippmann.cdb.ext.hydviga.ui; import static lu.lippmann.cdb.weka.WekaTimeSeriesUtil.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.event.*; import javax.swing.plaf.basic.BasicProgressBarUI; import lu.lippmann.cdb.App; import lu.lippmann.cdb.command.CommandDispatcher; import lu.lippmann.cdb.common.FormatterUtil; import lu.lippmann.cdb.common.async.simplified.AbstractSimpleAsync; import lu.lippmann.cdb.common.gui.LogoHelper; import lu.lippmann.cdb.common.gui.slider.RangeSlider; import lu.lippmann.cdb.common.mvp.*; import lu.lippmann.cdb.context.*; import lu.lippmann.cdb.datasetview.IDatasetView; import lu.lippmann.cdb.datasetview.tabs.*; import lu.lippmann.cdb.datasetview.tasks.*; import lu.lippmann.cdb.event.*; import lu.lippmann.cdb.ext.hydviga.data.StationsDataProvider; import lu.lippmann.cdb.weka.*; import org.jdesktop.swingx.*; import weka.core.*; /** * HydroDatasetView. * * @author the WP1 team */ public final class HydroDatasetView extends JXFrame implements Display, IDatasetView { // // Static fields // /** Serial version UID. */ private static final long serialVersionUID = 123479L; /** */ private static final String ALL_VAL = "- ALL -"; /** */ //private static final String NO_CLASS="NO_CLASS"; // // Instance fields // /** */ private final JXTaskPaneContainer taskPaneContainer; /** */ private Instances initialDataSet; /** */ private CompletenessComputer initialCompleteness; /** */ private Instances notFilteredDataSet; /** */ private Instances dataSet; /** */ private boolean filtered = false; /** */ private JTabbedPane tabbedPane; /** */ private final Map<String, JTabbedPane> supertabsmap; /** */ private JComboBox classSelectionCombo; /** */ private ActionListener classSelectionComboListener; /** */ private JXList historylist; /** */ private DefaultListModel historyListModel; /** */ private final EventPublisher eventPublisher; /** */ private CommandDispatcher commandDispatcher; /** */ private ApplicationContext applicationContext; /** */ private final List<TabView> tabViews; /** */ private final JXPanel filterPanel; /** */ private final JScrollPane scrollPane; /** */ private final GridBagConstraints gbc; /** */ private final JProgressBar dataCompletenessProgressBar; /** */ private final JXTaskPane supervisedTransformPane; /** */ private JCheckBox completnessCheckbox; /** */ private JXPanel progressBarPanel; /** */ private JComboBox<Granularity> granularitySelectionCombo; // // Constructors // /** * Constructor. * TODO: replace manual dependency injection by guice dependency injection! * @param gcp */ public HydroDatasetView(final String title, final EventPublisher eventPublisher, final CommandDispatcher commandDispatcher, final ApplicationContext applicationContext, final String pictureURL, final StationsDataProvider gcp) { super(); this.setTitle(title); this.eventPublisher = eventPublisher; this.commandDispatcher = commandDispatcher; this.applicationContext = applicationContext; LogoHelper.setLogo(this); this.setLayout(new BorderLayout()); this.taskPaneContainer = new JXTaskPaneContainer(); addGranularityMenu(); addExportMenu(); this.supervisedTransformPane = new JXTaskPane(); //addMiscMenu(); //addMissingValuesMenu(); //addCorrectMenu(); addHistoMenu(); this.add(taskPaneContainer, BorderLayout.WEST); this.filterPanel = new JXPanel(); this.filterPanel.setLayout(new GridBagLayout()); this.filterPanel.setScrollableWidthHint(ScrollableSizeHint.HORIZONTAL_STRETCH); this.scrollPane = new JScrollPane(this.filterPanel, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); this.scrollPane.setPreferredSize(new Dimension(2000, 100)); this.gbc = new GridBagConstraints(); this.gbc.gridx = 0; this.gbc.gridy = 0; this.gbc.weightx = 1; this.gbc.weighty = 1; this.gbc.fill = GridBagConstraints.VERTICAL; this.gbc.insets = new Insets(10, 10, 10, 10); this.add(this.scrollPane, BorderLayout.NORTH); this.tabbedPane = new JTabbedPane(); this.add(this.tabbedPane, BorderLayout.CENTER); this.supertabsmap = new HashMap<String, JTabbedPane>(); this.progressBarPanel = new JXPanel(); this.progressBarPanel.setVisible(false); progressBarPanel.setBorder(new TitledBorder("Completeness")); progressBarPanel.setLayout(new BorderLayout()); this.dataCompletenessProgressBar = new JProgressBar(0, 100); this.dataCompletenessProgressBar.setStringPainted(true); this.dataCompletenessProgressBar.updateUI(); this.dataCompletenessProgressBar.setVisible(false); this.dataCompletenessProgressBar.setUI(new BasicProgressBarUI() { protected Color getSelectionBackground() { return Color.black; } protected Color getSelectionForeground() { return Color.black; } }); progressBarPanel.add(this.dataCompletenessProgressBar, BorderLayout.CENTER); this.add(progressBarPanel, BorderLayout.SOUTH); this.tabViews = new ArrayList<TabView>(); addTabView(new StatsTabView()); /*addTabView(new PictureTabView(pictureURL) { @Override public String getName() { return "Map"; } @Override public Icon getIcon() { return ResourceLoader.getAndCacheIcon("menu/stats.png"); // TODO: change it } });*/ addTabView(new GapsTabView(gcp, eventPublisher, commandDispatcher, applicationContext) { @Override public String getName() { return "Gaps"; } @Override public Icon getIcon() { return ResourceLoader.getAndCacheIcon("menu/weighted-decision-trees.png"); } /*@Override public boolean isSlow() { return true; }*/ }); addTabView(new TimeSeriesTabView(true, false, false, false, false) { @Override public String getName() { return "Overview"; } @Override public Icon getIcon() { return ResourceLoader.getAndCacheIcon("menu/parsets.png"); } }); addTabView(new TimeSeriesTabView(false, true, false, false, false) { @Override public String getName() { return "Plots"; } @Override public Icon getIcon() { return ResourceLoader.getAndCacheIcon("menu/time-series.png"); } }); /*addTabView(new TimeSeriesTabView(false,false,false,false,true) { @Override public String getName() { return "Calendar"; } @Override public Icon getIcon() { return ResourceLoader.getAndCacheIcon("menu/attributes-summary.png"); } });*/ addTabView(new TableTabView(eventPublisher) { @Override public boolean isSlow() { return true; } }); addTabView(new GraphTabView(gcp.getRelationshipsGraphs(), eventPublisher, commandDispatcher) { @Override public String getName() { return "Relationships between stations"; } @Override public Icon getIcon() { return ResourceLoader.getAndCacheIcon("menu/decision-tree.png"); } }); } // // Instance methods // private void addTabView(final TabView tv, final String... supertabname) { tv.setDataChangeListener(new Listener<TabView.DataChange>() { @Override public void onAction(final TabView.DataChange change) { notifyTransformation(change.getDataSet(), change.getDataChangeTypeEnum() + " from " + tv.getName()); if (isComputingOfDataCompletnessEnabled()) { setDataCompleteness(initialCompleteness.computeUnchangedCellsCount(change.getDataSet())); } } }); this.tabViews.add(tv); final JXPanel p = new JXPanel(); p.setLayout(new BorderLayout()); p.add(tv.getComponent(), BorderLayout.CENTER); p.add(tv.getErrorComponent(), BorderLayout.SOUTH); p.add(tv.getBusyComponent(), BorderLayout.NORTH); if (supertabname.length > 0) { JTabbedPane supertab; if (!this.supertabsmap.containsKey(supertabname[0])) { supertab = new JTabbedPane(); this.supertabsmap.put(supertabname[0], supertab); this.tabbedPane.addTab(supertabname[0], tv.getIcon(), supertab, supertabname[0]); } else { supertab = this.supertabsmap.get(supertabname[0]); } supertab.addTab(tv.getName(), tv.getIcon(), p, tv.getName()); tv.setLocation(supertab, supertab.indexOfTab(tv.getName())); } else { this.tabbedPane.addTab(tv.getName(), tv.getIcon(), p, tv.getName()); tv.setLocation(tabbedPane, tabbedPane.indexOfTab(tv.getName())); } } private void updateFiltersPane(final Instances instances) throws Exception { filterPanel.removeAll(); gbc.gridx = 0; gbc.gridy = 0; final int numAttributes = instances.numAttributes(); final RangeSlider[] rangeSliders = new RangeSlider[numAttributes]; final JComboBox[] nominalCombos = new JComboBox[numAttributes]; boolean hasNumeric = false; boolean hasDate = false; for (int i = 0; i < numAttributes; i++) { final int attrIdx = i; if ((WekaDataStatsUtil.isInteger(instances, i)) || instances.attribute(i).isDate()) { hasNumeric = hasNumeric || (instances.attribute(i).isNumeric() && !instances.attribute(i).isDate()); hasDate = hasDate || instances.attribute(i).isDate(); final long[] minmax = WekaDataStatsUtil.getMinMaxForAttribute(instances, i); if (Math.abs(minmax[1] - minmax[0]) < 0.00001) continue; if (instances.attribute(i).isDate()) { minmax[0] = (int) (minmax[0] / (1000l)); minmax[1] = (int) (minmax[1] / (1000l)); } long[] oldminmax; try { final Attribute goodAttr = notFilteredDataSet.attribute(instances.attribute(i).name()); oldminmax = WekaDataStatsUtil.getMinMaxForAttribute(notFilteredDataSet, goodAttr.index()); if (instances.attribute(i).isDate()) { oldminmax[0] = (int) (oldminmax[0] / (1000l)); oldminmax[1] = (int) (oldminmax[1] / (1000l)); } } catch (Throwable t) { oldminmax = minmax; } rangeSliders[i] = new RangeSlider(); //System.out.println("pref size -> "+this.scrollPane.getPreferredSize().getWidth()); rangeSliders[i].setPreferredSize(new Dimension(600, rangeSliders[i].getPreferredSize().height)); rangeSliders[i].setMinimum((int) oldminmax[0]); rangeSliders[i].setMaximum((int) oldminmax[1]); rangeSliders[i].setValue((int) minmax[0]); rangeSliders[i].setUpperValue((int) minmax[1]); // hack... rangeSliders[i].setValue((int) minmax[0]); rangeSliders[i].setUpperValue((int) minmax[1]); if (!instances.attribute(i).isDate()) { rangeSliders[i].setPaintTicks(true); rangeSliders[i].setPaintLabels(true); final int rangeWidth = (int) (oldminmax[1] - oldminmax[0]); rangeSliders[i].setMinorTickSpacing(rangeWidth / 10); rangeSliders[i].setMajorTickSpacing(rangeWidth / 2); } rangeSliders[i].addChangeListener(new ChangeListener() { @Override public void stateChanged(final ChangeEvent e) { if (!rangeSliders[attrIdx].getValueIsAdjusting()) { processfilters(rangeSliders, nominalCombos, instances.attribute(attrIdx).name(), attrIdx); } else { if (instances.attribute(attrIdx).isDate()) { final Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(rangeSliders[attrIdx].getValue() * 1000l); final String minDate = FormatterUtil.DATE_FORMAT.format(cal.getTime()); cal.setTimeInMillis(rangeSliders[attrIdx].getUpperValue() * 1000l); final String maxDate = FormatterUtil.DATE_FORMAT.format(cal.getTime()); rangeSliders[attrIdx].setBorder(new TitledBorder(instances.attribute(attrIdx).name() + " [" + minDate + " - " + maxDate + "]")); } else { rangeSliders[attrIdx].setBorder(new TitledBorder(instances.attribute(attrIdx).name() + " [" + rangeSliders[attrIdx].getValue() + " - " + rangeSliders[attrIdx].getUpperValue() + "]")); } } } }); if (instances.attribute(i).isDate()) { filterPanel.add(rangeSliders[i], gbc); gbc.gridx++; final Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(rangeSliders[i].getValue() * 1000l); final String minDate = FormatterUtil.DATE_FORMAT.format(cal.getTime()); cal.setTimeInMillis(rangeSliders[i].getUpperValue() * 1000l); final String maxDate = FormatterUtil.DATE_FORMAT.format(cal.getTime()); rangeSliders[i].setBorder(new TitledBorder( instances.attribute(i).name() + " [" + minDate + " - " + maxDate + "]")); } else { filterPanel.add(rangeSliders[i], gbc); gbc.gridx++; rangeSliders[i].setBorder(new TitledBorder(instances.attribute(i).name() + " [" + rangeSliders[i].getValue() + " - " + rangeSliders[i].getUpperValue() + "]")); } } else { rangeSliders[i] = null; } } for (int i = 0; i < numAttributes; i++) { if (instances.attribute(i).isNominal()) { final ArrayList<String> possibleValuesList = new ArrayList<String>(); final Enumeration<?> es = notFilteredDataSet .attribute(notFilteredDataSet.attribute(instances.attribute(i).name()).index()) .enumerateValues(); possibleValuesList.add(ALL_VAL); while (es.hasMoreElements()) { possibleValuesList.add(es.nextElement().toString().trim()); } if (possibleValuesList.size() == 2) continue; // only one choice, no filter needed! nominalCombos[i] = new JComboBox(possibleValuesList.toArray()); if (WekaDataStatsUtil.getPresentValuesForNominalAttribute(instances, i).size() == 1) { nominalCombos[i].setSelectedItem(instances.instance(0).stringValue(i)); } nominalCombos[i].setBorder(new TitledBorder(instances.attribute(i).name())); final int nominalAttrIdx = i; nominalCombos[i].addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { processfilters(rangeSliders, nominalCombos, instances.attribute(nominalAttrIdx).name(), nominalAttrIdx); } }); filterPanel.add(nominalCombos[i], gbc); gbc.gridx++; } } filterPanel.setVisible(gbc.gridx > 0); filterPanel.updateUI(); scrollPane.setVisible(gbc.gridx > 0); scrollPane.updateUI(); /* automatically set the timestamp range */ /*SwingUtilities.invokeLater(new Runnable() { @Override public void run() { for (int i = 0 ; i < numAttributes ; i++) { if (rangeSliders[i]!=null&&instances.attribute(i).isDate()) { System.out.println(rangeSliders[i].getValue()+" "+rangeSliders[i].getMinimum()+" "+rangeSliders[i].getUpperValue()+" "+rangeSliders[i].getMaximum()); if (rangeSliders[i].getValue()==rangeSliders[i].getMinimum()&&rangeSliders[i].getUpperValue()==rangeSliders[i].getMaximum()) { final int toadd=(rangeSliders[i].getMaximum()-rangeSliders[i].getMinimum())/2; rangeSliders[i].setValue(rangeSliders[i].getMinimum()+toadd); break; } } } } });*/ } private void processfilters(final RangeSlider[] rangeSliders, final JComboBox[] nominalCombos, final String name, final int idx) { Instances newds = new Instances(notFilteredDataSet); for (int k = 0; k < nominalCombos.length; k++) { if (k == idx && nominalCombos[k] != null && !nominalCombos[k].getSelectedItem().toString().equals(ALL_VAL)) { newds = WekaDataProcessingUtil.filterDataSetOnNominalValue(newds, k, nominalCombos[k].getSelectedItem().toString()); System.out.println("filter on '" + nominalCombos[k].getSelectedItem().toString() + "'"); } } for (int k = 0; k < rangeSliders.length; k++) { if (k == idx && rangeSliders[k] != null) { if (newds.attribute(k).isDate()) { newds = WekaDataProcessingUtil.filterDataSetOnNumericValue(newds, k, rangeSliders[k].getValue() * 1000d, rangeSliders[k].getUpperValue() * 1000d); System.out.println("filter on '" + k + "': " + rangeSliders[k].getValue() + " -> " + rangeSliders[k].getUpperValue()); } else { newds = WekaDataProcessingUtil.filterDataSetOnNumericValue(newds, k, (double) rangeSliders[k].getValue(), (double) rangeSliders[k].getUpperValue()); System.out.println("filter on '" + k + "'"); } } } notifyFilter(newds, "Filtered on '" + name + "'"); } private void addMiscMenu() { final JXTaskPane timeSeriesPane = new JXTaskPane(); timeSeriesPane.setTitle("Misc"); timeSeriesPane.add(new SortTimeSeriesTask().buildAction(this)); timeSeriesPane.add(new AddDiscretizedTimeTask().buildAction(this)); timeSeriesPane.add(new AddFakeTimeTask().buildAction(this)); taskPaneContainer.add(timeSeriesPane); } private void addMissingValuesMenu() { final JXTaskPane missingValuesPane = new JXTaskPane(); missingValuesPane.setTitle("Missing values"); missingValuesPane.add(new FillShortGapsInTimeSeriesByInterpolationTask().buildAction(this)); /*missingValuesPane.add(new FillAllGapsInTimeSeriesWithEMTask().buildAction(this)); missingValuesPane.add(new RemoveFirstGapInTimeSeriesTask().buildAction(this)); missingValuesPane.add(new RemoveRowsWithMissingValuesTask().buildAction(this)); missingValuesPane.add(new RemoveAttrWithMissingValuesTask().buildAction(this)); missingValuesPane.add(new MarkMissingValuesTask().buildAction(this));*/ taskPaneContainer.add(missingValuesPane); } private void addCorrectMenu() { final JXTaskPane correctPane = new JXTaskPane(); correctPane.setTitle("Correct"); correctPane.add(new RemoveExtremeValuesTask().buildAction(this)); correctPane.add(new RemoveOutliersTask().buildAction(this)); correctPane.add(new RemoveDuplicatesTask().buildAction(this)); correctPane.add(new RemoveConstantAttributesTask().buildAction(this)); correctPane.add(new MarkExtremeValuesAndOutliersTask().buildAction(this)); taskPaneContainer.add(correctPane); } private void addHistoMenu() { final JXTaskPane histoPane = new JXTaskPane(); histoPane.setTitle("History"); this.historyListModel = new DefaultListModel(); final JXPanel tp = new JXPanel(); tp.setBorder(new TitledBorder("Changes")); this.historylist = new JXList(historyListModel); this.historylist.setLayoutOrientation(JList.VERTICAL); final JScrollPane listScroller = new JScrollPane(this.historylist); listScroller.setPreferredSize(new Dimension(150, 75)); tp.add(listScroller); histoPane.add(tp); histoPane.add(new CancelTask().buildAction(this)); taskPaneContainer.add(histoPane); } private final void addExportMenu() { final JXTaskPane exportPane = new JXTaskPane(); exportPane.setTitle("Export"); exportPane.add(new ExportARFFTask().buildAction(this)); exportPane.add(new ExportCSVTask().buildAction(this)); //exportPane.add(new ExportCallunaTask().buildAction(this)); taskPaneContainer.add(exportPane); } private final void addGranularityMenu() { final JXTaskPane granularitySelectionPane = new JXTaskPane(); granularitySelectionPane.setTitle("Temporal resolution"); this.granularitySelectionCombo = new JComboBox<Granularity>(Granularity.values()); granularitySelectionPane.add(this.granularitySelectionCombo); final ActionListener granularitySelectionComboListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final Granularity gr = (Granularity) granularitySelectionCombo.getSelectedItem(); new AbstractSimpleAsync<Instances>(true) { @Override public Instances execute() throws Exception { return WekaTimeSeriesUtil.changeGranularity(initialDataSet, Arrays.asList(gr.getFields())); } @Override public void onSuccess(final Instances inst) { notifyTransformation(inst, "Set granularity: " + gr); } @Override public void onFailure(final Throwable caught) { caught.printStackTrace(); } }.start(); } }; this.granularitySelectionCombo.addActionListener(granularitySelectionComboListener); taskPaneContainer.add(granularitySelectionPane); } public void setGranularity(final Granularity gr) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { granularitySelectionCombo.setSelectedItem(gr); } }); } /** * {@inheritDoc} */ @Override public final void notifyTransformation(final Instances newdataset, final String msg) { this.filtered = false; if (newdataset != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setDataSet(newdataset).setAsVisible(); historyListModel.addElement(msg); updateHistoryList(); } }); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setDataSet(initialDataSet).setAsVisible(); setGranularity((Granularity) granularitySelectionCombo.getSelectedItem()); historyListModel.removeAllElements(); } }); } } public final void notifyFilter(final Instances newdataset, final String msg) { this.filtered = true; setDataSet(newdataset).setAsVisible(); this.historyListModel.addElement(msg); updateHistoryList(); if (isComputingOfDataCompletnessEnabled()) { setDataCompleteness(initialCompleteness.computeUnchangedCellsCount(newdataset)); } } private void updateHistoryList() { this.historylist.setSelectedIndex(this.historyListModel.size() - 1); this.historylist.ensureIndexIsVisible(this.historylist.getSelectedIndex()); this.historylist.clearSelection(); } public final void setAsVisible(boolean setSize) { if (setSize) { this.setPreferredSize(new Dimension(1200, 950)); this.pack(); } this.setVisible(true); } public final void setAsVisible() { setAsVisible(false); } /** * {@inheritDoc} */ @Override public final Component asComponent() { return this; } /** * {@inheritDoc} */ @Override public final Instances getInitialDataSet() { return this.initialDataSet; } public final CompletenessComputer getInitialCompleteness() { return this.initialCompleteness; } public HydroDatasetView setDataSet(final Instances pdataSet) { if (pdataSet.classIndex() != -1 && !pdataSet.classAttribute().isNominal()) pdataSet.setClassIndex(-1); if (this.initialDataSet == null) { this.initialDataSet = pdataSet; this.initialCompleteness = new CompletenessComputer(this.initialDataSet); this.dataCompletenessProgressBar.setMaximum(pdataSet.numInstances() * pdataSet.numAttributes()); reinitDataCompleteness(); } this.dataSet = pdataSet; if (!filtered) this.notFilteredDataSet = pdataSet; //updateClassSelectionMenu(); this.supervisedTransformPane.setVisible(pdataSet.classIndex() != -1); for (final TabView tv : tabViews) { tv.update(dataSet); } try { updateFiltersPane(dataSet); } catch (Exception e) { eventPublisher.publish(new ErrorOccuredEvent("Error when updating filters", e)); } updateTooltipShowingDatasetDimensions(); return this; } private void updateTooltipShowingDatasetDimensions() { final StringBuilder sb = new StringBuilder(); sb.append("<html><body>"); sb.append("<b>Original dataset:</b> ").append(this.initialDataSet.numInstances()).append(" rows, ") .append(this.initialDataSet.numAttributes()).append(" columns").append("<br/>"); sb.append("<b>Current dataset:</b> ").append(this.dataSet.numInstances()).append(" rows, ") .append(this.dataSet.numAttributes()).append(" columns").append("<br/>"); sb.append("</body></html>"); this.dataCompletenessProgressBar.setToolTipText(sb.toString()); //this.dataCompletenessProgressBar.updateUI(); System.out.println(getDataCompleteness()); } /** * {@inheritDoc} */ @Override public void setDataCompleteness(final int completeness) { this.dataCompletenessProgressBar.setValue(completeness); final int ratio = getDataCompletenessRatio(); if (ratio > 90) this.dataCompletenessProgressBar.setForeground(Color.GREEN); else if (ratio > 60) this.dataCompletenessProgressBar.setForeground(Color.ORANGE); else this.dataCompletenessProgressBar.setForeground(Color.RED); } public void reinitDataCompleteness() { setDataCompleteness(this.initialDataSet.numInstances() * this.initialDataSet.numAttributes()); } /** * {@inheritDoc} */ @Override public int getDataCompleteness() { return this.dataCompletenessProgressBar.getValue(); } public int getDataCompletenessRatio() { final int ratio = (int) Math.round((100d * this.dataCompletenessProgressBar.getValue()) / (double) this.dataCompletenessProgressBar.getMaximum()); return ratio; } /** * {@inheritDoc} */ @Override public EventPublisher getEventPublisher() { return this.eventPublisher; } /** * {@inheritDoc} */ @Override public Instances getDataSet() { return this.dataSet; } /** * {@inheritDoc} */ @Override public boolean isComputingOfDataCompletnessEnabled() { return this.completnessCheckbox != null && this.completnessCheckbox.isSelected(); } // // Static enums // public static enum Granularity { INITIAL, BY_YEAR(YEAR), BY_MONTH(YEAR, MONTH), BY_DAY(YEAR, MONTH, DAY), BY_HOUR(YEAR, MONTH, DAY, HOUR); private final String[] fields; Granularity(final String... fields) { this.fields = fields; } public String[] getFields() { return fields; } } }