Source code: org/gjt/sp/jedit/browser/VFSDirectoryEntryTable.java
1 /*
2 * VFSDirectoryEntryTable.java - VFS directory entry table
3 * :tabSize=8:indentSize=8:noTabs=false:
4 * :folding=explicit:collapseFolds=1:
5 *
6 * Copyright (C) 2003 Slava Pestov
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 package org.gjt.sp.jedit.browser;
24
25 //{{{ Imports
26 import javax.swing.table.*;
27 import javax.swing.*;
28 import java.awt.event.*;
29 import java.awt.font.*;
30 import java.awt.*;
31 import java.util.ArrayList;
32 import java.util.HashSet;
33 import java.util.LinkedList;
34 import java.util.Set;
35 import org.gjt.sp.jedit.io.VFS;
36 import org.gjt.sp.jedit.io.VFSManager;
37 import org.gjt.sp.jedit.MiscUtilities;
38 import org.gjt.sp.util.Log;
39 //}}}
40
41 /**
42 * @author Slava Pestov
43 * @version $Id: VFSDirectoryEntryTable.java,v 1.20 2003/09/08 01:24:11 spestov Exp $
44 * @since jEdit 4.2pre1
45 */
46 public class VFSDirectoryEntryTable extends JTable
47 {
48 //{{{ VFSDirectoryEntryTable constructor
49 public VFSDirectoryEntryTable(BrowserView browserView)
50 {
51 super(new VFSDirectoryEntryTableModel());
52 this.browserView = browserView;
53 setShowGrid(false);
54
55 setIntercellSpacing(new Dimension(0,0));
56
57 /* TableColumn col1 = getColumnModel().getColumn(0);
58 col1.setMinWidth(20);
59 col1.setMaxWidth(20);
60 col1.setPreferredWidth(20); */
61
62 setDefaultRenderer(VFSDirectoryEntryTableModel.Entry.class,
63 renderer = new FileCellRenderer());
64
65 JTableHeader header = getTableHeader();
66 header.setReorderingAllowed(false);
67
68 setRowSelectionAllowed(true);
69 //setColumnSelectionAllowed(true);
70 //setCellSelectionEnabled(false);
71
72 setAutoResizeMode(AUTO_RESIZE_OFF);
73 } //}}}
74
75 //{{{ selectFile() method
76 public boolean selectFile(String path)
77 {
78 for(int i = 0; i < getRowCount(); i++)
79 {
80 VFSDirectoryEntryTableModel.Entry entry =
81 (VFSDirectoryEntryTableModel.Entry)
82 getValueAt(i,1);
83 if(entry.dirEntry.path.equals(path))
84 {
85 setSelectedRow(i);
86 return true;
87 }
88 }
89
90 return false;
91 } //}}}
92
93 //{{{ doTypeSelect() method
94 public void doTypeSelect(String str, boolean dirsOnly)
95 {
96 if(str.length() == 0)
97 clearSelection();
98 else if(getSelectedRow() == -1)
99 doTypeSelect(str,0,getRowCount(),dirsOnly);
100 else
101 {
102 int start = getSelectionModel().getMaxSelectionIndex();
103 boolean retVal = doTypeSelect(str,start,getRowCount(),
104 dirsOnly);
105
106 if(!retVal)
107 {
108 // scan from selection to end failed, so
109 // scan from start to selection
110 doTypeSelect(str,0,start,dirsOnly);
111 }
112 }
113 } //}}}
114
115 //{{{ getSelectedFiles() method
116 public VFS.DirectoryEntry[] getSelectedFiles()
117 {
118 VFSDirectoryEntryTableModel model
119 = (VFSDirectoryEntryTableModel)getModel();
120
121 LinkedList returnValue = new LinkedList();
122 int[] selectedRows = getSelectedRows();
123 for(int i = 0; i < selectedRows.length; i++)
124 {
125 returnValue.add(model.files[selectedRows[i]].dirEntry);
126 }
127 return (VFS.DirectoryEntry[])returnValue.toArray(new
128 VFS.DirectoryEntry[returnValue.size()]);
129 } //}}}
130
131 //{{{ getExpandedDirectories() method
132 public void getExpandedDirectories(Set set)
133 {
134 VFSDirectoryEntryTableModel model
135 = (VFSDirectoryEntryTableModel)getModel();
136
137 if(model.files != null)
138 {
139 for(int i = 0; i < model.files.length; i++)
140 {
141 if(model.files[i].expanded)
142 set.add(model.files[i].dirEntry.path);
143 }
144 }
145 } //}}}
146
147 //{{{ toggleExpanded() method
148 public void toggleExpanded(final int row)
149 {
150 VFSDirectoryEntryTableModel model
151 = (VFSDirectoryEntryTableModel)getModel();
152
153 VFSDirectoryEntryTableModel.Entry entry = model.files[row];
154 if(entry.dirEntry.type == VFS.DirectoryEntry.FILE)
155 return;
156
157 if(entry.expanded)
158 {
159 model.collapse(VFSManager.getVFSForPath(
160 entry.dirEntry.path),row);
161 resizeColumnsAppropriately();
162 }
163 else
164 {
165 browserView.clearExpansionState();
166 browserView.loadDirectory(entry,entry.dirEntry.path);
167 }
168
169 VFSManager.runInAWTThread(new Runnable()
170 {
171 public void run()
172 {
173 setSelectedRow(row);
174 }
175 });
176 } //}}}
177
178 //{{{ setDirectory() method
179 public void setDirectory(VFS vfs, Object node, ArrayList list,
180 Set tmpExpanded)
181 {
182 timer.stop();
183 typeSelectBuffer.setLength(0);
184
185 VFSDirectoryEntryTableModel model = ((VFSDirectoryEntryTableModel)getModel());
186 int startIndex;
187 if(node == null)
188 {
189 startIndex = 0;
190 model.setRoot(vfs,list);
191 }
192 else
193 {
194 startIndex =
195 model.expand(
196 vfs,
197 (VFSDirectoryEntryTableModel.Entry)node,
198 list);
199 startIndex++;
200 }
201
202 for(int i = 0; i < list.size(); i++)
203 {
204 VFSDirectoryEntryTableModel.Entry e
205 = model.files[startIndex + i];
206 String path = e.dirEntry.path;
207 if(tmpExpanded.contains(path))
208 {
209 browserView.loadDirectory(e,path);
210 tmpExpanded.remove(path);
211 }
212 }
213
214 resizeColumnsAppropriately();
215 } //}}}
216
217 //{{{ maybeReloadDirectory() method
218 public void maybeReloadDirectory(String path)
219 {
220 VFSDirectoryEntryTableModel model
221 = (VFSDirectoryEntryTableModel)getModel();
222
223 for(int i = 0; i < model.files.length; i++)
224 {
225 VFSDirectoryEntryTableModel.Entry e = model.files[i];
226 if(!e.expanded || e.dirEntry.type == VFS.DirectoryEntry.FILE)
227 continue;
228
229 if(VFSBrowser.pathsEqual(path,e.dirEntry.symlinkPath))
230 {
231 browserView.saveExpansionState();
232 browserView.loadDirectory(e,path);
233 return;
234 }
235 }
236 } //}}}
237
238 //{{{ propertiesChanged() method
239 public void propertiesChanged()
240 {
241 renderer.propertiesChanged();
242
243 VFS.DirectoryEntry template = new VFS.DirectoryEntry(
244 "foo","foo","foo",VFS.DirectoryEntry.FILE,0L,false);
245 setRowHeight(renderer.getTableCellRendererComponent(
246 this,new VFSDirectoryEntryTableModel.Entry(template,0),
247 false,false,0,0).getPreferredSize().height);
248 Dimension prefSize = getPreferredSize();
249 setPreferredScrollableViewportSize(new Dimension(prefSize.width,
250 getRowHeight() * 12));
251 } //}}}
252
253 //{{{ scrollRectToVisible() method
254 public void scrollRectToVisible(Rectangle rect)
255 {
256 // avoid scrolling to the right
257 rect.width = 0;
258 super.scrollRectToVisible(rect);
259 } //}}}
260
261 //{{{ processKeyEvent() method
262 public void processKeyEvent(KeyEvent evt)
263 {
264 if(evt.getID() == KeyEvent.KEY_PRESSED)
265 {
266 VFSDirectoryEntryTableModel model =
267 (VFSDirectoryEntryTableModel)getModel();
268 int row = getSelectedRow();
269
270 switch(evt.getKeyCode())
271 {
272 case KeyEvent.VK_LEFT:
273 evt.consume();
274 if(row != -1)
275 {
276 if(model.files[row].expanded)
277 {
278 model.collapse(
279 VFSManager.getVFSForPath(
280 model.files[row].dirEntry.path),
281 row);
282 break;
283 }
284
285 for(int i = row - 1; i >= 0; i--)
286 {
287 if(model.files[i].expanded)
288 {
289 setSelectedRow(i);
290 break;
291 }
292 }
293 }
294
295 String dir = browserView.getBrowser()
296 .getDirectory();
297 dir = MiscUtilities.getParentOfPath(dir);
298 browserView.getBrowser().setDirectory(dir);
299 break;
300 case KeyEvent.VK_RIGHT:
301 if(row != -1)
302 {
303 if(!model.files[row].expanded)
304 toggleExpanded(row);
305 }
306 evt.consume();
307 break;
308 case KeyEvent.VK_DOWN:
309 // stupid Swing
310 if(row == -1 && getModel().getRowCount() != 0)
311 {
312 setSelectedRow(0);
313 evt.consume();
314 }
315 break;
316 case KeyEvent.VK_ENTER:
317 browserView.getBrowser().filesActivated(
318 (evt.isShiftDown()
319 ? VFSBrowser.M_OPEN_NEW_VIEW
320 : VFSBrowser.M_OPEN),false);
321 evt.consume();
322 break;
323 }
324 }
325 else if(evt.getID() == KeyEvent.KEY_TYPED)
326 {
327 if(evt.isControlDown() || evt.isAltDown()
328 || evt.isMetaDown())
329 {
330 return;
331 }
332
333 // hack...
334 if(evt.isShiftDown() && evt.getKeyChar() == '\n')
335 return;
336
337 VFSBrowser browser = browserView.getBrowser();
338
339 switch(evt.getKeyChar())
340 {
341 case '~':
342 if(browser.getMode() == VFSBrowser.BROWSER)
343 browser.setDirectory(System.getProperty(
344 "user.home"));
345 break;
346 case '/':
347 if(browser.getMode() == VFSBrowser.BROWSER)
348 browser.rootDirectory();
349 break;
350 case '-':
351 if(browser.getMode() == VFSBrowser.BROWSER)
352 {
353 browser.setDirectory(
354 browser.getView().getBuffer()
355 .getDirectory());
356 }
357 break;
358 default:
359 typeSelectBuffer.append(evt.getKeyChar());
360 doTypeSelect(typeSelectBuffer.toString(),
361 browser.getMode() == VFSBrowser
362 .CHOOSE_DIRECTORY_DIALOG);
363
364 timer.stop();
365 timer.setInitialDelay(750);
366 timer.setRepeats(false);
367 timer.start();
368 return;
369 }
370 }
371
372 if(!evt.isConsumed())
373 super.processKeyEvent(evt);
374 } //}}}
375
376 //{{{ setSelectedRow() method
377 public void setSelectedRow(int row)
378 {
379 getSelectionModel().setSelectionInterval(row,row);
380 scrollRectToVisible(getCellRect(row,0,true));
381 } //}}}
382
383 //{{{ Private members
384 private BrowserView browserView;
385 private FileCellRenderer renderer;
386 private StringBuffer typeSelectBuffer = new StringBuffer();
387 private Timer timer = new Timer(0,new ClearTypeSelect());
388
389 //{{{ doTypeSelect() method
390 private boolean doTypeSelect(String str, int start, int end,
391 boolean dirsOnly)
392 {
393 for(int i = start; i < end; i++)
394 {
395 VFSDirectoryEntryTableModel.Entry entry =
396 (VFSDirectoryEntryTableModel.Entry)getValueAt(i,1);
397 if(dirsOnly && entry.dirEntry.type
398 == VFS.DirectoryEntry.FILE)
399 {
400 continue;
401 }
402
403 String matchAgainst = (MiscUtilities.isAbsolutePath(str)
404 ? entry.dirEntry.path : entry.dirEntry.name);
405 if(matchAgainst.regionMatches(true,
406 0,str,0,str.length()))
407 {
408 setSelectedRow(i);
409 return true;
410 }
411 }
412
413 return false;
414 } //}}}
415
416 //{{{ resizeColumnsAppropriately() method
417 private void resizeColumnsAppropriately()
418 {
419 VFSDirectoryEntryTableModel model
420 = (VFSDirectoryEntryTableModel)getModel();
421
422 FontRenderContext fontRenderContext = new FontRenderContext(
423 null,false,false);
424 int[] widths = new int[model.getColumnCount()];
425 for(int i = 0; i < widths.length; i++)
426 {
427 String columnName = model.getColumnName(i);
428 if(columnName != null)
429 {
430 widths[i] = (int)renderer.plainFont
431 .getStringBounds(columnName,
432 fontRenderContext).getWidth();
433 }
434 }
435
436 for(int i = 0; i < model.files.length; i++)
437 {
438 VFSDirectoryEntryTableModel.Entry entry
439 = model.files[i];
440 Font font = (entry.dirEntry.type
441 == VFS.DirectoryEntry.FILE
442 ? renderer.plainFont : renderer.boldFont);
443
444 widths[0] = Math.max(widths[0],renderer.getEntryWidth(
445 entry,font,fontRenderContext));
446
447 for(int j = 1; j < widths.length; j++)
448 {
449 String extAttr = model.getExtendedAttribute(
450 j - 1);
451 String attr = entry.dirEntry
452 .getExtendedAttribute(
453 extAttr);
454 if(attr != null)
455 {
456 widths[j] = Math.max(widths[j],
457 (int)font.getStringBounds(
458 attr,fontRenderContext)
459 .getWidth());
460 }
461 }
462 }
463
464 for(int i = 0; i < widths.length; i++)
465 {
466 int width = widths[i];
467 if(i != widths.length - 1 && width != 0)
468 width += 10;
469 else
470 width += 2;
471 getColumnModel().getColumn(i).setPreferredWidth(width);
472 getColumnModel().getColumn(i).setMinWidth(width);
473 getColumnModel().getColumn(i).setMaxWidth(width);
474 getColumnModel().getColumn(i).setWidth(width);
475 }
476
477 doLayout();
478 } //}}}
479
480 //}}}
481
482 //{{{ ClearTypeSelect class
483 class ClearTypeSelect implements ActionListener
484 {
485 public void actionPerformed(ActionEvent evt)
486 {
487 typeSelectBuffer.setLength(0);
488 }
489 } //}}}
490 }