001: /*
002: * VFSDirectoryEntryTableModel.java - VFS directory entry table model
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2003, 2005 Slava Pestov
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: */
022:
023: package org.gjt.sp.jedit.browser;
024:
025: import javax.swing.table.*;
026: import java.util.*;
027: import org.gjt.sp.jedit.io.FileVFS;
028: import org.gjt.sp.jedit.io.VFS;
029: import org.gjt.sp.jedit.io.VFSFile;
030: import org.gjt.sp.jedit.io.VFSManager;
031: import org.gjt.sp.jedit.*;
032: import org.gjt.sp.util.Log;
033: import org.gjt.sp.util.StandardUtilities;
034:
035: /**
036: * @author Slava Pestov
037: * @version $Id: VFSDirectoryEntryTableModel.java 10275 2007-08-01 22:08:40Z ezust $
038: * @since jEdit 4.2pre1
039: */
040: public class VFSDirectoryEntryTableModel extends AbstractTableModel {
041: //{{{ VFSDirectoryEntryTableModel constructor
042: public VFSDirectoryEntryTableModel() {
043: extAttrs = new ArrayList<ExtendedAttribute>();
044: sortColumn = 0;
045: ascending = true;
046: } //}}}
047:
048: //{{{ setRoot() method
049: public void setRoot(VFS vfs, List<VFSFile> list) {
050: extAttrs.clear();
051: addExtendedAttributes(vfs);
052:
053: /* if(files != null && files.length != 0)
054: fireTableRowsDeleted(0,files.length - 1); */
055:
056: files = new Entry[list.size()];
057: for (int i = 0; i < files.length; i++) {
058: files[i] = new Entry(list.get(i), 0);
059: }
060:
061: /* if(files.length != 0)
062: fireTableRowsInserted(0,files.length - 1); */
063:
064: Arrays.sort(files, new EntryCompare(
065: getSortAttribute(sortColumn), ascending));
066: fireTableStructureChanged();
067: } //}}}
068:
069: //{{{ expand() method
070: public int expand(VFS vfs, Entry entry, List<VFSFile> list) {
071: int startIndex = -1;
072: for (int i = 0; i < files.length; i++) {
073: if (files[i] == entry)
074: startIndex = i;
075: }
076: if (startIndex != -1)
077: collapse(vfs, startIndex);
078:
079: addExtendedAttributes(vfs);
080: entry.expanded = true;
081:
082: if (list != null) {
083: // make a large enough destination array
084: Entry[] newFiles = new Entry[files.length + list.size()];
085: Entry[] subdirFiles = new Entry[list.size()];
086:
087: for (int i = 0; i < list.size(); i++) {
088: subdirFiles[i] = new Entry(list.get(i),
089: entry.level + 1, entry);
090: }
091:
092: // sort expanded entries according to current sort params
093: Arrays.sort(subdirFiles, new EntryCompare(
094: getSortAttribute(sortColumn), ascending));
095:
096: // make room after expanded entry for subdir files
097: int nextIndex = startIndex + 1;
098: System.arraycopy(files, 0, newFiles, 0, nextIndex);
099: System.arraycopy(subdirFiles, 0, newFiles, nextIndex, list
100: .size());
101: System.arraycopy(files, nextIndex, newFiles, nextIndex
102: + list.size(), files.length - nextIndex);
103:
104: this .files = newFiles;
105:
106: /* fireTableRowsInserted(startIndex + 1,
107: startIndex + list.size() + 1); */
108: }
109:
110: /* fireTableRowsUpdated(startIndex,startIndex); */
111:
112: fireTableStructureChanged();
113:
114: return startIndex;
115: } //}}}
116:
117: //{{{ collapse() method
118: public void collapse(VFS vfs, int index) {
119: Entry entry = files[index];
120: if (!entry.expanded)
121: return;
122:
123: entry.expanded = false;
124:
125: int lastIndex = index + 1;
126: while (lastIndex < files.length) {
127: Entry e = files[lastIndex];
128:
129: if (e.level <= entry.level)
130: break;
131:
132: lastIndex++;
133:
134: if (e.expanded) {
135: removeExtendedAttributes(VFSManager
136: .getVFSForPath(e.dirEntry.getPath()));
137: }
138: }
139:
140: removeExtendedAttributes(vfs);
141:
142: Entry[] newFiles = new Entry[files.length - lastIndex + index
143: + 1];
144: System.arraycopy(files, 0, newFiles, 0, index + 1);
145: System.arraycopy(files, lastIndex, newFiles, index + 1,
146: files.length - lastIndex);
147:
148: files = newFiles;
149:
150: /* fireTableRowsUpdated(index,index);
151: fireTableRowsDeleted(index + 1,lastIndex); */
152:
153: fireTableStructureChanged();
154: } //}}}
155:
156: //{{{ getColumnCount() method
157: public int getColumnCount() {
158: return 1 + extAttrs.size();
159: } //}}}
160:
161: //{{{ getRowCount() method
162: public int getRowCount() {
163: if (files == null)
164: return 0;
165: else
166: return files.length;
167: } //}}}
168:
169: //{{{ getColumnName() method
170: public String getColumnName(int col) {
171: if (col == 0)
172: return jEdit.getProperty("vfs.browser.name");
173: else
174: return jEdit.getProperty("vfs.browser."
175: + getExtendedAttribute(col));
176: } //}}}
177:
178: //{{{ getColumnClass() method
179: public Class getColumnClass(int col) {
180: return Entry.class;
181: } //}}}
182:
183: //{{{ getValueAt() method
184: public Object getValueAt(int row, int col) {
185: if (files == null)
186: return null;
187: else
188: return files[row];
189: } //}}}
190:
191: //{{{ getAscending() method
192: public boolean getAscending() {
193: return ascending;
194: } //}}}
195:
196: //{{{ getSortColumn() method
197: public int getSortColumn() {
198: return sortColumn;
199: } //}}}
200:
201: //{{{ getSortAttribute() method
202: public String getSortAttribute(int column) {
203: return (column == 0) ? "name" : getExtendedAttribute(column);
204: } //}}}
205:
206: //{{{ sortByColumn() method
207: public boolean sortByColumn(int column) {
208: // toggle ascending/descending if column was clicked again
209: ascending = (sortColumn == column) ? !ascending : true;
210:
211: // we don't sort by some attributes
212: String sortBy = getSortAttribute(column);
213: if (sortBy == VFS.EA_STATUS)
214: return false;
215:
216: Arrays.sort(files, new EntryCompare(sortBy, ascending));
217:
218: // remember column
219: sortColumn = column;
220: fireTableStructureChanged();
221:
222: return true;
223: } //}}}
224:
225: //{{{ getExtendedAttribute() method
226: public String getExtendedAttribute(int index) {
227: return extAttrs.get(index - 1).name;
228: } //}}}
229:
230: //{{{ getColumnWidth() method
231: /**
232: * @param i The column index
233: * @return A saved column width
234: * @since jEdit 4.3pre2
235: */
236: public int getColumnWidth(int i) {
237: String extAttr = getExtendedAttribute(i);
238: return jEdit.getIntegerProperty("vfs.browser." + extAttr
239: + ".width", 100);
240: } //}}}
241:
242: //{{{ setColumnWidth() method
243: /**
244: * @param i The column index
245: * @param w The column width
246: * @since jEdit 4.3pre2
247: */
248: public void setColumnWidth(int i, int w) {
249: String extAttr = getExtendedAttribute(i);
250: jEdit
251: .setIntegerProperty(
252: "vfs.browser." + extAttr + ".width", w);
253: } //}}}
254:
255: //{{{ getFiles() method
256: public VFSFile[] getFiles() {
257: VFSFile[] f = new VFSFile[files.length];
258: for (int i = 0; i < f.length; i++)
259: f[i] = files[i].dirEntry;
260: return f;
261: } //}}}
262:
263: //{{{ Package-private members
264: Entry[] files;
265: //}}}
266:
267: //{{{ Private members
268: private List<ExtendedAttribute> extAttrs;
269: private int sortColumn;
270: private boolean ascending;
271:
272: //{{{ addExtendedAttributes() method
273: private void addExtendedAttributes(VFS vfs) {
274: String[] attrs = vfs.getExtendedAttributes();
275: vfs_attr_loop: for (int i = 0; i < attrs.length; i++) {
276: for (ExtendedAttribute attr : extAttrs) {
277: if (attrs[i].equals(attr.name)) {
278: attr.ref++;
279: continue vfs_attr_loop;
280: }
281: }
282:
283: // this vfs has an extended attribute which is not
284: // in the list. add it to the end with a ref count
285: // of 1
286: extAttrs.add(new ExtendedAttribute(attrs[i]));
287: }
288: } //}}}
289:
290: //{{{ removeExtendedAttributes() method
291: private void removeExtendedAttributes(VFS vfs) {
292: String[] attrs = vfs.getExtendedAttributes();
293: vfs_attr_loop: for (int i = 0; i < attrs.length; i++) {
294: Iterator<ExtendedAttribute> iter = extAttrs.iterator();
295: while (iter.hasNext()) {
296: ExtendedAttribute attr = iter.next();
297: if (attrs[i].equals(attr.name)) {
298: if (--attr.ref == 0) {
299: // we no longer have any
300: // dirs using this extended
301: // attribute
302: iter.remove();
303: }
304:
305: continue vfs_attr_loop;
306: }
307: }
308:
309: // this vfs has an extended attribute which is not
310: // in the list ???
311: Log.log(Log.WARNING, this , "We forgot about " + attrs[i]);
312: }
313: } //}}}
314:
315: //}}}
316:
317: //{{{ Entry class
318: static class Entry {
319: VFSFile dirEntry;
320: // is this branch an expanded dir?
321: boolean expanded;
322: // how deeply we are nested
323: int level;
324: // parent entry
325: Entry parent;
326: // file extension
327: String extension;
328:
329: Entry(VFSFile dirEntry, int level, Entry parent) {
330: this (dirEntry, level);
331: this .parent = parent;
332: }
333:
334: Entry(VFSFile dirEntry, int level) {
335: this .dirEntry = dirEntry;
336: this .level = level;
337: this .extension = MiscUtilities.getFileExtension(dirEntry
338: .getName());
339: }
340:
341: } //}}}
342:
343: //{{{ ExtendedAttribute class
344: static class ExtendedAttribute {
345: /* reference counter allows us to remove a column from
346: * the table when no directory using this column is
347: * visible */
348: int ref;
349:
350: String name;
351:
352: ExtendedAttribute(String name) {
353: this .name = name;
354: ref = 1;
355: }
356: } //}}}
357:
358: //{{{ EntryCompare class
359: /**
360: * Implementation of {@link Comparator}
361: * interface that compares {@link VFSDirectoryEntryTableModel.Entry} instances.
362: * For sorting columns in the VFS Browser.
363: * @since jEdit 4.3pre7
364: */
365: static class EntryCompare implements Comparator {
366: private boolean sortIgnoreCase, sortMixFilesAndDirs,
367: sortAscending;
368: private String sortAttribute;
369:
370: /**
371: * Creates a new <code>EntryCompare</code>
372: * Expanded branches are sorted, too, but keep with their parent entries
373: * @param sortBy The extended attribute by which to sort the entries.
374: * @param ascending If false, sort order is reversed.
375: */
376: EntryCompare(String sortBy, boolean ascending) {
377: this .sortMixFilesAndDirs = jEdit
378: .getBooleanProperty("vfs.browser.sortMixFilesAndDirs");
379: this .sortIgnoreCase = jEdit
380: .getBooleanProperty("vfs.browser.sortIgnoreCase");
381: this .sortAscending = ascending;
382: this .sortAttribute = sortBy;
383: }
384:
385: public int compare(Object obj1, Object obj2) {
386: Entry entry1 = (Entry) obj1;
387: Entry entry2 = (Entry) obj2;
388:
389: // we want to compare sibling ancestors of the entries
390: if (entry1.level < entry2.level)
391: return compare(entry1, entry2.parent);
392: if (entry1.level > entry2.level)
393: return compare(entry1.parent, entry2);
394:
395: // here we have entries of the same level
396: if (entry1.parent != entry2.parent)
397: return compare(entry1.parent, entry2.parent);
398:
399: // here we have siblings with the same parents
400: // let's do the real comparison
401:
402: VFSFile file1 = entry1.dirEntry;
403: VFSFile file2 = entry2.dirEntry;
404:
405: if (!sortMixFilesAndDirs) {
406: if (file1.getType() != file2.getType())
407: return file2.getType() - file1.getType();
408: }
409:
410: int result;
411:
412: // if the modified attribute is present, then we have a LocalFile
413: if (sortAttribute == VFS.EA_MODIFIED)
414: result = ((Long) ((FileVFS.LocalFile) file1)
415: .getModified())
416: .compareTo((Long) ((FileVFS.LocalFile) file2)
417: .getModified());
418: // sort by size
419: else if (sortAttribute == VFS.EA_SIZE)
420: result = ((Long) file1.getLength())
421: .compareTo((Long) file2.getLength());
422: // sort by type (= extension)
423: else if (sortAttribute == VFS.EA_TYPE)
424: result = StandardUtilities.compareStrings(
425: entry1.extension, entry2.extension,
426: sortIgnoreCase);
427: // default: sort by name
428: else
429: result = StandardUtilities.compareStrings(file1
430: .getName(), file2.getName(), sortIgnoreCase);
431: return (sortAscending) ? result : -result;
432: }
433: } //}}}
434:
435: }
|