PageRenderTime 120ms CodeModel.GetById 91ms app.highlight 23ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/browser/VFSDirectoryEntryTable.java

#
Java | 666 lines | 530 code | 76 blank | 60 comment | 82 complexity | f344a9587633546af7a7fcdf81ccc458 MD5 | raw file
  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, 2005 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
 23package org.gjt.sp.jedit.browser;
 24
 25//{{{ Imports
 26import javax.swing.event.*;
 27import javax.swing.table.*;
 28import javax.swing.*;
 29import java.awt.event.*;
 30import java.awt.font.*;
 31import java.awt.*;
 32import java.util.LinkedList;
 33import java.util.Set;
 34
 35import org.gjt.sp.jedit.browser.VFSDirectoryEntryTableModel.Entry;
 36import org.gjt.sp.jedit.io.VFS;
 37import org.gjt.sp.jedit.io.VFSFile;
 38import org.gjt.sp.jedit.io.VFSManager;
 39import org.gjt.sp.jedit.msg.VFSPathSelected;
 40import org.gjt.sp.jedit.ActionContext;
 41import org.gjt.sp.jedit.EditAction;
 42import org.gjt.sp.jedit.EditBus;
 43import org.gjt.sp.jedit.MiscUtilities;
 44import org.gjt.sp.jedit.GUIUtilities;
 45import org.gjt.sp.jedit.jEdit;
 46import org.gjt.sp.util.Log;
 47import org.gjt.sp.util.ThreadUtilities;
 48//}}}
 49
 50/**
 51 * @author Slava Pestov
 52 * @version $Id: VFSDirectoryEntryTable.java 18960 2010-11-15 19:23:52Z ezust $
 53 * @since jEdit 4.2pre1
 54 */
 55public class VFSDirectoryEntryTable extends JTable
 56{
 57	//{{{ VFSDirectoryEntryTable constructor
 58	VFSDirectoryEntryTable(BrowserView browserView)
 59	{
 60		super(new VFSDirectoryEntryTableModel());
 61		this.browserView = browserView;
 62		setShowGrid(false);
 63
 64		setIntercellSpacing(new Dimension(0,0));
 65
 66		setDefaultRenderer(Entry.class,
 67			renderer = new FileCellRenderer());
 68
 69		header = getTableHeader();
 70		header.setReorderingAllowed(false);
 71		addMouseListener(new MainMouseHandler());
 72		header.addMouseListener(new MouseHandler());
 73		header.setDefaultRenderer(new HeaderRenderer(
 74			(DefaultTableCellRenderer)header.getDefaultRenderer()));
 75
 76		setRowSelectionAllowed(true);
 77
 78		getColumnModel().addColumnModelListener(new ColumnHandler());
 79
 80		setAutoResizeMode(AUTO_RESIZE_OFF);
 81	} //}}}
 82
 83	//{{{ selectFile() method
 84	public boolean selectFile(String path)
 85	{
 86		for(int i = 0; i < getRowCount(); i++)
 87		{
 88			Entry entry = (Entry) getValueAt(i,1);
 89			if(entry.dirEntry.getPath().equals(path))
 90			{
 91				setSelectedRow(i);
 92				return true;
 93			}
 94		}
 95
 96		return false;
 97	} //}}}
 98
 99	//{{{ doTypeSelect() method
100	public void doTypeSelect(String str, boolean dirsOnly)
101	{
102		if(str.length() == 0)
103			clearSelection();
104		else if(getSelectedRow() == -1)
105			doTypeSelect(str,0,getRowCount(),dirsOnly);
106		else
107		{
108			int start = getSelectionModel().getMaxSelectionIndex();
109			boolean retVal = doTypeSelect(str,start,getRowCount(),
110				dirsOnly);
111
112			if(!retVal)
113			{
114				// scan from selection to end failed, so
115				// scan from start to selection
116				doTypeSelect(str,0,start,dirsOnly);
117			}
118		}
119	} //}}}
120
121	//{{{ getSelectedFiles() method
122	public VFSFile[] getSelectedFiles()
123	{
124		VFSDirectoryEntryTableModel model
125			= (VFSDirectoryEntryTableModel)getModel();
126
127		java.util.List<VFSFile> returnValue = new LinkedList<VFSFile>();
128		int[] selectedRows = getSelectedRows();
129		for(int i = 0; i < selectedRows.length; i++)
130		{
131			returnValue.add(model.files[selectedRows[i]].dirEntry);
132		}
133		return returnValue.toArray(new VFSFile[returnValue.size()]);
134	} //}}}
135
136	//{{{ getExpandedDirectories() method
137	public void getExpandedDirectories(Set<String> set)
138	{
139		VFSDirectoryEntryTableModel model
140			= (VFSDirectoryEntryTableModel)getModel();
141
142		if(model.files != null)
143		{
144			for(int i = 0; i < model.files.length; i++)
145			{
146				if(model.files[i].expanded)
147					set.add(model.files[i].dirEntry.getPath());
148			}
149		}
150	} //}}}
151
152	//{{{ toggleExpanded() method
153	public void toggleExpanded(final int row)
154	{
155		VFSDirectoryEntryTableModel model
156		= (VFSDirectoryEntryTableModel)getModel();
157
158		Entry entry = model.files[row];
159		if(entry.dirEntry.getType() == VFSFile.FILE)
160			return;
161
162		Runnable delayedAwtTask = new Runnable()
163		{
164			public void run()
165			{
166				setSelectedRow(row);
167			}
168		};
169		if(entry.expanded)
170		{
171			model.collapse(VFSManager.getVFSForPath(
172				entry.dirEntry.getPath()),row);
173			resizeColumns();
174			ThreadUtilities.runInDispatchThread(delayedAwtTask);
175		}
176		else
177		{
178			browserView.clearExpansionState();
179			browserView.loadDirectory(entry,entry.dirEntry.getPath(),
180				false, delayedAwtTask);
181		}
182
183
184
185	} //}}}
186
187	//{{{ setDirectory() method
188	public void setDirectory(VFS vfs, Object node, java.util.List<VFSFile> list,
189		Set<String> tmpExpanded)
190	{
191		timer.stop();
192		typeSelectBuffer.setLength(0);
193
194		VFSDirectoryEntryTableModel model = (VFSDirectoryEntryTableModel)getModel();
195		int startIndex;
196		if(node == null)
197		{
198			startIndex = 0;
199			model.setRoot(vfs,list);
200		}
201		else
202		{
203			startIndex =
204				model.expand(
205				vfs,
206				(Entry)node,
207				list);
208			startIndex++;
209		}
210
211		for(int i = 0; i < list.size(); i++)
212		{
213			Entry e = model.files[startIndex + i];
214			String path = e.dirEntry.getPath();
215			if(tmpExpanded.contains(path))
216			{
217				browserView.loadDirectory(e,path,false);
218				tmpExpanded.remove(path);
219			}
220		}
221
222		resizeColumns();
223	} //}}}
224
225	//{{{ maybeReloadDirectory() method
226	public void maybeReloadDirectory(String path)
227	{
228		VFSDirectoryEntryTableModel model
229		= (VFSDirectoryEntryTableModel)getModel();
230
231		for(int i = 0; i < model.files.length; i++)
232		{
233			Entry e = model.files[i];
234			if(!e.expanded || e.dirEntry.getType() == VFSFile.FILE)
235				continue;
236
237			VFSFile dirEntry = e.dirEntry;
238			// work around for broken FTP plugin!
239			String otherPath;
240			if(dirEntry.getSymlinkPath() == null)
241				otherPath = dirEntry.getPath();
242			else
243				otherPath = dirEntry.getSymlinkPath();
244			if(MiscUtilities.pathsEqual(path,otherPath))
245			{
246				browserView.saveExpansionState();
247				browserView.loadDirectory(e,path,false);
248				return;
249			}
250		}
251	} //}}}
252
253	//{{{ propertiesChanged() method
254	public void propertiesChanged()
255	{
256		renderer.propertiesChanged();
257
258		VFSFile template = new VFSFile(
259			"foo","foo","foo",VFSFile.FILE,0L,false);
260		setRowHeight(renderer.getTableCellRendererComponent(
261			this,new Entry(template,0),
262			false,false,0,0).getPreferredSize().height);
263		Dimension prefSize = getPreferredSize();
264		setPreferredScrollableViewportSize(new Dimension(prefSize.width,
265			getRowHeight() * 12));
266	} //}}}
267
268	//{{{ scrollRectToVisible() method
269	@Override
270	public void scrollRectToVisible(Rectangle rect)
271	{
272		// avoid scrolling to the right
273		rect.width = 0;
274		super.scrollRectToVisible(rect);
275	} //}}}
276
277	//{{{ processKeyEvent() method
278	@Override
279	public void processKeyEvent(KeyEvent evt)
280	{
281		if(evt.getID() == KeyEvent.KEY_PRESSED)
282		{
283			VFSDirectoryEntryTableModel model =
284				(VFSDirectoryEntryTableModel)getModel();
285			int row = getSelectedRow();
286			ActionContext ac = VFSBrowser.getActionContext();
287			ActionContext jac = jEdit.getActionContext();
288			EditAction browserUp = ac.getAction("vfs.browser.up");			
289			VFSBrowser browser = browserView.getBrowser();
290			switch(evt.getKeyCode())
291			{
292			case KeyEvent.VK_LEFT:
293				evt.consume();
294				if ((evt.getModifiers() & InputEvent.ALT_MASK)>0)
295				{
296					browser.previousDirectory();
297				}
298				else 
299				{
300					if(row != -1)
301					{
302						if(model.files[row].expanded)
303						{
304							toggleExpanded(row);
305							return;
306						}
307
308						for(int i = row - 1; i >= 0; i--)
309						{
310							if(model.files[i].expanded &&
311							   model.files[i].level < model.files[row].level)
312							{
313								setSelectedRow(i);
314								return;
315							}
316						}
317					}
318
319					String dir = browserView.getBrowser()
320						.getDirectory();
321					dir = MiscUtilities.getParentOfPath(dir);
322					browserView.getBrowser().setDirectory(dir);
323				}
324				break;
325			case KeyEvent.VK_TAB:
326				evt.consume();
327				if ((evt.getModifiers() & InputEvent.SHIFT_MASK) > 0)
328				{
329					browserView.getParentDirectoryList().requestFocus();
330				}
331				else
332				{
333					browser.focusOnDefaultComponent();	
334				}
335				break;
336			case KeyEvent.VK_BACK_SPACE:
337				evt.consume();
338				ac.invokeAction(evt, browserUp);
339				break;
340			case KeyEvent.VK_UP:
341				if ((evt.getModifiers() & InputEvent.ALT_MASK) >0)
342				{
343					evt.consume();
344					ac.invokeAction(evt, browserUp);
345				}
346				break;
347			case KeyEvent.VK_DELETE:
348				evt.consume();
349				EditAction deleteAct = ac.getAction("vfs.browser.delete");
350				ac.invokeAction(evt, deleteAct);
351				break;
352			case KeyEvent.VK_N:
353				if ((evt.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK)
354				{
355					evt.consume();
356					EditAction ea = ac.getAction("vfs.browser.new-file");
357					ac.invokeAction(evt, ea);
358				}
359				break;
360			case KeyEvent.VK_INSERT:
361				evt.consume();
362				EditAction newDir = ac.getAction("vfs.browser.new-directory");
363				ac.invokeAction(evt, newDir);
364				break;
365			case KeyEvent.VK_ESCAPE:
366				EditAction cda = ac.getAction("vfs.browser.closedialog");
367				ac.invokeAction(evt, cda);
368				break;
369			case KeyEvent.VK_F2:
370				EditAction ren = ac.getAction("vfs.browser.rename");
371				evt.consume();
372				ac.invokeAction(evt, ren);
373				break;
374			case KeyEvent.VK_F5:
375				evt.consume();
376				EditAction reload= ac.getAction("vfs.browser.reload");
377				ac.invokeAction(evt, reload);
378				break;
379			case KeyEvent.VK_F6:
380			case KeyEvent.VK_RIGHT:
381				evt.consume();
382				if ((evt.getModifiers() & InputEvent.ALT_MASK)>0)
383				{
384					browser.nextDirectory();
385				}
386				else if(row != -1)
387				{
388					if(!model.files[row].expanded)
389						toggleExpanded(row);
390				}
391				break;
392			case KeyEvent.VK_ENTER:
393				evt.consume();
394				browserView.getBrowser().filesActivated(
395					evt.isShiftDown()
396					? VFSBrowser.M_OPEN_NEW_VIEW
397					: VFSBrowser.M_OPEN,false);
398
399				break;
400			}
401		}
402		else if(evt.getID() == KeyEvent.KEY_TYPED)
403		{
404
405			if(evt.isControlDown() || evt.isAltDown()
406				|| evt.isMetaDown())
407			{
408				evt.consume();
409				return;
410			}
411
412			// hack...
413			if(evt.isShiftDown() && evt.getKeyChar() == '\n')
414			{
415				evt.consume();
416				return;
417			}
418
419
420			VFSBrowser browser = browserView.getBrowser();
421
422			switch(evt.getKeyChar())
423			{
424			case '~':
425				evt.consume();
426				if(browser.getMode() == VFSBrowser.BROWSER)
427					browser.setDirectory(System.getProperty(
428						"user.home"));
429				break;
430			case '/':
431				evt.consume();
432				if(browser.getMode() == VFSBrowser.BROWSER)
433					browser.rootDirectory();
434				break;
435			case '-':
436				evt.consume();
437				if(browser.getMode() == VFSBrowser.BROWSER)
438				{
439					browser.setDirectory(
440						browser.getView().getBuffer()
441						.getDirectory());
442				}
443				break;
444			default:
445				evt.consume();
446				typeSelectBuffer.append(evt.getKeyChar());
447				doTypeSelect(typeSelectBuffer.toString(),
448					browser.getMode() == VFSBrowser
449					.CHOOSE_DIRECTORY_DIALOG);
450
451				timer.stop();
452				timer.setInitialDelay(750);
453				timer.setRepeats(false);
454				timer.start();
455				return;
456			}
457		}
458
459		if(!evt.isConsumed())
460			super.processKeyEvent(evt);
461	} //}}}
462
463	//{{{ setSelectedRow() method
464	public void setSelectedRow(int row)
465	{
466		getSelectionModel().setSelectionInterval(row,row);
467		scrollRectToVisible(getCellRect(row,0,true));
468	} //}}}
469
470	//{{{ Private members
471	private final BrowserView browserView;
472	private final JTableHeader header;
473	private final FileCellRenderer renderer;
474	private final StringBuffer typeSelectBuffer = new StringBuffer();
475	private final Timer timer = new Timer(0,new ClearTypeSelect());
476	private boolean resizingColumns;
477
478	//{{{ doTypeSelect() method
479	private boolean doTypeSelect(String str, int start, int end,
480		boolean dirsOnly)
481	{
482		VFSFile[] files = ((VFSDirectoryEntryTableModel)
483			getModel()).getFiles();
484
485		int index = VFSFile.findCompletion(files,start,end,str,dirsOnly);
486		if(index != -1)
487		{
488			setSelectedRow(index);
489			return true;
490		}
491		else
492			return false;
493	} //}}}
494
495	//{{{ resizeColumns() method
496	private void resizeColumns()
497	{
498		VFSDirectoryEntryTableModel model = (VFSDirectoryEntryTableModel)getModel();
499
500		FontRenderContext fontRenderContext = new FontRenderContext(
501			null,false,false);
502		int[] widths = new int[model.getColumnCount()];
503		for(int i = 0; i < widths.length; i++)
504		{
505			String columnName = model.getColumnName(i);
506			if(columnName != null)
507			{
508				widths[i] = (int)renderer.plainFont
509					.getStringBounds(columnName,
510					fontRenderContext).getWidth();
511			}
512		}
513
514		for(int i = 1; i < widths.length; i++)
515		{
516			//String extAttr = model.getExtendedAttribute(i);
517			widths[i] = Math.max(widths[i],model.getColumnWidth(i));
518		}
519
520		for(int i = 0; i < model.files.length; i++)
521		{
522			Entry entry = model.files[i];
523			Font font = entry.dirEntry.getType()
524				== VFSFile.FILE
525				? renderer.plainFont : renderer.boldFont;
526
527			widths[0] = Math.max(widths[0],renderer.getEntryWidth(
528				entry,font,fontRenderContext));
529		}
530
531		widths[0] += 10;
532
533		TableColumnModel columns = getColumnModel();
534
535		try
536		{
537			resizingColumns = true;
538			for(int i = 0; i < widths.length; i++)
539			{
540				columns.getColumn(i).setPreferredWidth(widths[i]);
541				columns.getColumn(i).setWidth(widths[i]);
542			}
543		}
544		finally
545		{
546			resizingColumns = false;
547		}
548
549		doLayout();
550	} //}}}
551
552	//{{{ saveWidths() method
553	private void saveWidths()
554	{
555		if(resizingColumns)
556			return;
557
558		VFSDirectoryEntryTableModel model = (VFSDirectoryEntryTableModel)getModel();
559		TableColumnModel columns = getColumnModel();
560
561		for(int i = 1; i < model.getColumnCount(); i++)
562			model.setColumnWidth(i,columns.getColumn(i).getWidth());
563	} //}}}
564
565	//}}}
566
567	//{{{ ClearTypeSelect class
568	class ClearTypeSelect implements ActionListener
569	{
570		public void actionPerformed(ActionEvent evt)
571		{
572			typeSelectBuffer.setLength(0);
573		}
574	} //}}}
575
576	//{{{ ColumnHandler class
577	class ColumnHandler implements TableColumnModelListener
578	{
579		public void columnAdded(TableColumnModelEvent e) {}
580		public void columnRemoved(TableColumnModelEvent e) {}
581		public void columnMoved(TableColumnModelEvent e) {}
582		public void columnSelectionChanged(ListSelectionEvent e) {}
583
584		public void columnMarginChanged(ChangeEvent e)
585		{
586			saveWidths();
587		}
588	} //}}}
589
590	//{{{ class MainMouseHandler
591	class MainMouseHandler extends MouseInputAdapter
592	{
593
594		@Override
595		public void mouseClicked(MouseEvent e)
596		{
597			super.mouseClicked(e);
598			int ind = getSelectionModel().getMinSelectionIndex();
599			if (ind == -1)
600				return;
601			Entry node = (Entry) getModel().getValueAt(ind, 0);
602			boolean isDir = node.dirEntry.getType() == VFSFile.DIRECTORY;
603			EditBus.send(new VFSPathSelected(jEdit.getActiveView(),
604							 node.dirEntry.getPath(), isDir));
605		}
606
607	} //}}}
608
609	//{{{ MouseHandler class
610	class MouseHandler extends MouseInputAdapter
611	{
612		@Override
613		public void mousePressed(MouseEvent evt)
614		{
615			// double click on columns header
616			if (evt.getSource() == header && evt.getClickCount() == 2)
617			{
618				VFSDirectoryEntryTableModel model = (VFSDirectoryEntryTableModel) header.getTable().getModel();
619				TableColumnModel columnModel = header.getColumnModel();
620				int viewColumn = columnModel.getColumnIndexAtX(evt.getX());
621				int column = columnModel.getColumn(viewColumn).getModelIndex();
622				saveWidths();
623				if(model.sortByColumn(column))
624				{
625					resizeColumns();
626					Log.log(Log.DEBUG,this,"VFSDirectoryEntryTable sorted by "
627					+ model.getColumnName(column)
628					+ (model.getAscending() ? " ascending" : " descending") );
629				}
630			}
631		}
632	} //}}}
633
634	//{{{ HeaderRenderer
635	static class HeaderRenderer extends DefaultTableCellRenderer
636	{
637		private final DefaultTableCellRenderer tcr;
638
639		HeaderRenderer(DefaultTableCellRenderer tcr)
640		{
641			this.tcr = tcr;
642		}
643
644		@Override
645		public Component getTableCellRendererComponent(JTable table, Object value,
646			boolean isSelected, boolean hasFocus, int row, int column)
647		{
648			JLabel l = (JLabel)tcr.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
649			VFSDirectoryEntryTableModel model = (VFSDirectoryEntryTableModel)table.getModel();
650			Icon icon = column == model.getSortColumn()
651				? model.getAscending() ? ASC_ICON : DESC_ICON
652				: null;
653			l.setIcon(icon);
654			// l.setHorizontalTextPosition(l.LEADING);
655			return l;
656		}
657	} //}}}
658
659	//{{{ SortOrder Icons
660
661	static final Icon ASC_ICON  = GUIUtilities.loadIcon("arrow-asc.png");
662	static final Icon DESC_ICON = GUIUtilities.loadIcon("arrow-desc.png");
663
664	//}}}
665
666}