package org.geogebra.web.web.gui.view.algebra; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import org.geogebra.common.gui.view.algebra.AlgebraView.SortMode; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.App; import org.geogebra.common.main.SelectionManager; import org.geogebra.web.html5.main.GlobalKeyDispatcherW; /** * Selection controller for AV * * @author Laszlo */ public class AVSelectionController { /** Selection mode */ public enum SelectMode { /** single select */ Single, /** ctrl-select */ Toggle, /** shift-select */ Continuous, /** none */ None } private GeoElement selectedGeo; private GeoElement lastSelectedGeo; private App app; private SelectionManager selection; private boolean selectHandled; private SelectMode lastMode; /** * @param app * application */ public AVSelectionController(App app) { this.app = app; selection = app.getSelectionManager(); setLastSelectedGeo(null); lastMode = SelectMode.None; } private void singleSelect(GeoElement geo) { lastMode = SelectMode.Single; selection.clearSelectedGeos(false); // repaint will be done // next step selection.addSelectedGeo(geo); setLastSelectedGeo(geo); } private void toggleSelect(GeoElement geo) { lastMode = SelectMode.Toggle; selection.toggleSelectedGeo(geo); if (contains(geo)) { setLastSelectedGeo(geo); } else { setLastSelectedGeo(null); } } private void continuousSelect(GeoElement geo) { SortMode sortMode = app.getSettings().getAlgebra().getTreeMode(); switch (sortMode) { case LAYER: break; case ORDER: continuous(geo, app.getKernel().getConstruction() .getGeoSetConstructionOrder(), geo.getConstructionIndex() < getLastSelectedGeo() .getConstructionIndex()); break; case TYPE: continuous(geo, app.getKernel().getConstruction().getGeoSetLabelOrder(), geo.getLabel(StringTemplate.defaultTemplate) .compareTo(getLastSelectedGeo().getLabel( StringTemplate.defaultTemplate)) < 0); break; case VIEW: break; case DEPENDENCY: default: continuousDependent(geo); } setLastMode(SelectMode.Continuous); } private void continuous(GeoElement geo0, TreeSet<GeoElement> geoSet, boolean direction) { ensureClearLastSelection(); GeoElement geoFrom = direction ? geo0 : getLastSelectedGeo(); GeoElement geoTo = direction ? getLastSelectedGeo() : geo0; for (GeoElement geo : geoSet.subSet(geoFrom, true, geoTo, true)) { selection.toggleSelectedGeo(geo); } } private void continuousDependent(GeoElement geo) { boolean nowSelecting = true; boolean selecting = false; boolean aux = geo.isAuxiliaryObject(); boolean ind = geo.isIndependent(); boolean aux2 = getLastSelectedGeo().isAuxiliaryObject(); boolean ind2 = getLastSelectedGeo().isIndependent(); ensureClearLastSelection(); if ((aux == aux2 && aux) || (aux == aux2 && ind == ind2)) { Iterator<GeoElement> it = app.getKernel().getConstruction() .getGeoSetLabelOrder().iterator(); boolean direction = geo.getLabel(StringTemplate.defaultTemplate) .compareTo(getLastSelectedGeo() .getLabel(StringTemplate.defaultTemplate)) < 0; while (it.hasNext()) { GeoElement geo2 = it.next(); if ((geo2.isAuxiliaryObject() == aux && aux) || (geo2.isAuxiliaryObject() == aux && geo2.isIndependent() == ind)) { if (direction && geo2.equals(getLastSelectedGeo())) { selecting = !selecting; } if (!direction && geo2.equals(geo)) { selecting = !selecting; } if (selecting) { selection.toggleSelectedGeo(geo2); nowSelecting = selection.getSelectedGeos() .contains(geo2); } if (!direction && geo2.equals(getLastSelectedGeo())) { selecting = !selecting; } if (direction && geo2.equals(geo)) { selecting = !selecting; } } } } if (nowSelecting) { setLastSelectedGeo(geo); } else { selection.removeSelectedGeo(getLastSelectedGeo()); setLastSelectedGeo(null); } } private void ensureClearLastSelection() { if (lastMode != SelectMode.Continuous || lastMode != SelectMode.None) { selection.clearSelectedGeos(); } } // private void continuousOrder(GeoElement geo) { // ensureClearLastSelection(geo); // // boolean direction = geo.getConstructionIndex() < getLastSelectedGeo() // .getConstructionIndex(); // // GeoElement geoFrom = direction ? geo : getLastSelectedGeo(); // GeoElement geoTo = direction ? getLastSelectedGeo() : geo; // // SortedSet<GeoElement> geos = app.getKernel().getConstruction() // .getGeoSetConstructionOrder() // .subSet(geoFrom, true, geoTo, true); // // for (GeoElement geo1 : geos) { // selection.toggleSelectedGeo(geo1); // } // } /** * Selecting the GeoElement * * @param geo * GeoElement to be selected/toggled. * @param toggle * If selection should be toggled (Control-select). * @param continuous * if selection is continuous (Shift-select) */ public void select(GeoElement geo, boolean toggle, boolean continuous) { if (toggle) { toggleSelect(geo); } else if (continuous && getLastSelectedGeo() != null) { selection.clearSelectedGeos(); continuousSelect(geo); } else { singleSelect(geo); } } /** * @return last selected geo */ public GeoElement getLastSelectedGeo() { return lastSelectedGeo; } /** * @param lastSelectedGeo * last selected geo */ public void setLastSelectedGeo(GeoElement lastSelectedGeo) { this.lastSelectedGeo = lastSelectedGeo; } /** * @return currently selected geo */ public GeoElement getSelectedGeo() { return selectedGeo; } /** * @param selectedGeo * currently selected geo */ public void setSelectedGeo(GeoElement selectedGeo) { this.selectedGeo = selectedGeo; } /** * Clear global selection */ public void clear() { selection.clearSelectedGeos(); } /** * * @return if a multiselect is happening (with Shift or Control) */ public boolean isMultiSelect() { return GlobalKeyDispatcherW.getControlDown(); } /** * @return !hasMultGeos() */ public boolean isSingleGeo() { return selection.getSelectedGeos().size() == 1; } /** * @return whether more than 1 geo selected */ public boolean hasMultGeos() { return selection.getSelectedGeos().size() > 1; } /** * @return selected geos */ public List<GeoElement> getSelectedGeos() { return selection.getSelectedGeos(); } /** * @return whether some geos are selected */ public boolean isEmpty() { return selection.getSelectedGeos().isEmpty(); } /** * @return whether selection of UI is in sync */ public boolean isSelectHandled() { return selectHandled; } /** * @param selectHandled * whether selection of UI is in sync */ public void setSelectHandled(boolean selectHandled) { this.selectHandled = selectHandled; } /** * @param geo * element * @return whether geo is selected */ public boolean contains(GeoElement geo) { return selection.getSelectedGeos().contains(geo); } /** * @return last selection mode */ public SelectMode getLastMode() { return lastMode; } private void setLastMode(SelectMode lastMode) { this.lastMode = lastMode; } }