package org.geogebra.desktop.gui.dialog.options; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.awt.SystemColor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Hashtable; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.border.Border; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import org.geogebra.common.gui.SetLabels; import org.geogebra.common.gui.dialog.options.OptionsDefaults; import org.geogebra.common.kernel.ConstructionDefaults; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.Localization; import org.geogebra.desktop.gui.color.GeoGebraColorChooser; import org.geogebra.desktop.gui.dialog.PropertiesPanelD; import org.geogebra.desktop.gui.util.LayoutUtil; import org.geogebra.desktop.main.AppD; /** * Options with the default settings of objects. */ public class OptionsDefaultsD extends OptionsDefaults implements OptionPanelD, TreeSelectionListener, SetLabels { /** * An instance of the GeoGebra application. */ private AppD app; /** * The panel with the tabs for the different properties. */ private PropertiesPanelD propPanel; /** * A tree with the different available object types to which new default * values can be assigned. */ private JTree tree; private DefaultTreeCellRenderer treeCellRenderer; /** * The tree model. */ private DefaultTreeModel treeModel; /** * The root node of the tree. */ private DefaultMutableTreeNode rootNode; /** * Nodes for points. */ private DefaultMutableTreeNode pointsNode, pointsFreeNode, pointsDepNode, pointsPathNode, pointsInRegionNode, pointsComplexNode; private DefaultMutableTreeNode lineNode, segmentNode, vectorNode, conicNode, conicSectorNode, rayNode; private DefaultMutableTreeNode numberNode, angleNode; private DefaultMutableTreeNode functionNode, polygonNode, polylineNode, locusNode; private DefaultMutableTreeNode textNode, imageNode, booleanNode; private DefaultMutableTreeNode listNode, inequalitiesNode, functionNVarNode; // polyhedra, cylinders, cones etc private DefaultMutableTreeNode solidsNode; private JButton defaultsButton; /** * The class which contains all default objects. */ private ConstructionDefaults defaults; private JPanel wrappedPanel; /** * A dictionary which assigns a constant of the ConstructionsDefaults class * to the tree nodes. */ private static Hashtable<DefaultMutableTreeNode, Integer> typeToNode; /** * Construct an panel where the user can assign new values to the default * objects. * * @param app * application */ public OptionsDefaultsD(AppD app) { this.app = app; this.wrappedPanel = new JPanel(); defaults = app.getKernel().getConstruction().getConstructionDefaults(); initGUI(); updateGUI(); } /** * Initialize the GUI. */ private void initGUI() { // init the model of the tree initNodes(); treeModel = new DefaultTreeModel(rootNode); // init the real JTree component tree = new JTree(treeModel); tree.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); tree.setRootVisible(false); tree.setScrollsOnExpand(true); // expand the point node and select the first point tree.expandRow(0); tree.setSelectionRow(1); tree.addTreeSelectionListener(this); // disable leaf icons treeCellRenderer = new DefaultTreeCellRenderer(); treeCellRenderer.setLeafIcon(null); tree.setCellRenderer(treeCellRenderer); // create the properties panel GeoGebraColorChooser colorChooser = new GeoGebraColorChooser(app); propPanel = new PropertiesPanelD(app, colorChooser, true); propPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); propPanel.updateSelection(new Object[] { defaults .getDefaultGeo(ConstructionDefaults.DEFAULT_POINT_FREE) }); // apply defaults button defaultsButton = new JButton(); defaultsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { applyDefaults(); } }); // set the labels of the components setLabels(); // define panel properties // setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); wrappedPanel.setLayout(new BorderLayout()); // tree scroll pane tree.setBorder(BorderFactory.createEmptyBorder(2, 6, 2, 2)); JScrollPane treeScroller = new JScrollPane(tree); treeScroller.setMinimumSize(new Dimension(120, 200)); treeScroller.setBackground(tree.getBackground()); treeScroller.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, SystemColor.controlShadow)); // split pane JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScroller, propPanel); splitPane.setBorder(BorderFactory.createEmptyBorder()); // add components wrappedPanel.add(splitPane, BorderLayout.CENTER); wrappedPanel.add(LayoutUtil.flowPanel(0, 0, 20, defaultsButton), BorderLayout.SOUTH); app.setComponentOrientation(wrappedPanel); } /** * Initialize the nodes of the tree. */ private void initNodes() { // create the nodes for the tree rootNode = new DefaultMutableTreeNode(); pointsNode = new DefaultMutableTreeNode(); pointsFreeNode = new DefaultMutableTreeNode(); pointsDepNode = new DefaultMutableTreeNode(); pointsPathNode = new DefaultMutableTreeNode(); pointsInRegionNode = new DefaultMutableTreeNode(); pointsComplexNode = new DefaultMutableTreeNode(); lineNode = new DefaultMutableTreeNode(); segmentNode = new DefaultMutableTreeNode(); rayNode = new DefaultMutableTreeNode(); vectorNode = new DefaultMutableTreeNode(); conicNode = new DefaultMutableTreeNode(); conicSectorNode = new DefaultMutableTreeNode(); functionNode = new DefaultMutableTreeNode(); polygonNode = new DefaultMutableTreeNode(); polylineNode = new DefaultMutableTreeNode(); locusNode = new DefaultMutableTreeNode(); textNode = new DefaultMutableTreeNode(); imageNode = new DefaultMutableTreeNode(); numberNode = new DefaultMutableTreeNode(); angleNode = new DefaultMutableTreeNode(); booleanNode = new DefaultMutableTreeNode(); listNode = new DefaultMutableTreeNode(); inequalitiesNode = new DefaultMutableTreeNode(); functionNVarNode = new DefaultMutableTreeNode(); solidsNode = new DefaultMutableTreeNode(); rootNode.add(pointsNode); pointsNode.add(pointsFreeNode); pointsNode.add(pointsDepNode); pointsNode.add(pointsPathNode); pointsNode.add(pointsInRegionNode); pointsNode.add(pointsComplexNode); rootNode.add(lineNode); rootNode.add(segmentNode); rootNode.add(rayNode); rootNode.add(polylineNode); rootNode.add(vectorNode); rootNode.add(conicNode); rootNode.add(conicSectorNode); rootNode.add(functionNode); rootNode.add(functionNVarNode); rootNode.add(solidsNode); rootNode.add(polygonNode); rootNode.add(locusNode); rootNode.add(textNode); rootNode.add(imageNode); rootNode.add(numberNode); rootNode.add(angleNode); rootNode.add(booleanNode); rootNode.add(listNode); rootNode.add(inequalitiesNode); // create the dictionary which is used to assign a type constant (int) // to // every tree leaf createDefaultMap(); } /** * Creates the dictionary which is used to assign a type constant (int) to * every tree leaf */ private void createDefaultMap() { typeToNode = new Hashtable<DefaultMutableTreeNode, Integer>(15); typeToNode.put(pointsFreeNode, ConstructionDefaults.DEFAULT_POINT_FREE); typeToNode.put(pointsDepNode, ConstructionDefaults.DEFAULT_POINT_DEPENDENT); typeToNode.put(pointsPathNode, ConstructionDefaults.DEFAULT_POINT_ON_PATH); typeToNode.put(pointsInRegionNode, ConstructionDefaults.DEFAULT_POINT_IN_REGION); typeToNode.put(pointsComplexNode, ConstructionDefaults.DEFAULT_POINT_COMPLEX); typeToNode.put(lineNode, ConstructionDefaults.DEFAULT_LINE); typeToNode.put(segmentNode, ConstructionDefaults.DEFAULT_SEGMENT); typeToNode.put(rayNode, ConstructionDefaults.DEFAULT_RAY); typeToNode.put(vectorNode, ConstructionDefaults.DEFAULT_VECTOR); typeToNode.put(conicNode, ConstructionDefaults.DEFAULT_CONIC); typeToNode.put(conicSectorNode, ConstructionDefaults.DEFAULT_CONIC_SECTOR); typeToNode.put(functionNode, ConstructionDefaults.DEFAULT_FUNCTION); typeToNode.put(functionNVarNode, ConstructionDefaults.DEFAULT_FUNCTION_NVAR); typeToNode.put(solidsNode, ConstructionDefaults.DEFAULT_POLYHEDRON); typeToNode.put(polygonNode, ConstructionDefaults.DEFAULT_POLYGON); typeToNode.put(polylineNode, ConstructionDefaults.DEFAULT_POLYLINE); typeToNode.put(locusNode, ConstructionDefaults.DEFAULT_LOCUS); typeToNode.put(textNode, ConstructionDefaults.DEFAULT_TEXT); typeToNode.put(imageNode, ConstructionDefaults.DEFAULT_IMAGE); typeToNode.put(numberNode, ConstructionDefaults.DEFAULT_NUMBER); typeToNode.put(angleNode, ConstructionDefaults.DEFAULT_ANGLE); typeToNode.put(booleanNode, ConstructionDefaults.DEFAULT_BOOLEAN); typeToNode.put(listNode, ConstructionDefaults.DEFAULT_LIST); typeToNode.put(inequalitiesNode, ConstructionDefaults.DEFAULT_INEQUALITY); } /** * Restores all defaults to the current ConstructionDefault values. */ public void restoreDefaults() { createDefaultMap(); // update panel selection ... this should trigger the valueChanged // method TreePath path = tree.getSelectionPath(); tree.setSelectionPath(null); tree.setSelectionPath(path); // but if not, make sure that it is called certainly // defaults = // app.getKernel().getConstruction().getConstructionDefaults(); // valueChanged(null); } /** * Update the GUI to take care of new settings which were applied. */ @Override public void updateGUI() { SwingUtilities.updateComponentTreeUI(this.wrappedPanel); } /** * Update the labels of the current panel. Should be applied if the language * was changed. */ @Override public void setLabels() { // update tree labels Localization loc = app.getLocalization(); pointsNode.setUserObject(loc.getMenu("Point")); pointsFreeNode.setUserObject(loc.getMenu("PointFree")); pointsDepNode.setUserObject(loc.getMenu("PointDep")); pointsPathNode.setUserObject(loc.getMenu("PointOnPath")); pointsInRegionNode.setUserObject(loc.getMenu("PointInside")); pointsComplexNode.setUserObject(loc.getMenu("ComplexNumber")); lineNode.setUserObject(loc.getMenu("Line")); segmentNode.setUserObject(loc.getMenu("Segment")); rayNode.setUserObject(loc.getMenu("Ray")); vectorNode.setUserObject(loc.getMenu("Vector")); conicNode.setUserObject(loc.getMenu("Conic")); conicSectorNode.setUserObject(loc.getMenu("Sector")); functionNode.setUserObject(loc.getMenu("Function")); functionNVarNode.setUserObject(loc.getMenu("MultivariableFunction")); solidsNode.setUserObject(loc.getMenu("Solids")); polygonNode.setUserObject(loc.getMenu("Polygon")); polylineNode.setUserObject(loc.getMenu("PolyLine")); locusNode.setUserObject(loc.getMenu("Locus")); textNode.setUserObject(loc.getMenu("Text")); imageNode.setUserObject(loc.getMenu("Image")); numberNode.setUserObject(loc.getMenu("Slider")); angleNode.setUserObject(loc.getMenu("Angle")); booleanNode.setUserObject(loc.getMenu("Boolean")); listNode.setUserObject(loc.getMenu("List")); inequalitiesNode.setUserObject(loc.getMenu("Inequality")); defaultsButton.setText(loc.getMenu("ApplyToSelectedObjects")); propPanel.setLabels(); } /** * The selection has changed. */ @Override public void valueChanged(TreeSelectionEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree .getLastSelectedPathComponent(); if (node == null || node == rootNode) { propPanel.setVisible(false); } else { if (!propPanel.isVisible()) { propPanel.setVisible(true); } if (node == pointsNode) { Object[] selection = new Object[pointsNode.getChildCount()]; for (int i = 0; i < pointsNode.getChildCount(); ++i) { selection[i] = defaults.getDefaultGeo( typeToNode.get(pointsNode.getChildAt(i))); } propPanel.updateSelection(selection); } else { if (typeToNode.containsKey(node)) { propPanel.updateSelection(new Object[] { defaults.getDefaultGeo(typeToNode.get(node)) }); } } } } /** * Save the settings of this panel. */ @Override public void applyModifications() { propPanel.applyModifications(); } @Override public JPanel getWrappedPanel() { return this.wrappedPanel; } @Override public void revalidate() { getWrappedPanel().revalidate(); } @Override public void setBorder(Border border) { wrappedPanel.setBorder(border); } /** * Reset the visual style of the selected elements. * * TODO Does not work with lists (F.S.) */ private void applyDefaults() { for (GeoElement geo : app.getSelectionManager().getSelectedGeos()) { defaults.setDefaultVisualStyles(geo, true); geo.updateRepaint(); } } @Override public void updateFont() { Font font = app.getPlainFont(); tree.setFont(font); treeCellRenderer.setFont(font); defaultsButton.setFont(font); // propPanel.setFont(font); } @Override public void setSelected(boolean flag) { // see OptionsEuclidianD for possible implementation } }