001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002 *
003 * Copyright 2000-2013, Michael Meyling <mime@qedeq.org>.
004 *
005 * "Hilbert II" is free software; you can redistribute
006 * it and/or modify it under the terms of the GNU General Public
007 * License as published by the Free Software Foundation; either
008 * version 2 of the License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU General Public License for more details.
014 */
015
016 package org.qedeq.gui.se.tree;
017
018 import java.awt.event.MouseAdapter;
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import javax.swing.SwingUtilities;
023 import javax.swing.event.TreeModelEvent;
024 import javax.swing.event.TreeModelListener;
025 import javax.swing.event.TreeSelectionEvent;
026 import javax.swing.event.TreeSelectionListener;
027 import javax.swing.tree.DefaultMutableTreeNode;
028 import javax.swing.tree.TreePath;
029
030 import org.qedeq.base.trace.Trace;
031 import org.qedeq.gui.se.control.QedeqController;
032 import org.qedeq.gui.se.main.LowerTabbedView;
033 import org.qedeq.gui.se.main.UpperTabbedView;
034 import org.qedeq.kernel.bo.common.QedeqBo;
035
036
037 /**
038 * Controller for a certain JTree.
039 *
040 * A Controller, which represents the classes connecting the model and the view, and is used to
041 * communicate between classes in the model and view.
042 *
043 * TODO mime 20080126: rather work with listeners than referencing other views
044 *
045 * @version $Revision: 1.8 $
046 * @author Michael Meyling
047 */
048 public final class QedeqTreeCtrl implements TreeModelListener {
049
050 /** This class. */
051 private static final Class CLASS = QedeqTreeCtrl.class;
052
053 /** Tree view. */
054 private final QedeqTreeView treeView;
055
056 /** Tree model. */
057 private final QedeqTreeModel treeModel;
058
059 /** Context menu. */
060 private final QedeqTreeContextMenu contextMenu;
061
062 /** Reference to view. */
063 private final UpperTabbedView pane;
064
065 /** Reference to view. */
066 private final LowerTabbedView lower;
067
068
069 /**
070 * Tree controller.
071 *
072 * @param treeView View.
073 * @param treeModel Model.
074 * @param pane Dependent view.
075 * @param lowerView Dependent view.
076 * @param controller Main controller.
077 */
078 public QedeqTreeCtrl(final QedeqTreeView treeView, final QedeqTreeModel treeModel,
079 final UpperTabbedView pane, final LowerTabbedView lowerView,
080 final QedeqController controller) {
081
082 this.treeView = treeView;
083 this.treeModel = treeModel;
084 this.treeModel.addTreeModelListener(this);
085 this.contextMenu = new QedeqTreeContextMenu(controller);
086 this.treeView.treeAddMouseListener(new QedeqMouseListener());
087 this.treeView.addTreeSelectionListener(new SelectionChangedCommand());
088 // LATER mime 20071024: inform others per listener about this event
089 this.pane = pane;
090 this.lower = lowerView;
091 }
092
093 /**
094 * Get all selected QedeqBos.
095 *
096 * @return Selected QedeqBos.
097 * @throws NothingSelectedException Nothing was selected.
098 */
099 public final QedeqBo[] getSelected() throws NothingSelectedException {
100 final String method = "getSelected";
101 Trace.begin(CLASS, this, method);
102 try {
103 TreePath[] selected = treeView.getSelectionPaths();
104 final List list = new ArrayList();
105 if (selected != null && selected.length > 0) {
106 Trace.trace(CLASS, this, "actionPerformed",
107 "selection=" + selected[selected.length - 1]);
108 for (int i = 0; i < selected.length; i++) {
109 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)
110 (selected[i].getLastPathComponent());
111 if (node instanceof QedeqTreeNode) {
112 final QedeqBo prop = (QedeqBo) node.getUserObject();
113 list.add(prop);
114 }
115 }
116 }
117 if (list.size() <= 0) {
118 throw new NothingSelectedException();
119 }
120 return (QedeqBo[]) list.toArray(new QedeqBo[0]);
121 } catch (RuntimeException ex) {
122 Trace.trace(CLASS, this, method, ex);
123 throw new NothingSelectedException();
124 } finally {
125 Trace.end(CLASS, this, method);
126 }
127 }
128
129 /**
130 * Get edited QEDEQ text.
131 *
132 * @return QEDEQ text
133 * @throws IllegalStateException text is not editable
134 */
135 public final String getEditedQedeq() {
136 return this.pane.getEditedQedeq();
137 }
138
139 public void treeNodesChanged(final TreeModelEvent e) {
140 Trace.param(CLASS, this, "treeNodesChanged", "event", e);
141 final Runnable runLater = new Runnable() {
142 public void run() {
143 try {
144 pane.updateView();
145 } catch (RuntimeException ex) {
146 Trace.fatal(CLASS, this, "treeNodesChanged", "unexpected problem", ex);
147 }
148 }
149 };
150 SwingUtilities.invokeLater(runLater);
151 Trace.end(CLASS, this, "treeNodesChanged");
152 }
153
154 public void treeNodesInserted(final TreeModelEvent e) {
155 Trace.begin(CLASS, this, "treeNodesInserted");
156 // 20080501 mime: solution of an old problem:
157 // because the root is invisible its children are invisible too. to make them visible
158 // we must expand the the path of the root node. but this is possible only if there is
159 // already a child node there. so if the first node is added we must expand the
160 // path of root. when the model sends us this event we can not simply expand the path
161 // instantly because if we do so, the new node is added twice! This is done for example for
162 // VariableHeightLayoutCache.visibleNodes in the two methods
163 // setExpandedState(TreePath path, boolean isExpanded) (called by expandPath) and in
164 // (treeNodesInserted(TreeModelEvent e) (called by DefaultTreeModel.nodesWereInserted(
165 // TreeNode node, int[] childIndices)
166 // To solve this dilemma we simply generate a new event that is handled later on
167 final Runnable runLater = new Runnable() {
168 public void run() {
169 try {
170 if (((DefaultMutableTreeNode) treeModel.getRoot()).getChildCount() > 0) {
171 Trace.trace(CLASS, this, "treeNodesInserted", "expandPath");
172 treeView.expandPath(new TreePath(treeModel.getRoot()));
173 }
174 } catch (RuntimeException ex) {
175 Trace.fatal(CLASS, this, "treeNodesInserted", "unexpected problem", ex);
176 }
177 }
178 };
179 SwingUtilities.invokeLater(runLater);
180 Trace.end(CLASS, this, "treeNodesInserted");
181 }
182
183
184 public void treeNodesRemoved(final TreeModelEvent e) {
185 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)
186 (e.getTreePath().getLastPathComponent());
187 Trace.trace(CLASS, this, "treeNodeRemoved", node.getUserObject());
188 }
189
190
191 public void treeStructureChanged(final TreeModelEvent e) {
192 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)
193 (e.getTreePath().getLastPathComponent());
194 Trace.trace(CLASS, this, "treeStructureChanged", node.getUserObject());
195 }
196
197
198 /**
199 * Changes node view, depending from chosen object.
200 */
201 private class SelectionChangedCommand implements TreeSelectionListener {
202
203 public SelectionChangedCommand() {
204 }
205
206 public void valueChanged(final TreeSelectionEvent event) {
207 // TODO mime 20071024: inform others per listener about this event
208 Trace.trace(CLASS, this, "valueChanged", event);
209 TreePath path = event.getPath();
210 QedeqTreeNode treeNode = (QedeqTreeNode) path.getLastPathComponent();
211 if (event.isAddedPath()
212 && treeNode.getUserObject() instanceof QedeqBo) {
213 QedeqBo prop = (QedeqBo) treeNode.getUserObject();
214 pane.setQedeqModel(prop);
215 lower.setQedeqModel(prop);
216 } else {
217 pane.setQedeqModel(null);
218 lower.setQedeqModel(null);
219 }
220 }
221 }
222
223 /**
224 * Handle mouse events.
225 */
226 private class QedeqMouseListener extends MouseAdapter {
227
228 public void mousePressed(final java.awt.event.MouseEvent evt) {
229
230 if (SwingUtilities.isRightMouseButton(evt)) {
231 try {
232 getSelected();
233 } catch (NothingSelectedException e) {
234 final TreePath path = treeView.getPathForLocation(evt.getX(), evt.getY());
235 if (path != null) {
236 treeView.setSelectionPath(path);
237 } // TODO mime 20080126: other ContextMenu if no selection was done
238 }
239 contextMenu.show(evt.getComponent(),
240 evt.getX(), evt.getY());
241 }
242 // super.mousePressed(evt);
243 }
244
245 }
246
247 }
|