001:/*
002: * Copyright (c) 2000, Jacob Smullyan.
003: *
004: * This is part of SkunkDAV, a WebDAV client. See http://skunkdav.sourceforge.net/
005: * for the latest version.
006: *
007: * SkunkDAV is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License as published
009: * by the Free Software Foundation; either version 2, or (at your option)
010: * any later version.
011: *
012: * SkunkDAV 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 GNU
015: * General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with SkunkDAV; see the file COPYING. If not, write to the Free
019: * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
020: * 02111-1307, USA.
021:*/
022:
023:package org.skunk.dav.client.gui;
024:
025:import java.awt.BorderLayout;
026:import java.awt.Dimension;
027:import java.awt.Component;
028:import java.io.File;
029:import java.io.IOException;
030:import java.util.ArrayList;
031:import java.util.Enumeration;
032:import java.util.Iterator;
033:import java.util.ListIterator;
034:import java.util.Map;
035:import javax.swing.ImageIcon;
036:import javax.swing.JComponent;
037:import javax.swing.JFileChooser;
038:import javax.swing.JLabel;
039:import javax.swing.JOptionPane;
040:import javax.swing.JPanel;
041:import javax.swing.JScrollPane;
042:import javax.swing.JSplitPane;
043:import javax.swing.JTable;
044:import javax.swing.JTree;
045:import javax.swing.ListSelectionModel;
046:import javax.swing.SwingUtilities;
047:import javax.swing.ToolTipManager;
048:import javax.swing.UIManager;
049:import javax.swing.border.Border;
050:import javax.swing.event.TableModelListener;
051:import javax.swing.event.TreeModelListener;
052:import javax.swing.table.DefaultTableColumnModel;
053:import javax.swing.table.DefaultTableCellRenderer;
054:import javax.swing.table.TableColumn;
055:import javax.swing.tree.DefaultMutableTreeNode;
056:import javax.swing.tree.TreeNode;
057:import javax.swing.tree.TreePath;
058:import org.skunk.assert.Assertion;
059:import org.skunk.config.Configurator;
060:import org.skunk.dav.client.DAVConstants;
061:import org.skunk.dav.client.DAVFile;
062:import org.skunk.dav.client.Lock;
063:import org.skunk.dav.client.gui.editor.DAVEditor;
064:import org.skunk.dav.client.gui.editor.EditEvent;
065:import org.skunk.dav.client.gui.editor.EditListener;
066:import org.skunk.swing.TreeNodeChooser;
067:import org.skunk.trace.Debug;
068:
069:/**
070: * An embeddable widget that presents conjoined
071: * tree and table views of a DAV file hierarchy.
072: *
073: * @author Jacob Smullyan
074: * @version $Version$
075: */
076:public class Explorer extends JPanel implements Buffer, EditListener
077:{
078: static final long serialVersionUID = 3129234418500414985L;
079:
080: private static ArrayList allExplorers;
081: private DefaultMutableTreeNode rootNode;
082: private DAVTreeModel treeModel;
083: private DAVTableModel tableModel;
084: private JTable table;
085: private JTree tree;
086:
087: /*
088: *
089: *configurable properties --default values
090: *
091: */
092:
093: private DAVTableHeader[] tableHeaders=new DAVTableHeader[]
094: {
095: DAVTableHeader.RESOURCETYPE,
096: DAVTableHeader.LOCK,
097: DAVTableHeader.FILE_NAME,
098: DAVTableHeader.CONTENT_TYPE,
099: DAVTableHeader.CONTENT_LENGTH,
100: DAVTableHeader.LAST_MODIFIED,
101: DAVTableHeader.OWNER
102: };
103:
104: private boolean showTableVerticalLines=true;
105: private boolean showTableHorizontalLines=true;
106:
107: public static final String TABLE_HEADERS_PROPERTY="tableHeaders";
108:
109: static
110: {
111: allExplorers=new ArrayList();
112: }
113:
114: public static synchronized Iterator explorers()
115: {
116: return ((ArrayList)allExplorers.clone()).iterator();
117: }
118:
119: public static int getExplorerCount()
120: {
121: return allExplorers.size();
122: }
123:
124: public static Explorer guessActiveExplorer()
125: {
126: for (ListIterator lit=allExplorers.listIterator();lit.hasNext();)
127: {
128: Explorer ex=(Explorer) lit.next();
129: //if the explorer is contained by something
130: //which in turn contains something that has focus,
131: //return it
132: if (SwingUtilities.findFocusOwner(SwingUtilities.getRoot(ex))!=null)
133: return ex;
134: }
135: return null;
136: }
137:
138: public Explorer()
139: {
140: super ();
141: initComponents();
142: allExplorers.add(this );
143: }
144:
145: /* IMPLEMENTATION OF Buffer INTERFACE */
146:
147: public String getName()
148: {
149: return ResourceManager.getMessage(ResourceManager.EXPLORER_NAME);
150: }
151:
152: public JComponent getComponent()
153: {
154: return this ;
155: }
156:
157: public void docking()
158: {
159: }
160:
161: public void undocking()
162: {
163: }
164:
165: /* END OF Buffer IMPLEMENTATION */
166:
167: /* IMPLEMENTATION OF EditListener INTERFACE */
168:
169: public void editPerformed(EditEvent event)
170: {
171: int code=event.getEditCode();
172: final DAVEditor editor=(DAVEditor)event.getSource();
173: Runnable successRunner;
174: switch (code)
175: {
176: case EditEvent.CLOSE:
177: Debug.trace(this , Debug.DP3, "received EditEvent.CLOSE");
178: //will probably want to unlock, but that should be configurable
179: break;
180: case EditEvent.SAVE:
181: Debug.trace(this , Debug.DP3, "received EditEvent.SAVE");
182:
183: successRunner=new Runnable()
184: {
185: public void run()
186: {
187: editor.setDirty(false);
188: }
189: };
190: createFile(editor.getResourceName(), editor.getResourceBody(), successRunner);
191: editor.setDirty(false);
192: break;
193: case EditEvent.SAVE_AS:
194: Debug.trace(this , Debug.DP3, "received EditEvent.SAVE_AS");
195: //get old file info, so we can perform an unlock
196: DAVFile oldFile=editor.getDAVFile();
197: DAVTreeNode oldParentNode=getNodeForFile(oldFile);
198: //get save target
199: String title=ResourceManager.getMessage(ResourceManager.SAVE_AS_KEY);
200: DAVFileChooser.ChoiceStruct choice=chooseFile(oldParentNode,
201: title,
202: true,
203: oldFile.getFileName());
204: if (choice==null)
205: {
206: Debug.trace(this , Debug.DP3, "user cancelled save as");
207: return;
208: }
209: final DAVTreeNode parentNode=choice.getParentNode();
210: Assertion.assert((parentNode!=null), "parent node is not null");
211: final String newFileName=choice.getFilename();
212: if (newFileName==null)
213: {
214: Debug.trace(this , Debug.DP3, "user didn't select anything");
215: return;
216: }
217: final String newPath=choice.getFilePath();
218: successRunner=new Runnable()
219: {
220: public void run()
221: {
222: Debug.trace(this , Debug.DP3, "in runnable");
223: refreshNode(parentNode);
224: DAVFile parentFile=parentNode.getDAVFile();
225: //DAVFile's getChildNamed() method doesn't like a host name in the path
226: String pathWithoutHost=parentFile.getName()+newFileName;
227: final DAVFile newDAVFile=parentFile.getChildNamed(pathWithoutHost);
228: if (newDAVFile==null)
229: {
230: Debug.trace(this , Debug.DP1, "*** ERROR: DAVFile not found with path "+newPath);
231: return;
232: }
233: editor.setDAVFile(newDAVFile);
234: editor.setDirty(false);
235: editor.setResourceName(newDAVFile.getFullName());
236: editor.setName(newFileName);
237: Debug.trace(this , Debug.DP3,
238: "editor is {0}, its file is {1}, its dirtiness is {2}, its name is {3}",
239: new Object[] { editor, editor.getDAVFile(), new Boolean(editor.isDirty()),
240: editor.getName() });
241: //lock the new file for editing
242: Explorer.this .lock(parentNode, newDAVFile);
243: ExplorerApp.getViewForBuffer(editor).dock(editor);
244: }
245: };
246: //save new file
247: createFile(newPath, editor.getResourceBody(), successRunner);
248: //unlock old file
249: unlock(oldParentNode, oldFile);
250: break;
251: default:
252: Assertion.assert(false,
253: "this default case of the switch on editCode should not be reached");
254: }
255: }
256:
257: /* END OF EditListener IMPLEMENTATION */
258:
259:
260: private void initComponents()
261: {
262: //root node is not displayed.
263: rootNode=new DefaultMutableTreeNode("root");
264: treeModel=new DAVTreeModel(rootNode);
265: treeModel.addTreeModelListener(new DAVTreeModelListener(this ));
266: tree=new JTree(treeModel);
267:
268: //setting largeModel to be true produces a noticeable performance enhancement (Metal L&F, IBM Linux 1.3)
269: tree.setLargeModel(true);
270:
271: //in order to enable tooltips, use custom renderer
272: tree.setCellRenderer(new DAVTreeCellRenderer());
273: //tree must be registered with ToolTipManager for this to work
274: ToolTipManager.sharedInstance().registerComponent(tree);
275: tree.setRootVisible(false);
276: tree.setShowsRootHandles(true);
277:
278: tableModel=new DAVTableModel(tableHeaders);
279:
280: /*
281: DAVTreeSelectionListener needs a references to the table model in order in for the
282: table to respond to tree events
283: */
284: tree.addTreeSelectionListener(new DAVTreeSelectionListener(treeModel, tableModel));
285:
286: table=new JTable(tableModel);
287: addTableColumns();
288:
289: table.setShowVerticalLines(getShowHorizontalLines());
290: table.setShowHorizontalLines(getShowHorizontalLines());
291: TableMouser mouseCatcher=new TableMouser(this );
292: table.addMouseListener(mouseCatcher);
293: table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
294: table.setDefaultRenderer(Lock.class, new LockRenderer());
295: table.getTableHeader().setReorderingAllowed(false);
296:
297: JScrollPane treePane=new JScrollPane(tree,
298: JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
299: JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
300: //ensure that the tree gets enough room initially in the splitpane
301: Dimension treeD=tree.getPreferredSize();
302: treeD.width=Math.max(treeD.width, 200);
303: treePane.setPreferredSize(treeD);
304:
305: JScrollPane tablePane=new JScrollPane(table);
306: tablePane.addMouseListener(mouseCatcher);
307: JSplitPane splitPane=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
308: treePane,
309: tablePane);
310: splitPane.setPreferredSize(new Dimension(800, 600));
311: setLayout(new BorderLayout());
312: add(splitPane, BorderLayout.CENTER);
313: }
314:
315: private void addTableColumns()
316: {
317: table.createDefaultColumnsFromModel();
318: //cheesy, despicable, doomed.
319: int doneCanAbort=0;
320: for (Enumeration enum=table.getColumnModel().getColumns();enum.hasMoreElements();)
321: {
322: TableColumn tc=(TableColumn) enum.nextElement();
323: Object identifier = tc.getIdentifier();
324: if (identifier.equals(DAVTableHeader.LOCK.toString()))
325: {
326: setColumnForIcon(tc, ResourceManager.getImageIcon(ResourceManager.LOCK_ICON, null));
327: doneCanAbort++;
328: }
329: else if (identifier.equals(DAVTableHeader.CONTENT_LENGTH.toString()))
330: {
331: tc.setPreferredWidth(40);
332: doneCanAbort++;
333: }
334: else if (identifier.equals(DAVTableHeader.RESOURCETYPE.toString()))
335: {
336: setColumnForIcon(tc, ResourceManager.getImageIcon(ResourceManager.FOLDER_ICON, null));
337: tc.setCellRenderer(new ResourceTypeRenderer());
338: doneCanAbort++;
339: }
340: if (doneCanAbort==3) return;
341: }
342: }
343:
344: private void setColumnForIcon(TableColumn tc, ImageIcon ii)
345: {
346: int width=ii.getIconWidth();
347: tc.setMaxWidth(width);
348: tc.setPreferredWidth(width);
349: tc.setMinWidth(width);
350: tc.setResizable(false);
351: tc.setHeaderValue("");
352: }
353:
354: /**
355: * @return array of table headers
356: */
357: public DAVTableHeader[] getTableHeaders()
358: {
359: return this .tableHeaders;
360: }
361:
362: public void setTableHeaders(DAVTableHeader[] tableHeaders)
363: {
364: this .tableHeaders=tableHeaders;
365: /*
366: * it is simpler to use side-effects in the mutators of
367: * configurable properties rather than PropertyChangeEvents.
368: * These properties only exist so they can be configured
369: */
370: tableModel.setTableHeaders(tableHeaders);
371: addTableColumns();
372: }
373:
374: public boolean getShowVerticalLines()
375: {
376: return this .showTableVerticalLines;
377: }
378:
379: public void setShowVerticalLines(boolean showVerticalLines)
380: {
381: this .showTableVerticalLines=showVerticalLines;
382: table.setShowVerticalLines(showVerticalLines);
383: }
384:
385: public boolean getShowHorizontalLines()
386: {
387: return this .showTableHorizontalLines;
388: }
389:
390: public void setShowHorizontalLines(boolean showHorizontalLines)
391: {
392: this .showTableHorizontalLines=showHorizontalLines;
393: table.setShowHorizontalLines(showHorizontalLines);
394: }
395:
396: /**
397: * tries to connect to the server <code>sd</code> and
398: * displays a corresponding tree node in the explorer.
399: * If the attempt succeeded, the <code>Runnable</code> <code>postRunner</code>
400: * will then be executed.
401: * @param sd the <code>ServerData</code> representing the target server
402: * @param postRunner the <code>Runnable</a> to be executed upon success
403: */
404: public void addConnectionNode(ServerData sd, Runnable postRunner)
405: {
406: selectNode(treeModel.addConnectionNode(sd, postRunner));
407:
408: }
409:
410: public void removeConnectionNode(String host, int port, String initialPath)
411: {
412: treeModel.removeConnectionNode(host, port, initialPath);
413: tree.clearSelection();
414: }
415:
416: public void removeConnectionNode(ServerData sd)
417: {
418: treeModel.removeConnectionNode(sd);
419: tree.clearSelection();
420: }
421:
422: public int getConnectedServerCount()
423: {
424: return treeModel.getChildCount(rootNode);
425: }
426:
427: public ServerData[] getConnectedServers()
428: {
429: int numServers=getConnectedServerCount();
430: ServerData[] servers=new ServerData[numServers];
431: for (int i=0;i< getConnectedServerCount();i++)
432: {
433: Object nodeObj=treeModel.getChild(rootNode, i);
434: if (nodeObj instanceof DAVTreeNode)
435: servers[i]=ServerData.getServer(nodeObj.toString());
436: }
437: return servers;
438: }
439:
440: public boolean isConnected(ServerData sd)
441: {
442: ServerData[] servers=getConnectedServers();
443: for (int i=0;i<servers.length;i++)
444: {
445: if (servers[i].equals(sd))
446: return true;
447: }
448: return false;
449: }
450:
451: public byte[] get(DAVFile file)
452: {
453: return treeModel.get(file);
454: }
455:
456: public void delete(DAVTreeNode parentNode, String fileName)
457: {
458: treeModel.delete(parentNode, fileName);
459: selectNode(parentNode);
460: }
461:
462: public void lock(DAVTreeNode parentNode, DAVFile file)
463: {
464: lock(parentNode, file, null);
465: }
466:
467: public void lock(DAVTreeNode parentNode, DAVFile file, Runnable runnable)
468: {
469: ServerData sd=getConnection(parentNode);
470: Assertion.assert((sd!=null), "node {0} has non-null ServerData",
471: new Object[] {parentNode});
472: String owner=sd.getOwner();
473: if (owner==null)
474: {
475: owner=promptForLockOwner(sd);
476: if (owner==null)
477: return;
478: }
479: treeModel.lock(parentNode, file, owner, runnable);
480: selectNode(parentNode);
481: }
482:
483: private String promptForLockOwner(ServerData sd)
484: {
485: String owner;
486: String message=ResourceManager.getMessage(ResourceManager.LOCK_OWNER_PROMPT,
487: new Object[] {sd.getHost()});
488: String title=ResourceManager.getMessage(ResourceManager.LOCK_OWNER_DIALOG_TITLE);
489: while (true)
490: {
491: Object result=JOptionPane.showInputDialog(this ,
492: message,
493: title,
494: JOptionPane.QUESTION_MESSAGE,
495: null,
496: null,
497: sd.getUsername());
498: if (result==null)
499: return null;
500: else
501: {
502: owner=result.toString().trim();
503: if (owner.equals(""))
504: continue;
505: else break;
506: }
507: }
508: sd.setOwner(owner);
509: try
510: {
511: ServerData.saveServers();
512: }
513: catch (IOException oyVeh)
514: {
515: Debug.trace(this , Debug.DP1, oyVeh);
516: }
517: return owner;
518: }
519:
520: public void unlock(DAVTreeNode parentNode, DAVFile file)
521: {
522: treeModel.unlock(parentNode, file);
523: selectNode(parentNode);
524: }
525:
526: public void stealLock(DAVTreeNode parentNode, DAVFile file)
527: {
528: ServerData sd=getConnection(parentNode);
529: Assertion.assert((sd!=null), "node {0} has non-null ServerData",
530: new Object[] {parentNode});
531: String owner=sd.getOwner();
532: if (owner==null)
533: owner=promptForLockOwner(sd);
534: if (owner==null)
535: return;
536: treeModel.stealLock(parentNode, file, owner);
537: selectNode(parentNode);
538: }
539:
540: public void proppatch(DAVTreeNode parentNode, DAVFile file, Map propertyValueMap)
541: {
542: treeModel.proppatch(parentNode, file, propertyValueMap);
543: }
544:
545: public void copy(DAVTreeNode parentNode, DAVFile file, String destinationURL)
546: {
547: treeModel.copy(parentNode, file, destinationURL);
548: int lastDex=destinationURL.lastIndexOf(DAVConstants.DAV_FILE_SEPARATOR)+1;
549: selectNode(treeModel.getNodeMatchingURL(destinationURL.substring(0, lastDex)));
550: }
551:
552: public void move(DAVTreeNode parentNode, DAVFile file, String destinationURL)
553: {
554: treeModel.move(parentNode, file, destinationURL);
555: int lastDex=destinationURL.lastIndexOf(DAVConstants.DAV_FILE_SEPARATOR)+1;
556: selectNode(treeModel.getNodeMatchingURL(destinationURL.substring(0, lastDex)));
557: }
558:
559: public ServerData getConnection(DAVTreeNode node)
560: {
561: Debug.trace(this , Debug.DP3, "node for getConnection() is {0}",
562: new Object[] {node} );
563: Object[] path=treeModel.getPathToRoot(node);
564: return _getConnection(path);
565: }
566:
567: private ServerData _getConnection(Object[] path)
568: {
569: if (path==null) return null;
570: if (path.length>1) //first element in path is root
571: {
572: Object serverNodeObj=path[1];
573: if (serverNodeObj instanceof DAVTreeNode)
574: {
575: DAVTreeNode serverNode=(DAVTreeNode) serverNodeObj;
576: ServerData foundSD=ServerData.getServer(serverNode.toString());
577: Debug.trace(this , Debug.DP3, "ServerData found is "+foundSD);
578: return foundSD;
579: }
580: }
581: Debug.trace(this , Debug.DP3, "returning null from _getConnection");
582: return null;
583: }
584:
585: public ServerData getSelectedConnection()
586: {
587: TreePath teepee=tree.getSelectionPath();
588: Debug.trace(this , Debug.DP3, "selected TreePath is "+teepee);
589: if (teepee!=null)
590: {
591: Object[] path=teepee.getPath();
592: if (Debug.isDebug(this , Debug.DP4))
593: {
594: StringBuffer sb=new StringBuffer("path returned by treepath:\n");
595: for (int i=0;i<path.length;i++)
596: sb.append("\t").append(path[i]).append("\n");
597: Debug.trace(this , Debug.DP3, sb.toString());
598: }
599: return _getConnection(path);
600: }
601: Debug.trace(this , Debug.DP3, "returning null from getSelectedConnection()");
602: return null;
603: }
604:
605: public void selectLastNode()
606: {
607: TreePath path=null;
608: if (rootNode.getChildCount()>0)
609: {
610: path=new TreePath(((DefaultMutableTreeNode)rootNode.getLastChild()).getPath());
611: }
612: else
613: {
614: path=new TreePath(rootNode.getPath());
615: }
616: Debug.trace(this , Debug.DP3, "selecting path "+path);
617: tree.setSelectionPath(path);
618: }
619:
620: public void selectNode(DAVTreeNode node)
621: {
622: Debug.trace(this , Debug.DP3, "in selectNode with node " + node);
623: if (node!=null)
624: tree.setSelectionPath(new TreePath(treeModel.getPathToRoot(node)));
625: }
626:
627: public void displayCollection(String filename)
628: {
629: DAVTreeNode parentNode=getSelectedNode();
630: if (parentNode!=null)
631: displayCollection(parentNode, filename);
632: }
633:
634:
635: /**
636: * displays a given collection in the explorer.
637: * @param parentNode the node of the containing collection
638: * @param filename the name of the collection resource to display
639: */
640: public void displayCollection(DAVTreeNode parentNode, String filename)
641: {
642: DAVTreeNode childNode=getChildNode(parentNode, filename);
643: if (childNode==null)
644: {
645: Debug.trace(this , Debug.DP2,
646: "filename {0} not found under node {1}",
647: new Object[] {filename, parentNode});
648: return;
649: }
650: TreeNode[] nodeArray=treeModel.getPathToRoot(childNode);
651: if (Debug.isDebug(this , Debug.DP5))
652: {
653: StringBuffer sb=new StringBuffer("path returned by model for node ")
654: .append(childNode)
655: .append(":\n");
656: for (int i=0;i<nodeArray.length;i++)
657: sb.append("\t")
658: .append(nodeArray[i])
659: .append("\n");
660: Debug.trace(this , Debug.DP5, sb.toString());
661: }
662: TreePath newPath=new TreePath(nodeArray);
663: tree.makeVisible(newPath);
664: tree.scrollPathToVisible(newPath);
665: tree.setSelectionPath(newPath);
666: }
667:
668: protected DAVTreeNode getChildNode(DAVTreeNode parentNode, String filename)
669: {
670: for (Enumeration enum=parentNode.children();enum.hasMoreElements();)
671: {
672: Object nextObj=enum.nextElement();
673: Assertion.assert((nextObj instanceof DAVTreeNode),
674: nextObj + " is a DAVTreeNode");
675: DAVTreeNode childNode=(DAVTreeNode) nextObj;
676: DAVFile file=childNode.getDAVFile();
677: if (file!=null
678: && file.isCollection()
679: && filename.equals(file.getFileName()))
680: {
681: return childNode;
682: }
683: }
684: return null;
685: }
686:
687: public DAVTreeNode getNodeForFile(DAVFile file)
688: {
689: String fullPath=file.getFullName();
690: String directoryPath=(file.isCollection())
691: ? fullPath
692: : fullPath.substring(0, fullPath.lastIndexOf(DAVConstants.DAV_FILE_SEPARATOR));
693: Debug.trace(this , Debug.DP3, "directory path: "+ directoryPath);
694: DAVTreeNode node=treeModel.getNodeMatchingPath(directoryPath);
695: Debug.trace(this , Debug.DP3, "returning node "+node);
696: return node;
697: }
698:
699: public void createCollection(DAVTreeNode parentNode, String collectionName)
700: {
701: treeModel.mkcol(parentNode, collectionName);
702: selectNode(parentNode);
703: }
704:
705: public void createFile(String fullPath, byte[] bodyBytes)
706: {
707: createFile(fullPath, bodyBytes, null);
708: }
709:
710: public void createFile(String fullPath, byte[] bodyBytes, Runnable successRunner)
711: {
712: int lastSep=fullPath.lastIndexOf(DAVConstants.DAV_FILE_SEPARATOR);
713: String directoryPath=fullPath.substring(0, lastSep);
714: String filename=fullPath.substring(lastSep+1);
715: DAVTreeNode node=treeModel.getNodeMatchingPath(directoryPath);
716: if (node!=null)
717: {
718: createFile(node, filename, bodyBytes, successRunner);
719: }
720: else
721: {
722: Debug.trace(this , Debug.DP2,
723: "no node found for path {0}",
724: new Object[] {fullPath});
725: }
726: }
727:
728: public void createFile(DAVTreeNode parentNode, String fileName)
729: {
730: createFile(parentNode, fileName, new byte[0], null);
731: }
732:
733: public void createFile(DAVTreeNode parentNode, String fileName, Runnable successRunner)
734: {
735: createFile(parentNode, fileName, new byte[0], successRunner);
736: }
737:
738: public void createFile(DAVTreeNode parentNode, String fileName, byte[] bodyBytes)
739: {
740: createFile(parentNode, fileName, bodyBytes, null);
741: }
742:
743: public void createFile(DAVTreeNode parentNode, String fileName, byte[] bodyBytes, Runnable successRunner)
744: {
745: treeModel.put(parentNode, fileName, bodyBytes, successRunner);
746: selectNode(parentNode);
747: }
748:
749: protected void setTableFile(DAVFile file)
750: {
751: tableModel.setDAVFile(file);
752: table.clearSelection();
753: }
754:
755: public DAVFile getCurrentFile()
756: {
757: if (table.getSelectedRow()!=-1)
758: return getSelectedTableFile();
759: DAVTreeNode node=getSelectedNode();
760: if (node==null) return null;
761: else return node.getDAVFile();
762: }
763:
764: public DAVFile getSelectedTableFile()
765: {
766: return tableModel.getDAVFile(table.getSelectedRow());
767: }
768:
769: public DAVFile getFile(DAVTreeNode parentNode, String filename)
770: {
771: for (Iterator it=parentNode.getDAVFile().children();it.hasNext();)
772: {
773: DAVFile kidFile=(DAVFile)it.next();
774: if (kidFile.getFileName().equals(filename))
775: return kidFile;
776: }
777: return null;
778: }
779:
780: public DAVTreeNode getSelectedNode()
781: {
782: TreePath currentPath=tree.getSelectionPath();
783: if (currentPath==null) return null;
784: Object lastObj=currentPath.getLastPathComponent();
785: Debug.trace(this , Debug.DP3, "current node is {0}", new Object[] {lastObj});
786: return (lastObj instanceof DAVTreeNode) ? (DAVTreeNode) lastObj : null;
787: }
788:
789: public void refreshNode(DAVTreeNode node)
790: {
791: Assertion.assert((node!=null), "node does not equal null");
792: treeModel.refreshNode(node);
793: if (node.equals(getSelectedNode()))
794: setTableFile(node.getDAVFile());
795: }
796:
797: public void refreshNode(DAVTreeNode node, boolean useAllprop)
798: {
799: Assertion.assert((node!=null), "node does not equal null");
800: treeModel.refreshNode(node, useAllprop);
801: if (node.equals(getSelectedNode()))
802: setTableFile(node.getDAVFile());
803: }
804:
805: /**
806: * utility method for showing a DAVFileChooser
807: * @param node a node on the DAVServer where the user may choose a file
808: * @param title the title of the choice dialog
809: * @param editable whether the user may freely enter a new filename
810: * @param initialFileName the initial contents of the filename entry field
811: * @return a struct of information about the chosen file, or null
812: *
813: */
814: public DAVFileChooser.ChoiceStruct chooseFile(DAVTreeNode node,
815: String title,
816: boolean editable,
817: String initialFileName)
818: {
819: DAVFileChooser chooser=(node==null)
820: ? getDAVFileChooser()
821: : getDAVFileChooser(node);
822: chooser.setSelectionMode(TreeNodeChooser.SelectionMode.LEAF_ONLY);
823: if (initialFileName!=null)
824: {
825: chooser.setEntryFieldText(initialFileName);
826: chooser.setEntryFieldTextSticky(true);
827: }
828: chooser.setEntryFieldEditable(editable);
829:
830: //configure the chooser's labels -- TO BE DONE
831:
832: //I should use a JDialog and roll my own,
833: //probably in the TreeNodeChooser class (an instance showDialog() method)
834: int option=JOptionPane.showConfirmDialog(this ,
835: chooser,
836: title,
837: JOptionPane.OK_CANCEL_OPTION,
838: JOptionPane.QUESTION_MESSAGE,
839: new ImageIcon());
840: if (option!=JOptionPane.OK_OPTION)
841: {
842: Debug.trace(this , Debug.DP3, "user cancelled ");
843: return null;
844: }
845: DAVFileChooser.ChoiceStruct struct=chooser.getChoiceStruct();
846: Object[] retStruct=new Object[4];
847: Object lastPathComponent=chooser.getSelectedPath().getLastPathComponent();
848: DAVTreeNode parentNode=struct.getParentNode();
849: //replace the parent node in the struct with the corresponding node in the explorer's tree model
850: struct.setParentNode(treeModel.getNodeMatchingPath(parentNode.getDAVFile().getFullName()));
851: return struct;
852: }
853:
854: public DAVFileChooser getDAVFileChooser(ServerData[] serversToConnect)
855: {
856: final DefaultMutableTreeNode chooserRoot=new DefaultMutableTreeNode("chooser");
857: final DAVTreeModel chooserModel=new DAVTreeModel(chooserRoot, true);
858: final int numServers=serversToConnect.length;
859: for (int i=0;i<numServers;i++)
860: {
861: chooserModel.addConnectionNode(serversToConnect[i], true, null);
862: }
863:
864: DAVFileChooser chooser=new DAVFileChooser(chooserModel);
865: Object firstChild=chooserModel.getChild(chooserRoot, 0);
866: chooser.setCurrentPath(new TreePath(chooserModel.getPathToRoot((TreeNode)firstChild)));
867: return chooser;
868: }
869:
870: public DAVFileChooser getDAVFileChooser()
871: {
872: return getDAVFileChooser(getConnectedServers());
873: }
874:
875: public DAVFileChooser getDAVFileChooser(DAVTreeNode node)
876: {
877: ServerData sd=getConnection(node);
878: DAVFileChooser chooser=getDAVFileChooser(new ServerData[] {sd});
879: // the below doesn't work, yet -- setCurrentPath won't take you in one hop
880: // to any depth in the tree -- you need to walk the tree path.
881: // to fix this, I will wait for the MAJOR FIX I intend to make to the way
882: // tree models are handled!!
883:// DAVFile file=node.getDAVFile();
884:// if (file!=null)
885:// {
886:// DAVTreeModel model = (DAVTreeModel) chooser.getModel();
887:// DAVTreeNode chooserNode=model.getNodeMatchingPath(file.getFullName());
888:// if (chooserNode!=null)
889:// {
890:// TreePath newPath=new TreePath(model.getPathToRoot(chooserNode));
891:// chooser.setCurrentPath(newPath);
892:// }
893:// }
894: return chooser;
895: }
896:
897: public void addTableModelListener(TableModelListener tml)
898: {
899: tableModel.addTableModelListener(tml);
900: }
901:
902:
903: public void removeTableModelListener(TableModelListener tml)
904: {
905: tableModel.removeTableModelListener(tml);
906: }
907:
908: public void addTreeModelListener(TreeModelListener tml)
909: {
910: treeModel.addTreeModelListener(tml);
911: }
912:
913: public void removeTreeModelListener(TreeModelListener tml)
914: {
915: treeModel.removeTreeModelListener(tml);
916: }
917:
918: protected void finalize() throws Throwable
919: {
920: allExplorers.remove(this );
921: }
922:}
923:
924:/* $Log: Explorer.java,v $
925:/* Revision 1.41 2001/06/13 01:09:03 smulloni
926:/* Some improvements to the network customizer (which is still buggy).
927:/* Also improvements for using the doAllprop switch, and for the layout of
928:/* the PropertiesDialog.
929:/*
930:/* Revision 1.40 2001/06/05 01:09:53 smulloni
931:/* fixed bug wtih failed connection attempts, which used to set the
932:/* connection flag as if the connection had succeeded.
933:/*
934:/* Revision 1.39 2001/05/30 15:25:28 smulloni
935:/* Added prompt for lock owner the first time a resource is locked for a
936:/* given server -- default value is username, if any.
937:/*
938:/* Revision 1.38 2001/01/03 20:11:31 smulloni
939:/* the DAVFileChooser now replaces JFileChooser for remote file access.
940:/* DAVMethod now has a protocol property.
941:/*
942:/* Revision 1.37 2001/01/03 00:30:35 smulloni
943:/* a number of modifications along the way to replacing JFileChooser with
944:/* something more suitable for remote (virtual) files.
945:/*
946:/* Revision 1.36 2000/12/21 18:53:13 smulloni
947:/* cosmetic improvements.
948:/*
949:/* Revision 1.35 2000/12/19 22:36:05 smulloni
950:/* adjustments to preamble.
951:/*
952:/* Revision 1.34 2000/12/07 00:01:34 smulloni
953:/* adding an additional editor, still hard-coded into the DAVEditorFactory.
954:/*
955:/* Revision 1.33 2000/12/03 23:53:26 smulloni
956:/* added license and copyright preamble to java files.
957:/*
958:/* Revision 1.32 2000/12/01 16:25:51 smullyan
959:/* improvements to look and feel; fixed NPE in DAVFile; new actions for text
960:/* editor
961:/*
962:/* Revision 1.31 2000/11/28 19:36:19 smullyan
963:/* some bug fixes; notes.
964:/*
965:/* Revision 1.30 2000/11/28 00:01:37 smullyan
966:/* added a status bar/minibuffer, with a location field showing the current line and
967:/* column number (for the SimpleTextEditor and kin only).
968:/*
969:/* Revision 1.29 2000/11/22 00:11:26 smullyan
970:/* editor now locks and unlocks, more or less appropriately.
971:/*
972:/* Revision 1.28 2000/11/20 23:30:20 smullyan
973:/* more editor integration work.
974:/*
975:/* Revision 1.27 2000/11/18 04:36:03 smullyan
976:/* work on StateMonitor and related functionality.
977:/*
978:/* Revision 1.26 2000/11/17 20:25:05 smullyan
979:/* new SaveAction; a StateMonitor being added to handle application state.
980:/*
981:/* Revision 1.25 2000/11/15 20:17:02 smullyan
982:/* added a Buffer interface, which is a wrapper around a displayable component.
983:/*
984:/* Revision 1.24 2000/11/14 17:13:34 smullyan
985:/* Added TreeModelListener hooks into Explorer, and revised PropertiesDialog to
986:/* use it.
987:/*
988:/* Revision 1.23 2000/11/13 23:28:30 smullyan
989:/* first pass at a gui for proppatch, added to the propertiese dialog. Highly
990:/* problematic still, needs substantial work.
991:/*
992:/* Revision 1.22 2000/11/10 22:40:06 smullyan
993:/* added icon to table for resource type; fixes to copy and move; disabling of
994:/* menu items that are inappropriate.
995:/*
996:/* Revision 1.21 2000/11/09 23:34:56 smullyan
997:/* log added to every Java file, with the help of python. Lock stealing
998:/* implemented, and treatment of locks made more robust.
999:/* */
|