/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ /* * AlgebraView.java * * Created on 27. September 2001, 11:30 */ package org.geogebra.desktop.gui.view.algebra; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Rectangle; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.util.ArrayList; import java.util.EventObject; import java.util.HashMap; import java.util.Map.Entry; import javax.swing.DefaultCellEditor; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.TreeSelectionEvent; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellEditor; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import org.geogebra.common.gui.view.algebra.AlgebraView; import org.geogebra.common.kernel.LayerView; import org.geogebra.common.kernel.ModeSetter; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.kernelND.GeoElementND; import org.geogebra.common.main.App; import org.geogebra.common.main.Localization; import org.geogebra.common.main.settings.AbstractSettings; import org.geogebra.common.main.settings.AlgebraSettings; import org.geogebra.common.main.settings.SettingListener; import org.geogebra.common.plugin.EventType; import org.geogebra.common.util.AsyncOperation; import org.geogebra.desktop.gui.inputfield.MathTextField; import org.geogebra.desktop.gui.view.Gridable; import org.geogebra.desktop.main.AppD; /** * AlgebraView with tree for free and dependent objects. * * @author Markus */ public class AlgebraViewD extends AlgebraTree implements LayerView, Gridable, AlgebraView, SettingListener { private static final long serialVersionUID = 1L; /** */ // public static final int MODE_VIEW = 2; private MyDefaultTreeCellEditor editor; private MathTextField editTF; /** * Root node for tree mode MODE_DEPENDENCY. */ protected DefaultMutableTreeNode rootDependency; /** * Nodes for tree mode MODE_DEPENDENCY */ private DefaultMutableTreeNode depNode, indNode; protected DefaultMutableTreeNode auxiliaryNode; /* for SortMode.ORDER */ private DefaultMutableTreeNode rootOrder; /* for SortMode.LAYER */ private DefaultMutableTreeNode rootLayer; private HashMap<Integer, DefaultMutableTreeNode> layerNodesMap; /** * The mode of the tree, see MODE_DEPENDENCY, MODE_TYPE */ protected SortMode treeMode; private GeoElement selectedGeoElement; private DefaultMutableTreeNode selectedNode; private AlgebraHelperBar helperBar; public AlgebraControllerD getAlgebraController() { return (AlgebraControllerD) algebraController; } /** Creates new AlgebraView */ public AlgebraViewD(AlgebraControllerD algCtrl) { super(algCtrl, true); // Initialize settings and register listener app.getSettings().getAlgebra().addListener(this); settingsChanged(app.getSettings().getAlgebra()); } @Override protected void initTree() { // this is the default value treeMode = SortMode.TYPE; // cell renderer (tooltips) and editor ToolTipManager.sharedInstance().registerComponent(this); // EDITOR setEditable(true); super.initTree(); // enable drag n drop ((AlgebraControllerD) algebraController).enableDnD(); // attachView(); } @Override protected MyRendererForAlgebraTree newMyRenderer(AppD app) { return new MyRendererForAlgebraView(app, this); } @Override protected void initModel() { // build default tree structure switch (treeMode) { default: case DEPENDENCY: // don't re-init anything if (rootDependency == null) { rootDependency = new DefaultMutableTreeNode(); depNode = new DefaultMutableTreeNode(); // dependent objects indNode = new DefaultMutableTreeNode(); auxiliaryNode = new DefaultMutableTreeNode(); // independent objects rootDependency.add(indNode); rootDependency.add(depNode); } // set the root model.setRoot(rootDependency); // add auxiliary node if neccessary if (app.showAuxiliaryObjects) { if (!auxiliaryNode.isNodeChild(rootDependency)) { model.insertNodeInto(auxiliaryNode, rootDependency, rootDependency.getChildCount()); } } break; case ORDER: if (rootOrder == null) { rootOrder = new DefaultMutableTreeNode(); } checkRemoveAuxiliaryNode(); // set the root model.setRoot(rootOrder); break; case TYPE: super.initModel(); break; case LAYER: // don't re-init anything if (rootLayer == null) { rootLayer = new DefaultMutableTreeNode(); layerNodesMap = new HashMap<Integer, DefaultMutableTreeNode>( 10); } checkRemoveAuxiliaryNode(); // set the root model.setRoot(rootLayer); break; } } @Override protected void checkRemoveAuxiliaryNode() { // always try to remove the auxiliary node if (app.showAuxiliaryObjects && auxiliaryNode != null) { removeAuxiliaryNode(); } } protected void removeAuxiliaryNode() { if (auxiliaryNode.getParent() != null) { model.removeNodeFromParent(auxiliaryNode); } } boolean attached = false; public void attachView() { // AbstractApplication.printStacktrace(""); if (attached) { return; } clearView(); kernel.notifyAddAll(this); applySettings(); kernel.attach(this); attached = true; } public void detachView() { // does nothing : view may be used in object properties /* * kernel.detach(this); clearView(); attached = false; */ } @Override public void updateFonts() { super.updateFonts(); Font font = app.getPlainFont(); editor.setFont(font); editTF.setFont(font); if (helperBar != null) { helperBar.update(); } renderer.update(); } @Override protected void initTreeCellRendererEditor() { super.initTreeCellRendererEditor(); editTF = new MathTextField(app); editTF.enableColoring(true); editTF.setShowSymbolTableIcon(true); editor = new MyDefaultTreeCellEditor(this, renderer, new MyCellEditorD(editTF, app)); // add focus listener to the editor text field so that editing is // canceled on a focus lost event editTF.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { // only handle focus lost } @Override public void focusLost(FocusEvent e) { if (e.getSource() == editTF) { cancelEditItem(); } } }); editor.addCellEditorListener(editor); // self-listening // setCellRenderer(renderer); setCellEditor(editor); } @Override public void clearSelection() { super.clearSelection(); selectedGeoElement = null; } public GeoElement getSelectedGeoElement() { return selectedGeoElement; } @Override public boolean showAuxiliaryObjects() { return app.showAuxiliaryObjects; } public void setShowAuxiliaryObjects(boolean flag) { app.showAuxiliaryObjects = flag; cancelEditItem(); if (flag) { clearView(); switch (getTreeMode()) { default: // do nothing break; case DEPENDENCY: model.insertNodeInto(auxiliaryNode, rootDependency, rootDependency.getChildCount() - 1); break; } kernel.notifyAddAll(this); } else { // if we're listing the auxiliary objects in a single leaf we can // just remove that leaf, but for type-based categorization those // auxiliary nodes might be scattered across the whole tree, // therefore we just rebuild the tree switch (getTreeMode()) { case DEPENDENCY: if (auxiliaryNode.getParent() != null) { model.removeNodeFromParent(auxiliaryNode); } break; default: clearView(); kernel.notifyAddAll(this); } } } @Override public SortMode getTreeMode() { return treeMode; } public void setTreeMode(int mode) { switch (mode) { default: case 0: setTreeMode(SortMode.DEPENDENCY); break; case 1: setTreeMode(SortMode.TYPE); break; case 2: setTreeMode(SortMode.LAYER); break; case 3: setTreeMode(SortMode.ORDER); break; } } /** * @param value * Either AlgebraView.MODE_DEPDENCY or AlgebraView.MODE_TYPE */ @Override public void setTreeMode(SortMode value) { if (getTreeMode().equals(value)) { return; } clearView(); this.treeMode = value; initModel(); kernel.notifyAddAll(this); setLabels(); // shake the tree so it looks good after the change SwingUtilities.updateComponentTreeUI(this); } /** * @return The helper bar for this view. */ public AlgebraHelperBar getHelperBar() { if (helperBar == null) { helperBar = newAlgebraHelperBar(); } return helperBar; } /** * * @return new algebra helper bar */ final protected AlgebraHelperBar newAlgebraHelperBar() { return new AlgebraHelperBar(this, app); } /** * Open Editor textfield for geo. */ @Override public void startEditItem(GeoElement geo) { if (geo == null) { return; } // open Object Properties for eg GeoImages // also for GeoPenStroke if (!geo.isAlgebraViewEditable()) { ArrayList<GeoElement> geos = new ArrayList<GeoElement>(); geos.add(geo); app.getDialogManager().showPropertiesDialog(geos); return; } if (!geo.isPointOnPath() && !geo.isPointInRegion()) { if (!geo.isIndependent() || !attached) // needed for F2 when Algebra // View closed { if (geo.isRedefineable()) { app.getDialogManager().showRedefineDialog(geo, true); } return; } if (!geo.isChangeable()) { if (geo.isProtected(EventType.UPDATE)) { // app.showMessage(app.getError("AssignmentToFixed")); } else if (geo.isRedefineable()) { app.getDialogManager().showRedefineDialog(geo, true); } return; } } DefaultMutableTreeNode node = nodeTable.get(geo); if (node != null) { cancelEditItem(); // select and show node TreePath tp = new TreePath(node.getPath()); setSelectionPath(tp); // select expandPath(tp); makeVisible(tp); scrollPathToVisible(tp); startEditingAtPath(tp); // opend editing text field } } /** * resets all fix labels of the View. This method is called by the * application if the language setting is changed. */ @Override public void setLabels() { super.setLabels(); if (helperBar != null) { helperBar.updateLabels(); } } /** * set labels on the tree */ @Override protected void setTreeLabels() { Localization loc = app.getLocalization(); switch (getTreeMode()) { default: case DEPENDENCY: indNode.setUserObject(loc.getMenu("FreeObjects")); model.nodeChanged(indNode); depNode.setUserObject(loc.getMenu("DependentObjects")); model.nodeChanged(depNode); auxiliaryNode.setUserObject(loc.getMenu("AuxiliaryObjects")); model.nodeChanged(auxiliaryNode); break; case TYPE: super.setTreeLabels(); break; case LAYER: DefaultMutableTreeNode node; for (Entry<Integer, DefaultMutableTreeNode> entry : layerNodesMap .entrySet()) { Integer key = entry.getKey(); node = entry.getValue(); node.setUserObject(key); model.nodeChanged(node); } break; case ORDER: model.nodeChanged(rootOrder); break; } } /** * * @param geo * @return parent node of this geo */ @Override protected DefaultMutableTreeNode getParentNode(GeoElement geo, int forceLayer) { DefaultMutableTreeNode parent; switch (treeMode) { case DEPENDENCY: if (geo.isAuxiliaryObject()) { parent = auxiliaryNode; } else if (geo.isIndependent()) { parent = indNode; } else { parent = depNode; } break; case TYPE: parent = super.getParentNode(geo, forceLayer); break; case LAYER: // get type node int layer = forceLayer > -1 ? forceLayer : geo.getLayer(); parent = layerNodesMap.get(layer); // do we have to create the parent node? if (parent == null) { String layerStr = layer + ""; parent = new DefaultMutableTreeNode(layer); layerNodesMap.put(layer, parent); // find insert pos int pos = rootLayer.getChildCount(); for (int i = 0; i < pos; i++) { DefaultMutableTreeNode child = (DefaultMutableTreeNode) rootLayer .getChildAt(i); if (layerStr.compareTo(child.toString()) < 0) { pos = i; break; } } model.insertNodeInto(parent, rootLayer, pos); } break; case ORDER: parent = rootOrder; break; default: parent = null; } return parent; } /** * Performs a binary search for geo among the children of parent. All * children of parent have to be instances of GeoElement sorted * alphabetically by their names. * * @return -1 when not found */ final public static int binarySearchGeo(DefaultMutableTreeNode parent, String geoLabel) { int left = 0; int right = parent.getChildCount() - 1; if (right == -1 || geoLabel == null) { return -1; } // binary search for geo's label while (left <= right) { int middle = (left + right) / 2; DefaultMutableTreeNode node = (DefaultMutableTreeNode) parent .getChildAt(middle); String nodeLabel = ((GeoElement) node.getUserObject()) .getLabelSimple(); int compare = GeoElement.compareLabels(geoLabel, nodeLabel); if (compare < 0) { right = middle - 1; } else if (compare > 0) { left = middle + 1; } else { return middle; } } return -1; } /** * Performs a linear search for geo among the children of parent. * * @return -1 when not found */ final public static int linearSearchGeo(DefaultMutableTreeNode parent, String geoLabel) { if (geoLabel == null) { return -1; } int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) parent .getChildAt(i); GeoElement g = (GeoElement) node.getUserObject(); if (geoLabel.equals(g.getLabel(StringTemplate.defaultTemplate))) { return i; } } return -1; } /** * remove all from the tree */ @Override protected void clearTree() { switch (getTreeMode()) { default: case DEPENDENCY: indNode.removeAllChildren(); depNode.removeAllChildren(); auxiliaryNode.removeAllChildren(); break; case TYPE: super.clearTree(); break; case LAYER: rootLayer.removeAllChildren(); layerNodesMap.clear(); break; case ORDER: rootOrder.removeAllChildren(); } } @Override public DefaultMutableTreeNode getRoot() { switch (getTreeMode()) { case DEPENDENCY: return rootDependency; case TYPE: default: return super.getRoot(); case LAYER: return rootLayer; case ORDER: return rootOrder; } } @Override public ArrayList<GeoElement> getGeosBetween(GeoElement geo1, GeoElement geo2) { // specific case for ORDER mode if (getTreeMode() == SortMode.ORDER) { int found = 0; ArrayList<GeoElement> ret = new ArrayList<GeoElement>(); DefaultMutableTreeNode root = getRoot(); for (int i = 0; i < root.getChildCount() && found < 2; i++) { DefaultMutableTreeNode child = (DefaultMutableTreeNode) root .getChildAt(i); Object ob = child.getUserObject(); if (ob == geo1 || ob == geo2) { found++; } if (found > 0) { ret.add((GeoElement) ob); } } return ret; } // other cases return super.getGeosBetween(geo1, geo2); } @Override public void repaintView() { repaint(); } /** * Reset the algebra view if the mode changed. */ @Override public void setMode(int mode, ModeSetter m) { reset(); } @Override public void reset() { cancelEditItem(); repaint(); } /** * Remove this node from the model. * * @param node * @param model */ @Override protected void removeFromModelForMode(DefaultMutableTreeNode node, DefaultTreeModel model) { // remove the type branch if there are no more children switch (treeMode) { default: // do nothing break; case TYPE: super.removeFromModelForMode(node, model); break; case LAYER: removeFromLayer(model, ((GeoElement) node.getUserObject()).getLayer()); break; } } private void removeFromLayer(DefaultTreeModel model2, int i) { DefaultMutableTreeNode parent = layerNodesMap.get(i); // this has been the last node if ((parent != null) && parent.getChildCount() == 0) { layerNodesMap.remove(i); model.removeNodeFromParent(parent); } } /** * inner class MyEditor handles editing of tree nodes * * Created on 28. September 2001, 12:36 */ private class MyDefaultTreeCellEditor extends DefaultTreeCellEditor implements CellEditorListener { public MyDefaultTreeCellEditor(AlgebraViewD tree, DefaultTreeCellRenderer renderer, DefaultCellEditor editor) { super(tree, renderer, editor); // editor container that expands to fill the width of the tree's // enclosing panel editingContainer = new WideEditorContainer(); } /* * CellEditorListener implementation */ @Override public void editingCanceled(ChangeEvent event) { // nothing to do } @Override public void editingStopped(ChangeEvent event) { // get the entered String String newValue = getCellEditorValue().toString(); // the userObject was changed to this String // reset it to the old userObject, which we stored // in selectedGeoElement (see valueChanged()) // only nodes with a GeoElement as userObject can be edited! selectedNode.setUserObject(selectedGeoElement); // change this GeoElement in the Kernel // allow shift-double-click on a PointonPath in Algebra View to // change without redefine boolean redefine = !selectedGeoElement.isPointOnPath(); AsyncOperation<GeoElementND> callback = new AsyncOperation<GeoElementND>() { @Override public void callback(GeoElementND geo) { if (geo != null) { selectedGeoElement = geo.toGeoElement(); selectedNode.setUserObject(selectedGeoElement); } ((DefaultTreeModel) getModel()).nodeChanged(selectedNode); } }; kernel.getAlgebraProcessor().changeGeoElement(selectedGeoElement, newValue, redefine, true, app.getDefaultErrorHandler(), callback); } /* * OVERWRITE SOME METHODS TO ONLY ALLOW EDITING OF GeoElements */ @Override public boolean isCellEditable(EventObject event) { if (event == null) { return true; } return false; } // // TreeSelectionListener // /** * Resets lastPath. */ @Override public void valueChanged(TreeSelectionEvent e) { if (tree != null) { if (tree.getSelectionCount() == 1) { lastPath = tree.getSelectionPath(); } else { lastPath = null; } /***** ADDED by Markus Hohenwarter ***********/ storeSelection(lastPath); /********************************************/ } if (timer != null) { timer.stop(); } } /** * stores currently selected GeoElement and node. selectedNode, * selectedGeoElement are private members of AlgebraView */ private void storeSelection(TreePath tp) { if (tp == null) { return; } Object ob; selectedNode = (DefaultMutableTreeNode) tp.getLastPathComponent(); if (selectedNode != null && (ob = selectedNode .getUserObject()) instanceof GeoElement) { selectedGeoElement = (GeoElement) ob; } else { selectedGeoElement = null; } } /** * Overrides getTreeCellEditor so that a custom * DefaultTreeCellEditor.EditorContainer class can be called to adjust * the container width. */ @Override public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) { Component c = super.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row); ((WideEditorContainer) editingContainer).updateContainer(tree, lastPath, offset, editingComponent); return c; } /** * Extends DefaultTreeCellEditor.EditorContainer to allow full-width * editor fields. */ class WideEditorContainer extends DefaultTreeCellEditor.EditorContainer { private static final long serialVersionUID = 1L; JTree tree; TreePath lastPath; int offset; Component editingComponent; /** * Overrides doLayout so that the editor component width is resized * to extend the full width of the tree's enclosing panel */ @Override public void doLayout() { if (editingComponent != null) { // get component preferred size Dimension eSize = editingComponent.getPreferredSize(); // expand component width to extend to the enclosing // container bounds int n = lastPath.getPathCount(); Rectangle r = tree.getParent().getBounds(); eSize.width = r.width - (offset * n); // only show the symbol table icon if the editor is wide // enough ((MathTextField) editingComponent) .setShowSymbolTableIcon(eSize.width > 100); // set the component size and location editingComponent.setSize(eSize); editingComponent.setLocation(offset, 0); editingComponent.setBounds(offset, 0, eSize.width, eSize.height); setSize(new Dimension(eSize.width + offset, eSize.height)); } } /** * Overrides getPreferredSize to prevent extra large heights when * other tree nodes contain tall LaTeX images */ @Override public Dimension getPreferredSize() { Dimension d = super.getPreferredSize(); if (editingComponent != null) { d.height = editingComponent.getHeight(); } return d; } void updateContainer(JTree tree, TreePath lastPath, int offset, Component editingComponent) { this.tree = tree; this.lastPath = lastPath; this.offset = offset; this.editingComponent = editingComponent; } } } // MyDefaultTreeCellEditor @Override public int getViewID() { return App.VIEW_ALGEBRA; } @Override public AppD getApplication() { return app; } @Override public int[] getGridColwidths() { return new int[] { getWidth() }; } @Override public int[] getGridRowHeights() { // Object root=model.getRoot(); // ArrayList<Integer> heights=new ArrayList<Integer>(); // for (int i=0;i<model.getChildCount(root);i++){ // Object folder=model.getChild(root, i); // if (model.) // } // // m.getChildCount(root); // // return new int[]{getHeight()}; int[] heights; if (getRowCount() > 0) { heights = new int[getRowCount()]; for (int i = 0; i < heights.length; i++) { heights[i] = getRowBounds(i).height; } } else { heights = new int[1]; } heights[0] += 2; return heights; } @Override public Component[][] getPrintComponents() { return new Component[][] { { this } }; } @Override public void changeLayer(GeoElement g, int oldLayer, int newLayer) { if (this.treeMode.equals(SortMode.LAYER)) { DefaultMutableTreeNode node = nodeTable.get(g); if (node != null) { ((DefaultTreeModel) getModel()).removeNodeFromParent(node); nodeTable.remove(node.getUserObject()); removeFromLayer(((DefaultTreeModel) getModel()), oldLayer); } this.add(g, newLayer); } } /** * returns settings in XML format * * public void getXML(StringBuilder sb) { * * sb.append("<algebraView>\n"); sb.append("\t<useLaTeX "); sb.append( * " value=\""); sb.append(isRenderLaTeX()); sb.append("\""); * sb.append("/>\n"); sb.append("</algebraView>\n"); } */ // temporary proxies for the temporary implementation of AlgebraController // in common public GeoElement getGeoElementForPath(Object tp) { return getGeoElementForPath((TreePath) tp); } public GeoElement getGeoElementForLocation(Object tree, int x, int y) { return getGeoElementForLocation((JTree) tree, x, y); } public Object getPathBounds(Object tp) { return getPathBounds((TreePath) tp); } // temporary proxies end @Override protected boolean show(GeoElement geo) { return super.show(geo) && geo.showInAlgebraView() && geo.isSetAlgebraVisible(); } private StringBuilder sbXML; private void updateCollapsedNodesIndices() { // no collapsed nodes if (getTreeMode() == SortMode.ORDER) { collapsedNodes = null; return; } if (collapsedNodes == null) { collapsedNodes = new ArrayList<Integer>(); } else { collapsedNodes.clear(); } DefaultMutableTreeNode root = getRoot(); for (int i = 0; i < root.getChildCount(); i++) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) root .getChildAt(i); if (isCollapsed(new TreePath(node.getPath()))) { collapsedNodes.add(i); } } } /** * returns settings in XML format */ public void getXML(StringBuilder sb, boolean asPreference) { if (sbXML == null) { sbXML = new StringBuilder(); } else { sbXML.setLength(0); } // tree mode if (getTreeMode() != SortMode.TYPE) { sbXML.append("\t<mode "); sbXML.append("val=\""); sbXML.append(getTreeMode().toInt()); sbXML.append("\""); sbXML.append("/>\n"); } // auxiliary objects boolean flag = showAuxiliaryObjects(); if (flag) { sbXML.append("\t<auxiliary "); sbXML.append("show=\""); sbXML.append(flag); sbXML.append("\""); sbXML.append("/>\n"); } // collapsed nodes updateCollapsedNodesIndices(); if (collapsedNodes != null && collapsedNodes.size() > 0) { sbXML.append("\t<collapsed "); sbXML.append("val=\""); sbXML.append(collapsedNodes.get(0)); for (int i = 1; i < collapsedNodes.size(); i++) { sbXML.append(","); sbXML.append(collapsedNodes.get(i)); } sbXML.append("\""); sbXML.append("/>\n"); } if (sbXML.length() > 0) { sb.append("<algebraView>\n"); sb.append(sbXML); sb.append("</algebraView>\n"); } } private ArrayList<Integer> collapsedNodes; private void setCollapsedNodes(int[] collapsedNodes) { if (collapsedNodes == null) { return; } if (this.collapsedNodes == null) { this.collapsedNodes = new ArrayList<Integer>(); } else { this.collapsedNodes.clear(); } for (int i = 0; i < collapsedNodes.length; i++) { this.collapsedNodes.add(collapsedNodes[i]); } } /** * apply the settings */ public void applySettings() { if (!settingsChanged) { // that means that no settings were stored in the file: reset // settings to have default AlgebraSettings settings = app.getSettings().getAlgebra(); settings.reset(); settingsChanged(settings); } settingsChanged = false; // auxilliary objects setShowAuxiliaryObjects(showAuxiliaryObjectsSettings); // collapsed nodes if (collapsedNodes == null) { return; } DefaultMutableTreeNode root = getRoot(); for (int i : collapsedNodes) { // validate i, #4346 if (i >= root.getChildCount()) { continue; } DefaultMutableTreeNode node = (DefaultMutableTreeNode) root .getChildAt(i); collapsePath(new TreePath(node.getPath())); } } private boolean showAuxiliaryObjectsSettings = false; private boolean settingsChanged = false; @Override public void settingsChanged(AbstractSettings settings) { AlgebraSettings algebraSettings = (AlgebraSettings) settings; setTreeMode(algebraSettings.getTreeMode()); showAuxiliaryObjectsSettings = algebraSettings .getShowAuxiliaryObjects(); setCollapsedNodes(algebraSettings.getCollapsedNodes()); settingsChanged = true; } @Override public void setFocus(boolean b) { // TODO Auto-generated method stub } @Override public GeoElement getLastSelectedGeo() { // TODO Auto-generated method stub return null; } @Override public void setLastSelectedGeo(GeoElement geo) { // TODO Auto-generated method stub } @Override public void startBatchUpdate() { // TODO Auto-generated method stub } @Override public void endBatchUpdate() { // TODO Auto-generated method stub } @Override public boolean suggestRepaint() { return false; // only for web } @Override public boolean isAttachedToKernel() { return attached; } @Override public GeoElement getDraggedGeo() { // temporary change to fix it because it did not compile return null; } @Override public void setShowAlgebraInput(boolean b) { // only used in web } @Override public void resetItems(boolean clear) { // TODO Auto-generated method stub } @Override public void cancelEditItem() { cancelEditing(); } @Override public boolean isEditItem() { return isEditing(); } } // AlgebraView