001: /*
002: * Gruntspud
003: *
004: * Copyright (C) 2002 Brett Smith.
005: *
006: * Written by: Brett Smith <t_magicthize@users.sourceforge.net>
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Library General Public License
010: * as published by the Free Software Foundation; either version 2 of
011: * the License, or (at your option) any later version.
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU Library General Public License for more details.
016: *
017: * You should have received a copy of the GNU Library General Public
018: * License along with this program; if not, write to the Free Software
019: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
020: */
021:
022: package gruntspud.ui.view;
023:
024: import gruntspud.CVSFileNode;
025: import gruntspud.Constants;
026: import gruntspud.Gruntspud;
027: import gruntspud.GruntspudHost;
028: import gruntspud.SortCriteria;
029: import gruntspud.file.FileTypeMapping;
030: import gruntspud.ui.ListSearch;
031: import gruntspud.ui.ListSearchListener;
032: import gruntspud.ui.UIUtil;
033:
034: import java.awt.BorderLayout;
035: import java.awt.CardLayout;
036: import java.awt.event.MouseAdapter;
037: import java.awt.event.MouseEvent;
038: import java.io.File;
039: import java.util.Enumeration;
040: import java.util.Iterator;
041: import java.util.Vector;
042:
043: import javax.swing.Icon;
044: import javax.swing.JComponent;
045: import javax.swing.JLabel;
046: import javax.swing.JPanel;
047: import javax.swing.JScrollPane;
048: import javax.swing.UIManager;
049: import javax.swing.event.TreeSelectionEvent;
050: import javax.swing.event.TreeSelectionListener;
051: import javax.swing.tree.DefaultTreeModel;
052: import javax.swing.tree.TreePath;
053:
054: /**
055: * Description of the Class
056: *
057: *@author magicthize
058: *@created 26 May 2002
059: */
060: public class TreeCVSView extends AbstractCVSView implements
061: TreeSelectionListener, ListSearchListener {
062: private CVSFileNodeTree tree;
063: private boolean adjusting;
064: private JScrollPane scroller;
065: private CVSFileNode cwdNode;
066: private SortCriteria sortCriteria;
067: private String textMask;
068: private ListSearch listSearch;
069: private JPanel treeComponent;
070: private CardLayout cardLayout;
071:
072: /**
073: * Creates a new TreeCVSView object.
074: *
075: * @param sortCriteria DOCUMENT ME!
076: * @param textMask DOCUMENT ME!
077: */
078: public TreeCVSView(SortCriteria sortCriteria, String textMask) {
079: super ("Folders", UIUtil
080: .getCachedIcon(Constants.ICON_TOOL_SMALL_HOME),
081: "Tree view of CVS files");
082: this .sortCriteria = sortCriteria;
083: this .textMask = textMask;
084: }
085:
086: /**
087: * DOCUMENT ME!
088: *
089: * @param searchText DOCUMENT ME!
090: */
091: public void searchUpdated(String searchText) {
092: Constants.UI_LOG.debug("Searching for node begining with "
093: + searchText);
094: CVSFileNode n = (CVSFileNode) tree.getModel().getRoot();
095: CVSFileNode f = searchNode(n, searchText.toLowerCase());
096: if (f != null) {
097: setSelectedNodes(new CVSFileNode[] { f });
098: }
099: }
100:
101: private CVSFileNode searchNode(CVSFileNode n, String text) {
102: if (n.getName().toLowerCase().startsWith(text)) {
103: return n;
104: } else if (!n.isLeaf() && n.isChildListLoaded()
105: && tree.isExpanded(getPathForNode(n))) {
106: for (int i = 0; i < n.getChildCount(); i++) {
107: CVSFileNode f = (CVSFileNode) n.getChildAt(i);
108: CVSFileNode r = searchNode(f, text);
109: if (r != null) {
110: return r;
111: }
112: }
113: }
114: return null;
115: }
116:
117: /**
118: * DOCUMENT ME!
119: */
120: public void searchCancelled() {
121:
122: }
123:
124: /**
125: * DOCUMENT ME!
126: */
127: public void searchComplete(String searchText) {
128: Constants.UI_LOG.debug("Search complete with '" + searchText
129: + "'");
130: searchUpdated(searchText);
131: }
132:
133: /**
134: * DOCUMENT ME!
135: *
136: * @return DOCUMENT ME!
137: */
138: public boolean canClose() {
139: return false;
140: }
141:
142: private void initialiseTree(CVSFileNode node) {
143: GruntspudHost host = getViewManager().getContext().getHost();
144: String lineStyle = host.getProperty(
145: Constants.OPTIONS_DISPLAY_EXPLORER_LINE_STYLE, "None");
146: Constants.UI_LOG.debug("Line style is " + lineStyle);
147: tree.putClientProperty("JTree.lineStyle", lineStyle);
148: tree.setHideFileNodes(host.getBooleanProperty(
149: Constants.OPTIONS_DISPLAY_HIDE_FILES_IN_TREE, false));
150: ((CVSFileNodeTreeCellRenderer) tree.getCellRenderer())
151: .setShowSubstTypes(host.getBooleanProperty(
152: Constants.OPTIONS_DISPLAY_SUBST_TYPES_IN_TREE,
153: true));
154: ((CVSFileNodeTreeCellRenderer) tree.getCellRenderer())
155: .setTextMask(textMask);
156: ((CVSFileNodeTreeCellRenderer) tree.getCellRenderer())
157: .setHighlight(getViewManager()
158: .getContext()
159: .getHost()
160: .getBooleanProperty(
161: Constants.OPTIONS_DISPLAY_HIGHLIGHT_READ_ONLY_AND_MISSING_FILES,
162: true));
163:
164: if ((node != null) && node.getFile().exists()) {
165: tree.setRootVisible(host.getBooleanProperty(
166: Constants.OPTIONS_DISPLAY_SHOW_ROOT_TREE_NODE,
167: false));
168: tree.setEnabled(true);
169: } else {
170: tree.setRootVisible(true);
171: tree.setEnabled(false);
172: }
173: }
174:
175: /**
176: * DOCUMENT ME!
177: *
178: * @param cwdNode DOCUMENT ME!
179: */
180: public void setCWDNode(CVSFileNode cwdNode) {
181: setSelectedNodes(new CVSFileNode[] { cwdNode });
182: }
183:
184: /**
185: * DOCUMENT ME!
186: *
187: * @param manager DOCUMENT ME!
188: */
189: public void start(ViewManager manager) {
190: super .start(manager);
191: CVSFileNode node = new CVSFileNode(manager.getContext(), null,
192: null, new File("/DUMMY_FILE"), null);
193: tree = new CVSFileNodeTree(node, textMask, manager.getContext());
194: tree.addTreeSelectionListener(this );
195: int insets = manager.getContext().getHost()
196: .getFileRendererInsets().top
197: + manager.getContext().getHost()
198: .getFileRendererInsets().bottom;
199: Icon icon = manager.getContext().getHost().getIcon(
200: Constants.ICON_TOOL_SMALL_DEFAULT_FOLDER_OPEN);
201: int rh = Math.max(insets
202: + (icon == null ? 0 : icon.getIconHeight()),
203: 16 + insets);
204: tree.setRowHeight(rh);
205: tree.addMouseListener(new MouseAdapter() {
206: public void mouseClicked(MouseEvent evt) {
207: CVSFileNode[] s = getSelectedNodes();
208: if (evt.getClickCount() == (s != null && s.length > 0
209: && s[0].getFile().isDirectory() ? 3 : 2)) {
210: if ((s != null) && (s.length == 1)) {
211: getViewManager().getContext().openNode(s[0],
212: FileTypeMapping.OPEN_USING_DEFAULT);
213: }
214: } else if ((evt.getModifiers() & MouseEvent.BUTTON3_MASK) > 0) {
215: TreePath path = tree.getPathForLocation(evt.getX(),
216: evt.getY());
217:
218: if (path != null) {
219: boolean inSelection = false;
220: TreePath[] sel = tree.getSelectionPaths();
221:
222: if (sel != null) {
223: for (int i = 0; (i < sel.length)
224: && !inSelection; i++) {
225: if (sel[i].equals(path)) {
226: inSelection = true;
227:
228: }
229: }
230: }
231: if (!inSelection) {
232: tree.setSelectedFileNode((CVSFileNode) path
233: .getLastPathComponent());
234: }
235: }
236:
237: getViewManager().showNodeContextMenu(tree,
238: evt.getX(), evt.getY());
239: }
240: }
241: });
242:
243: if (Gruntspud.is14())
244: listSearch = new ListSearch(tree, this );
245:
246: // Create the 'Loading tree' panel
247: JPanel loading = new JPanel(new BorderLayout());
248: JLabel loadingLabel = new JLabel("Loading file tree ..", UIUtil
249: .getCachedIcon(Constants.ICON_TOOL_SMALL_STOP_COMMAND),
250: JLabel.CENTER);
251: loading.add(loadingLabel);
252: loading.setOpaque(true);
253: loading.setBackground(UIManager.getColor("Tree.background"));
254: loading.setForeground(UIManager.getColor("Tree.foreground"));
255: loading.setFont(UIManager.getFont("Tree.font"));
256:
257: //
258: scroller = new JScrollPane(tree);
259: treeComponent = new JPanel(cardLayout = new CardLayout());
260: treeComponent.add("scroller", scroller);
261: treeComponent.add("loading", loading);
262: cardLayout.show(treeComponent, "scroller");
263: }
264:
265: /**
266: * DOCUMENT ME!
267: *
268: * @return DOCUMENT ME!
269: */
270: public CVSFileNode getCWDNode() {
271: return cwdNode;
272: }
273:
274: /**
275: * DOCUMENT ME!
276: */
277: public void stop() {
278: super .stop();
279: if (listSearch != null)
280: listSearch.removeSearch();
281: tree.removeTreeSelectionListener(this );
282: }
283:
284: private synchronized TreePath getPathForNode(CVSFileNode node) {
285: return new TreePath(((DefaultTreeModel) tree.getModel())
286: .getPathToRoot(node));
287: }
288:
289: /**
290: * DOCUMENT ME!
291: */
292: public synchronized void resort() {
293: ((DefaultTreeModel) tree.getModel()).reload();
294: }
295:
296: /**
297: * DOCUMENT ME!
298: *
299: * @param node DOCUMENT ME!
300: */
301: public synchronized void updateNode(CVSFileNode node) {
302: if (node != null) {
303: synchronized (tree.getTreeLock()) {
304: ((DefaultTreeModel) tree.getModel()).reload(node);
305: }
306: }
307: }
308:
309: /**
310: * DOCUMENT ME!
311: *
312: * @param node DOCUMENT ME!
313: */
314: public synchronized void refilterAndResort() {
315: CVSFileNode node = getViewManager().getRootNode();
316: if (node != null) {
317: CVSFileNode[] sel = getSelectedNodes();
318: ((DefaultTreeModel) tree.getModel())
319: .reload((CVSFileNode) tree.getModel().getRoot());
320: setSelectedNodes(sel);
321: }
322: }
323:
324: /**
325: * DOCUMENT ME!
326: *
327: * @param node DOCUMENT ME!
328: */
329: public synchronized void reload(CVSFileNode node) {
330: synchronized (tree.getTreeLock()) {
331: adjusting = true;
332: if (node == getViewManager().getRootNode()) {
333: initialiseTree(node);
334: }
335: TreePath p = getPathForNode(node);
336: final Vector expanded = new Vector();
337: Enumeration e = tree.getExpandedDescendants(p);
338: while (e != null && e.hasMoreElements()) {
339: expanded.addElement(e.nextElement());
340: }
341: boolean expand = tree.isExpanded(p);
342: ((DefaultTreeModel) tree.getModel()).reload(node);
343: tree.repaint();
344: for (Iterator i = expanded.iterator(); i.hasNext();) {
345: p = (TreePath) i.next();
346: if (tree.getPathBounds(p) != null)
347: tree.expandPath(p);
348: }
349: adjusting = false;
350: fireViewEvent(new ViewEvent(this ,
351: ViewEvent.SELECTION_CHANGED, true));
352: }
353: }
354:
355: /**
356: * DOCUMENT ME!
357: *
358: * @param evt DOCUMENT ME!
359: */
360: public synchronized void valueChanged(TreeSelectionEvent evt) {
361: CVSFileNode n = tree.getSelectedFileNode();
362:
363: if (n != null) {
364: CVSFileNode newCWD = null;
365:
366: if (n.isLeaf()) {
367: newCWD = (CVSFileNode) n.getParent();
368: } else {
369: newCWD = n;
370:
371: }
372: if (newCWD != cwdNode) {
373: cwdNode = newCWD;
374: fireViewEvent(new ViewEvent(this ,
375: ViewEvent.CWD_CHANGED, adjusting));
376: }
377: }
378:
379: fireViewEvent(new ViewEvent(this , ViewEvent.SELECTION_CHANGED,
380: adjusting));
381: }
382:
383: /**
384: * DOCUMENT ME!
385: *
386: * @return DOCUMENT ME!
387: */
388: public JComponent getViewComponent() {
389: return treeComponent;
390: }
391:
392: /**
393: * DOCUMENT ME!
394: *
395: * @param rootNode DOCUMENT ME!
396: */
397: public synchronized void setRootNode(CVSFileNode rootNode) {
398: adjusting = true;
399: tree.clearSelection();
400: if (rootNode != tree.getModel().getRoot()) {
401: ((DefaultTreeModel) tree.getModel()).setRoot(rootNode);
402: }
403: adjusting = false;
404: }
405:
406: /**
407: * DOCUMENT ME!
408: *
409: * @param sel DOCUMENT ME!
410: */
411: public synchronized void setSelectedNodes(CVSFileNode[] sel) {
412: adjusting = true;
413: tree.setSelectedFileNodes(sel);
414: adjusting = false;
415: }
416:
417: /**
418: * DOCUMENT ME!
419: *
420: * @return DOCUMENT ME!
421: */
422: public CVSFileNode[] getSelectedNodes() {
423: return tree.getSelectedFileNodes();
424: }
425:
426: /**
427: * DOCUMENT ME!
428: *
429: * @param evt DOCUMENT ME!
430: */
431: public synchronized void viewEventNotify(ViewEvent evt) {
432: if (evt.getType() == ViewEvent.TREE_STARTED_LOADING) {
433: cardLayout.show(treeComponent, "loading");
434: } else if (evt.getType() == ViewEvent.TREE_FINISHED_LOADING) {
435: cardLayout.show(treeComponent, "scroller");
436: }
437: }
438: }
|