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.Frame;
028:import java.awt.GridBagConstraints;
029:import java.awt.GridBagLayout;
030:import java.awt.Insets;
031:import java.awt.event.ActionEvent;
032:import java.awt.event.ActionListener;
033:import java.io.IOException;
034:import java.lang.reflect.Method;
035:import java.util.ArrayList;
036:import java.util.Enumeration;
037:import java.util.HashMap;
038:import java.util.Iterator;
039:import java.util.Map;
040:import java.util.TreeMap;
041:import javax.swing.Box;
042:import javax.swing.JButton;
043:import javax.swing.JComponent;
044:import javax.swing.JDialog;
045:import javax.swing.JLabel;
046:import javax.swing.JOptionPane;
047:import javax.swing.JPanel;
048:import javax.swing.JScrollPane;
049:import javax.swing.JTabbedPane;
050:import javax.swing.JTable;
051:import javax.swing.JTextField;
052:import javax.swing.ListSelectionModel;
053:import javax.swing.event.ListSelectionEvent;
054:import javax.swing.event.ListSelectionListener;
055:import javax.swing.event.TreeModelEvent;
056:import javax.swing.event.TreeModelListener;
057:import javax.swing.table.AbstractTableModel;
058:import javax.swing.table.TableColumn;
059:import javax.swing.tree.TreeNode;
060:import org.skunk.assert.Assertion;
061:import org.skunk.dav.client.DAVConnection;
062:import org.skunk.dav.client.DAVException;
063:import org.skunk.dav.client.DAVFile;
064:import org.skunk.dav.client.DAVProperty;
065:import org.skunk.dav.client.Depth;
066:import org.skunk.dav.client.method.PropFindMethod;
067:import org.skunk.trace.Debug;
068:
069:public class PropertiesDialog extends JDialog
070:{
071: private DAVFile file;
072: private DAVTreeNode node;
073: private Explorer ex;
074: private DAVPropertiesTableModel davModel;
075: private CustomPropertiesTableModel customModel;
076:
077: private String[] headers=
078: {
079: ResourceManager.getMessage(ResourceManager.NAME),
080: ResourceManager.getMessage(ResourceManager.NAMESPACE),
081: ResourceManager.getMessage(ResourceManager.VALUE)
082: };
083:
084: public PropertiesDialog(Frame owner, Explorer ex, DAVFile file)
085: {
086: super (owner, false); //does not need to be modal
087: if (file==null)
088: throw new IllegalArgumentException("file must be non-null");
089: this .file=file;
090: this .ex=ex;
091: this .node=ex.getSelectedNode();
092: if (node.getDAVFile().getName().equals(file.getName()))
093: {
094: TreeNode pops=node.getParent();
095: if (pops!=null && pops instanceof DAVTreeNode)
096: {
097: node=(DAVTreeNode)pops;
098: }
099: else
100: {
101: Debug.trace(this , Debug.DP2, "OOPS -- node not a DAVTreeNode");
102: }
103: }
104: refreshIfNeeded();
105: ex.addTreeModelListener(new ExplorerListener());
106: initComponents();
107: }
108:
109: protected void setDAVFile(DAVFile file)
110: {
111: this .file=file;
112: if (davModel!=null)
113: davModel.setDAVFile(file);
114: if (customModel!=null)
115: customModel.setDAVFile(file);
116: }
117:
118: private void refreshIfNeeded()
119: {
120: if (! DAVTreeModel.usesAllprop())
121: {
122: DAVFile newFile=null;
123: String resource=file.getName();
124: PropFindMethod method=new PropFindMethod(resource, Depth.ZERO, false);
125: DAVConnection conn=file.getDAVConnection();
126: try
127: {
128: conn.execute(method);
129: newFile=method.getDAVFile();
130: }
131: catch (DAVException davex)
132: {
133: Debug.trace(this , Debug.DP2, davex);
134: }
135: catch (IOException oyVeh)
136: {
137: Debug.trace(this , Debug.DP2, oyVeh);
138: }
139: if (newFile!=null)
140: {
141: DAVProperty[] props=newFile.getAvailableProperties();
142: Assertion.assert(props!=null,
143: "available properties are not null");
144: method=new PropFindMethod(resource, Depth.ZERO, props);
145: try
146: {
147: conn.execute(method);
148: newFile=method.getDAVFile();
149: }
150: catch (DAVException davex)
151: {
152: Debug.trace(this , Debug.DP2, davex);
153: }
154: catch (IOException oyVeh)
155: {
156: Debug.trace(this , Debug.DP2, oyVeh);
157: }
158: }
159: Assertion.assert(newFile!=null, "new file is not null");
160: Debug.trace(this , Debug.DP3, newFile.toVerboseString());
161: setDAVFile(newFile);
162: }
163: }
164:
165: private void initComponents()
166: {
167: setTitle(ResourceManager.getMessage(ResourceManager.PROPERTIES_DIALOG_TITLE,
168: new Object[] {file.getFileName()}));
169: JTabbedPane tabby=new JTabbedPane(JTabbedPane.TOP);
170: tabby.add(getDAVPropertiesTab(),
171: ResourceManager.getMessage(ResourceManager.DAV_PROPERTIES_TAB_TITLE));
172: tabby.add(getCustomPropertiesTab(),
173: ResourceManager.getMessage(ResourceManager.CUSTOM_PROPERTIES_TAB_TITLE));
174: JPanel contentPanel=new JPanel();
175: contentPanel.setLayout(new BorderLayout());
176: contentPanel.add(tabby, BorderLayout.CENTER);
177:
178: /*
179: CONSIDER ADDING A DIALOG DISMISSAL BUTTON HERE
180: contentPanel.add(getButtonBox(), BorderLayout.SOUTH);
181: */
182: setContentPane(contentPanel);
183: pack();
184: }
185:
186: private void initTableColumns(JTable table)
187: {
188: for (Enumeration enum=table.getColumnModel().getColumns();
189: enum.hasMoreElements();)
190: {
191: TableColumn tc=(TableColumn) enum.nextElement();
192: Object identifier = tc.getIdentifier();
193: if (identifier.equals(headers[0])) //name
194: {
195: tc.setPreferredWidth(110);
196: }
197: else if (identifier.equals(headers[1])) //namespace
198: {
199: tc.setPreferredWidth(75);
200: }
201: else if (identifier.equals(headers[2])) //value
202: {
203: tc.setPreferredWidth(180);
204: }
205: }
206: }
207:
208: private JComponent getDAVPropertiesTab()
209: {
210: davModel=new DAVPropertiesTableModel(file);
211: JTable table=new JTable(davModel);
212: table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
213: initTableColumns(table);
214: JScrollPane jsp= new JScrollPane(table);
215: jsp.setPreferredSize(new Dimension(350, 330));
216: return jsp;
217: }
218:
219: private JComponent getCustomPropertiesTab()
220: {
221: customModel=new CustomPropertiesTableModel(file);
222: final JTable table=new JTable(customModel);
223: initTableColumns(table);
224: table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
225: table.clearSelection();
226: table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
227: JScrollPane jsp= new JScrollPane(table);
228: jsp.setPreferredSize(new Dimension(250, 350));
229: final JButton addCustomButton=new JButton(ResourceManager.getMessage(ResourceManager.ADD_KEY));
230: addCustomButton.addActionListener(new AddCustomAction());
231: final JButton editCustomButton=new JButton(ResourceManager.getMessage(ResourceManager.EDIT_KEY));
232: editCustomButton.addActionListener(new EditCustomAction(table));
233: editCustomButton.setEnabled(false);
234: final JButton deleteCustomButton=new JButton(ResourceManager.getMessage(ResourceManager.DELETE_KEY));
235: deleteCustomButton.addActionListener(new DeleteCustomAction(table));
236: deleteCustomButton.setEnabled(false);
237: table.getSelectionModel().addListSelectionListener(new ListSelectionListener()
238: {
239: public void valueChanged(ListSelectionEvent lassie)
240: {
241: boolean enableEm=table.getSelectedRowCount()==1;
242: deleteCustomButton.setEnabled(enableEm);
243: editCustomButton.setEnabled(enableEm);
244: }
245: });
246:
247: Box buttonBox = Box.createHorizontalBox();
248: buttonBox.add(Box.createHorizontalGlue());
249: buttonBox.add(addCustomButton);
250: buttonBox.add(Box.createHorizontalGlue());
251: buttonBox.add(editCustomButton);
252: buttonBox.add(Box.createHorizontalGlue());
253: buttonBox.add(deleteCustomButton);
254: buttonBox.add(Box.createHorizontalGlue());
255:
256: JPanel wholeTab=new JPanel(new BorderLayout());
257: wholeTab.add(jsp, BorderLayout.CENTER);
258: wholeTab.add(buttonBox, BorderLayout.SOUTH);
259: return wholeTab;
260: }
261:
262: private class ExplorerListener implements TreeModelListener
263: {
264: public void treeNodesChanged(TreeModelEvent tme)
265: {
266: Debug.trace(this , Debug.DP3, "in treeNodesChanged");
267: _process();
268: }
269:
270: public void treeNodesInserted(TreeModelEvent tme) {}
271:
272: public void treeNodesRemoved(TreeModelEvent tme) {}
273:
274: public void treeStructureChanged(TreeModelEvent tme)
275: {
276: Debug.trace(this , Debug.DP3, "in treeStructureChanged");
277: _process();
278: }
279:
280: public void _process()
281: {
282: String filename=file.getFileName();
283: DAVFile newFile=ex.getFile(node, filename);
284: if (newFile!=null) setDAVFile(newFile);
285: refreshIfNeeded();
286: }
287: }
288:
289:
290: private class AddCustomAction implements ActionListener
291: {
292: public void actionPerformed(ActionEvent ae)
293: {
294: PropertyEditPanel propPanel=new PropertyEditPanel();
295: int option=propPanel.showAddDialog();
296: if (option==JOptionPane.OK_OPTION)
297: {
298: String name=propPanel.getPropertyName();
299: String namespace=propPanel.getPropertyNamespace();
300: String value=propPanel.getPropertyValue();
301: if (name==null || namespace==null || value==null)
302: {
303: Debug.trace(this , Debug.DP3, "incomplete submission for action");
304: //should show an error message -- TO BE DONE
305: return;
306: }
307: //do a proppatch
308: Map m=new HashMap();
309: m.put(new DAVProperty(name,
310: "ns"+(int)Math.floor(111*Math.random()),
311: namespace),
312: value);
313: ex.proppatch(node, file, m);
314: refreshIfNeeded();
315: }
316: }
317: }
318:
319: private class EditCustomAction implements ActionListener
320: {
321: private JTable table;
322:
323: EditCustomAction(JTable table)
324: {
325: this .table=table;
326: }
327: public void actionPerformed(ActionEvent ae)
328: {
329: int selected=table.getSelectedRow();
330: if (selected==-1)
331: {
332: Debug.trace(this , Debug.DP3, "no row selected!");
333: return;
334: }
335:
336: String name=table.getValueAt(selected, 0).toString();
337: String namespace=table.getValueAt(selected, 1).toString();
338: String value=table.getValueAt(selected, 2).toString();
339: PropertyEditPanel propPanel=new PropertyEditPanel(name, namespace, value);
340: int option=propPanel.showEditDialog();
341: if (option==JOptionPane.OK_OPTION)
342: {
343: String newName=propPanel.getPropertyName();
344: String newNamespace=propPanel.getPropertyNamespace();
345: value=propPanel.getPropertyValue();
346: if (newName==null || newNamespace==null || value==null)
347: {
348: Debug.trace(this , Debug.DP3, "incomplete submission for action");
349: return;
350: }
351: Map m=new HashMap();
352: if ((!name.equals(newName)) || (!namespace.equals(newNamespace)))
353: {
354: //user has changed the name or namespace of the property; delete old version
355: m.put(new DAVProperty(name, "ns"+(int)Math.floor(111*Math.random()), namespace), null);
356: }
357: m.put(new DAVProperty(newName, "ns"+(int)Math.floor(111*Math.random()), newNamespace), value);
358: ex.proppatch(node, file, m);
359: refreshIfNeeded();
360: }
361: }
362: }
363:
364: private class DeleteCustomAction implements ActionListener
365: {
366: private JTable table;
367:
368: DeleteCustomAction(JTable table)
369: {
370: this .table=table;
371: }
372:
373: public void actionPerformed(ActionEvent ae)
374: {
375: int selected=table.getSelectedRow();
376: if (selected==-1)
377: {
378: Debug.trace(this , Debug.DP3, "no row selected!");
379: return;
380: }
381: String name=table.getValueAt(selected, 0).toString();
382: String namespace=table.getValueAt(selected, 1).toString();
383:
384: //do a proppatch
385: Map m=new HashMap();
386: m.put(new DAVProperty(name, "ns"+(int)Math.floor(111*Math.random()), namespace), null);
387: ex.proppatch(node, file, m);
388: refreshIfNeeded();
389:
390: }
391: }
392:
393: private class PropertyEditPanel extends JPanel
394: {
395: JTextField nameField, namespaceField, valueField;
396:
397: int showAddDialog()
398: {
399: String title=ResourceManager.getMessage(ResourceManager.PROPERTY_ADD_DIALOG_TITLE);
400: return JOptionPane.showConfirmDialog(PropertiesDialog.this ,
401: this ,
402: title,
403: JOptionPane.OK_CANCEL_OPTION,
404: JOptionPane.QUESTION_MESSAGE,
405: null);
406: }
407:
408: int showEditDialog()
409: {
410: String title=ResourceManager.getMessage(ResourceManager.PROPERTY_EDIT_DIALOG_TITLE);
411: return JOptionPane.showConfirmDialog(PropertiesDialog.this ,
412: (Object) this ,
413: title,
414: JOptionPane.OK_CANCEL_OPTION,
415: JOptionPane.QUESTION_MESSAGE,
416: null);
417: }
418:
419: public String getPropertyName()
420: {
421: return nameField.getText();
422: }
423:
424: public void setPropertyName(String name)
425: {
426: this .nameField.setText(name);
427: }
428:
429: public String getPropertyNamespace()
430: {
431: return namespaceField.getText();
432: }
433:
434: public void setPropertyNamespace(String namespace)
435: {
436: this .namespaceField.setText(namespace);
437: }
438:
439: public String getPropertyValue()
440: {
441: return valueField.getText();
442: }
443:
444: public void setPropertyValue(String value)
445: {
446: this .valueField.setText(value);
447: }
448:
449: protected PropertyEditPanel()
450: {
451: this (null, null, null);
452: }
453:
454: protected PropertyEditPanel(String name, String namespace, String value)
455: {
456: super (new BorderLayout());
457: this .add(getPropertyEditPanel(name, namespace, value), BorderLayout.CENTER);
458: }
459:
460: private JPanel getPropertyEditPanel(String propertyName,
461: String propertyNamespace,
462: String propertyValue)
463: {
464: JPanel propPanel=new JPanel(new GridBagLayout());
465: GridBagConstraints gbc=new GridBagConstraints();
466: gbc.gridx=0;
467: gbc.gridy=0;
468: gbc.fill=GridBagConstraints.NONE;
469: gbc.anchor=GridBagConstraints.NORTHWEST;
470: gbc.insets=new Insets(2, 2, 2, 2);
471: gbc.weightx=0.0;
472: gbc.weighty=0.0;
473: gbc.gridwidth=1;
474: gbc.gridheight=1;
475:
476: JLabel tempLabel=new JLabel(ResourceManager.getMessage(ResourceManager.PROPERTY_NAME));
477: propPanel.add(tempLabel, gbc);
478: gbc.gridx++;
479:
480: nameField=new JTextField(22);
481: if (propertyName!=null) nameField.setText(propertyName);
482: propPanel.add(nameField, gbc);
483: gbc.gridx=0;
484: gbc.gridy++;
485:
486: tempLabel=new JLabel(ResourceManager.getMessage(ResourceManager.PROPERTY_NAMESPACE));
487: propPanel.add(tempLabel, gbc);
488: gbc.gridx++;
489:
490: namespaceField=new JTextField(22);
491: if (propertyNamespace!=null) namespaceField.setText(propertyNamespace);
492: propPanel.add(namespaceField, gbc);
493: gbc.gridx=0;
494: gbc.gridy++;
495:
496: tempLabel=new JLabel(ResourceManager.getMessage(ResourceManager.PROPERTY_VALUE));
497: propPanel.add(tempLabel, gbc);
498: gbc.gridx++;
499:
500: valueField=new JTextField(22);
501: if (propertyValue!=null) valueField.setText(propertyValue);
502: propPanel.add(valueField, gbc);
503:
504: return propPanel;
505: }
506: }
507:
508: private class DAVPropertiesTableModel extends AbstractTableModel
509: {
510: /**
511: * data for the table -- two columns, property names and values
512: */
513: private Object[][] tableData=
514: {
515: { ResourceManager.getMessage(ResourceManager.HOST_FILE_PROP), "" },
516: { ResourceManager.getMessage(ResourceManager.PORT_FILE_PROP), "" },
517: { ResourceManager.getMessage(ResourceManager.FILE_NAME_FILE_PROP), "" },
518: { ResourceManager.getMessage(ResourceManager.CREATION_DATE_FILE_PROP), "" },
519: { ResourceManager.getMessage(ResourceManager.LAST_MODIFIED_FILE_PROP), "" },
520: { ResourceManager.getMessage(ResourceManager.CONTENT_TYPE_FILE_PROP), "" },
521: { ResourceManager.getMessage(ResourceManager.CONTENT_LENGTH_FILE_PROP), "" },
522: { ResourceManager.getMessage(ResourceManager.CONTENT_LANGUAGE_FILE_PROP), "" },
523: { ResourceManager.getMessage(ResourceManager.DISPLAY_NAME_FILE_PROP), "" },
524: { ResourceManager.getMessage(ResourceManager.RESOURCE_TYPE_FILE_PROP), "" },
525: { ResourceManager.getMessage(ResourceManager.ETAG_FILE_PROP), "" },
526: { ResourceManager.getMessage(ResourceManager.SUPPORTED_LOCKS_FILE_PROP), "" },
527: { ResourceManager.getMessage(ResourceManager.ACTIVE_LOCKS_FILE_PROP), "" },
528: { ResourceManager.getMessage(ResourceManager.LINKS_FILE_PROP), "" }
529: };
530:
531:
532: DAVPropertiesTableModel(DAVFile file)
533: {
534: super ();
535: makePropertyList(file);
536: }
537:
538: void setDAVFile(DAVFile file)
539: {
540: makePropertyList(file);
541: }
542:
543: private void makePropertyList(DAVFile file)
544: {
545: int i=0;
546: tableData[i++][1]=file.getHost();
547: tableData[i++][1]=new Integer(file.getPort());
548: tableData[i++][1]=file.getName();
549: tableData[i++][1]=file.getCreationDate();
550: tableData[i++][1]=file.getLastModified();
551: tableData[i++][1]=file.getContentType();
552: tableData[i++][1]=file.getContentLength();
553: tableData[i++][1]=file.getContentLanguage();
554: tableData[i++][1]=file.getDisplayName();
555: tableData[i++][1]=file.getResourceType();
556: tableData[i++][1]=file.getEtag();
557: tableData[i++][1]=printArray(file.getSupportedLocks());
558: tableData[i++][1]=printArray(file.getLocks());
559: tableData[i][1]=printArray(file.getLinks());
560: }
561:
562: private String printArray(Object[] stuff)
563: {
564: if (stuff==null) return null;
565: StringBuffer sb=new StringBuffer();
566: for (int i=0;i<stuff.length;i++)
567: {
568: if (i>0) sb.append(", ");
569: sb.append(stuff[i]);
570: }
571: return sb.toString();
572: }
573:
574: public int getRowCount()
575: {
576: return tableData.length;
577: }
578:
579: public String getColumnName(int c)
580: {
581: //skip the namespace header
582: return headers[(c==1) ? 2: 0];
583: }
584:
585: public int getColumnCount()
586: {
587: return 2;
588: }
589:
590: public Object getValueAt(int row, int column)
591: {
592: return tableData[row][column];
593: }
594: }
595:
596: private class CustomPropertiesTableModel extends AbstractTableModel
597: {
598: ArrayList tableData;
599: CustomPropertiesTableModel(DAVFile file)
600: {
601: super ();
602: this .setDAVFile(file);
603: }
604:
605: void setDAVFile(DAVFile file)
606: {
607: tableData=extractPairs(file.getCustomProperties());
608: Debug.trace(this , Debug.DP3, "tableData for custom properties: {0}",
609: new Object[] {tableData});
610: fireTableDataChanged();
611: }
612:
613: private ArrayList extractPairs(Map m)
614: {
615: ArrayList daList=new ArrayList();
616: if (m!=null)
617: {
618: for (Iterator it=m.keySet().iterator();it.hasNext();)
619: {
620: Object key=it.next();
621: Object value=m.get(key);
622: Debug.trace(this , Debug.DP3, "reading custom property {0} with value {1}",
623: new Object[] {key, value});
624: daList.add(new Object[] {key, value});
625: }
626: }
627: return daList;
628: }
629:
630: public int getRowCount()
631: {
632: return tableData.size();
633: }
634:
635: public int getColumnCount()
636: {
637: return 3;
638: }
639:
640: public String getColumnName(int c)
641: {
642: return headers[c];
643: }
644:
645: public Object getValueAt(int row, int column)
646: {
647: Assertion.assert((column<3), "only three columns");
648: Object o=tableData.get(row);
649: switch (column)
650: {
651: case 0:
652: case 1:
653: Object propObj=((Object[]) o)[0];
654: if (propObj instanceof DAVProperty)
655: {
656: DAVProperty davProp=(DAVProperty) propObj;
657: if (column==0) return davProp.getElementName();
658: else return davProp.getNamespace();
659: }
660: else return propObj;
661: case 2:
662: return ((Object[]) o)[1];
663: default:
664: Assertion.assert(false, "this should not be reached");
665: return null;
666: }
667: }
668: }
669:
670:
671:}
672:
673:
674:/* $Log: PropertiesDialog.java,v $
675:/* Revision 1.13 2001/06/13 01:09:03 smulloni
676:/* Some improvements to the network customizer (which is still buggy).
677:/* Also improvements for using the doAllprop switch, and for the layout of
678:/* the PropertiesDialog.
679:/*
680:/* Revision 1.12 2000/12/19 22:36:05 smulloni
681:/* adjustments to preamble.
682:/*
683:/* Revision 1.11 2000/12/14 23:09:17 smulloni
684:/* fixes to search and replace; partial fix to adding custom properties bug.
685:/*
686:/* Revision 1.10 2000/12/03 23:53:26 smulloni
687:/* added license and copyright preamble to java files.
688:/*
689:/* Revision 1.9 2000/11/29 23:16:04 smullyan
690:/* adding first rough cut of search capability to the text editor. View
691:/* is being updated to allow components to be docked into the status bar.
692:/*
693:/* Revision 1.8 2000/11/14 23:17:08 smullyan
694:/* more improvements to the PropertiesDialog.
695:/*
696:/* Revision 1.7 2000/11/14 17:13:35 smullyan
697:/* Added TreeModelListener hooks into Explorer, and revised PropertiesDialog to
698:/* use it.
699:/*
700:/* Revision 1.6 2000/11/13 23:28:31 smullyan
701:/* first pass at a gui for proppatch, added to the propertiese dialog. Highly
702:/* problematic still, needs substantial work.
703:/*
704:/* Revision 1.5 2000/11/09 23:34:59 smullyan
705:/* log added to every Java file, with the help of python. Lock stealing
706:/* implemented, and treatment of locks made more robust.
707:/* */
|