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 * @author Michael Meyling
046 */
047 public final class QedeqTreeCtrl implements TreeModelListener {
048
049 /** This class. */
050 private static final Class CLASS = QedeqTreeCtrl.class;
051
052 /** Tree view. */
053 private final QedeqTreeView treeView;
054
055 /** Tree model. */
056 private final QedeqTreeModel treeModel;
057
058 /** Context menu. */
059 private final QedeqTreeContextMenu contextMenu;
060
061 /** Reference to view. */
062 private final UpperTabbedView pane;
063
064 /** Reference to view. */
065 private final LowerTabbedView lower;
066
067
068 /**
069 * Tree controller.
070 *
071 * @param treeView View.
072 * @param treeModel Model.
073 * @param pane Dependent view.
074 * @param lowerView Dependent view.
075 * @param controller Main controller.
076 */
077 public QedeqTreeCtrl(final QedeqTreeView treeView, final QedeqTreeModel treeModel,
078 final UpperTabbedView pane, final LowerTabbedView lowerView,
079 final QedeqController controller) {
080
081 this.treeView = treeView;
082 this.treeModel = treeModel;
083 this.treeModel.addTreeModelListener(this);
084 this.contextMenu = new QedeqTreeContextMenu(controller);
085 this.treeView.treeAddMouseListener(new QedeqMouseListener());
086 this.treeView.addTreeSelectionListener(new SelectionChangedCommand());
087 // LATER mime 20071024: inform others per listener about this event
088 this.pane = pane;
089 this.lower = lowerView;
090 }
091
092 /**
093 * Get all selected QedeqBos.
094 *
095 * @return Selected QedeqBos.
096 * @throws NothingSelectedException Nothing was selected.
097 */
098 public final QedeqBo[] getSelected() throws NothingSelectedException {
099 final String method = "getSelected";
100 Trace.begin(CLASS, this, method);
101 try {
102 TreePath[] selected = treeView.getSelectionPaths();
103 final List list = new ArrayList();
104 if (selected != null && selected.length > 0) {
105 Trace.trace(CLASS, this, "actionPerformed",
106 "selection=" + selected[selected.length - 1]);
107 for (int i = 0; i < selected.length; i++) {
108 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)
109 (selected[i].getLastPathComponent());
110 if (node instanceof QedeqTreeNode) {
111 final QedeqBo prop = (QedeqBo) node.getUserObject();
112 list.add(prop);
113 }
114 }
115 }
116 if (list.size() <= 0) {
117 throw new NothingSelectedException();
118 }
119 return (QedeqBo[]) list.toArray(new QedeqBo[0]);
120 } catch (RuntimeException ex) {
121 Trace.trace(CLASS, this, method, ex);
122 throw new NothingSelectedException();
123 } finally {
124 Trace.end(CLASS, this, method);
125 }
126 }
127
128 /**
129 * Get edited QEDEQ text.
130 *
131 * @return QEDEQ text
132 * @throws IllegalStateException text is not editable
133 */
134 public final String getEditedQedeq() {
135 return this.pane.getEditedQedeq();
136 }
137
138 public void treeNodesChanged(final TreeModelEvent e) {
139 Trace.param(CLASS, this, "treeNodesChanged", "event", e);
140 final Runnable runLater = new Runnable() {
141 public void run() {
142 try {
143 pane.updateView();
144 } catch (RuntimeException ex) {
145 Trace.fatal(CLASS, this, "treeNodesChanged", "unexpected problem", ex);
146 }
147 }
148 };
149 SwingUtilities.invokeLater(runLater);
150 Trace.end(CLASS, this, "treeNodesChanged");
151 }
152
153 public void treeNodesInserted(final TreeModelEvent e) {
154 Trace.begin(CLASS, this, "treeNodesInserted");
155 // 20080501 mime: solution of an old problem:
156 // because the root is invisible its children are invisible too. to make them visible
157 // we must expand the the path of the root node. but this is possible only if there is
158 // already a child node there. so if the first node is added we must expand the
159 // path of root. when the model sends us this event we can not simply expand the path
160 // instantly because if we do so, the new node is added twice! This is done for example for
161 // VariableHeightLayoutCache.visibleNodes in the two methods
162 // setExpandedState(TreePath path, boolean isExpanded) (called by expandPath) and in
163 // (treeNodesInserted(TreeModelEvent e) (called by DefaultTreeModel.nodesWereInserted(
164 // TreeNode node, int[] childIndices)
165 // To solve this dilemma we simply generate a new event that is handled later on
166 final Runnable runLater = new Runnable() {
167 public void run() {
168 try {
169 if (((DefaultMutableTreeNode) treeModel.getRoot()).getChildCount() > 0) {
170 Trace.trace(CLASS, this, "treeNodesInserted", "expandPath");
171 treeView.expandPath(new TreePath(treeModel.getRoot()));
172 }
173 } catch (RuntimeException ex) {
174 Trace.fatal(CLASS, this, "treeNodesInserted", "unexpected problem", ex);
175 }
176 }
177 };
178 SwingUtilities.invokeLater(runLater);
179 Trace.end(CLASS, this, "treeNodesInserted");
180 }
181
182
183 public void treeNodesRemoved(final TreeModelEvent e) {
184 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)
185 (e.getTreePath().getLastPathComponent());
186 Trace.trace(CLASS, this, "treeNodeRemoved", node.getUserObject());
187 }
188
189
190 public void treeStructureChanged(final TreeModelEvent e) {
191 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)
192 (e.getTreePath().getLastPathComponent());
193 Trace.trace(CLASS, this, "treeStructureChanged", node.getUserObject());
194 }
195
196
197 /**
198 * Changes node view, depending from chosen object.
199 */
200 private class SelectionChangedCommand implements TreeSelectionListener {
201
202 public SelectionChangedCommand() {
203 // nothing to do
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 }
|