0001: /*
0002: * VFSBrowser.java - VFS browser
0003: * :tabSize=8:indentSize=8:noTabs=false:
0004: * :folding=explicit:collapseFolds=1:
0005: *
0006: * Copyright (C) 2000, 2003 Slava Pestov
0007: *
0008: * This program is free software; you can redistribute it and/or
0009: * modify it under the terms of the GNU General Public License
0010: * as published by the Free Software Foundation; either version 2
0011: * of the License, or any later version.
0012: *
0013: * This program is distributed in the hope that it will be useful,
0014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0016: * GNU General Public License for more details.
0017: *
0018: * You should have received a copy of the GNU General Public License
0019: * along with this program; if not, write to the Free Software
0020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0021: */
0022:
0023: package org.gjt.sp.jedit.browser;
0024:
0025: //{{{ Imports
0026: import org.gjt.sp.jedit.bsh.*;
0027: import javax.swing.border.EmptyBorder;
0028: import javax.swing.event.*;
0029: import javax.swing.*;
0030: import java.awt.event.*;
0031: import java.awt.*;
0032: import java.io.File;
0033: import java.util.*;
0034: import java.util.List;
0035:
0036: import org.gjt.sp.jedit.io.*;
0037: import org.gjt.sp.jedit.gui.*;
0038: import org.gjt.sp.jedit.msg.*;
0039: import org.gjt.sp.jedit.search.*;
0040: import org.gjt.sp.jedit.*;
0041: import org.gjt.sp.jedit.buffer.JEditBuffer;
0042: import org.gjt.sp.util.Log;
0043:
0044: //}}}
0045:
0046: /**
0047: * The main class of the VFS browser.
0048: * @author Slava Pestov
0049: * @version $Id: VFSBrowser.java 10803 2007-10-04 20:45:31Z kpouer $
0050: */
0051: public class VFSBrowser extends JPanel implements EBComponent,
0052: DefaultFocusComponent, DockableWindow {
0053: public static final String NAME = "vfs.browser";
0054:
0055: //{{{ Browser types
0056: /**
0057: * Open file dialog mode. Equals JFileChooser.OPEN_DIALOG for
0058: * backwards compatibility.
0059: */
0060: public static final int OPEN_DIALOG = 0;
0061:
0062: /**
0063: * Save file dialog mode. Equals JFileChooser.SAVE_DIALOG for
0064: * backwards compatibility.
0065: */
0066: public static final int SAVE_DIALOG = 1;
0067: /**
0068: * Choose directory dialog mode.
0069: */
0070: public static final int BROWSER_DIALOG = 4;
0071: /**
0072: * Choose directory dialog mode.
0073: */
0074: public static final int CHOOSE_DIRECTORY_DIALOG = 3;
0075:
0076: /**
0077: * Stand-alone browser mode.
0078: */
0079: public static final int BROWSER = 2;
0080:
0081: //}}}
0082:
0083: //{{{ browseDirectoryInNewWindow() method
0084: /**
0085: * Opens the specified directory in a new, floating, file system browser.
0086: * @param view The view
0087: * @param path The directory's path
0088: * @since jEdit 4.1pre2
0089: */
0090: public static void browseDirectoryInNewWindow(View view, String path) {
0091: DockableWindowManager wm = view.getDockableWindowManager();
0092: if (path != null) {
0093: // this is such a bad way of doing it, but oh well...
0094: jEdit.setTemporaryProperty("vfs.browser.path.tmp", path);
0095: }
0096: wm.floatDockableWindow("vfs.browser");
0097: jEdit.unsetProperty("vfs.browser.path.tmp");
0098: } //}}}
0099:
0100: //{{{ browseDirectory() method
0101: /**
0102: * Opens the specified directory in a file system browser.
0103: * @param view The view
0104: * @param path The directory's path
0105: * @since jEdit 4.0pre3
0106: */
0107: public static void browseDirectory(View view, String path) {
0108: DockableWindowManager wm = view.getDockableWindowManager();
0109: VFSBrowser browser = (VFSBrowser) wm.getDockable(NAME);
0110: if (browser != null) {
0111: wm.showDockableWindow(NAME);
0112: browser.setDirectory(path);
0113: } else {
0114: if (path != null) {
0115: // this is such a bad way of doing it, but oh well...
0116: jEdit
0117: .setTemporaryProperty("vfs.browser.path.tmp",
0118: path);
0119: }
0120: wm.addDockableWindow("vfs.browser");
0121: jEdit.unsetProperty("vfs.browser.path.tmp");
0122: }
0123: } //}}}
0124:
0125: //{{{ getActionContext() method
0126: /**
0127: * Returns the browser action context.
0128: * @since jEdit 4.2pre1
0129: */
0130: public static ActionContext getActionContext() {
0131: return actionContext;
0132: } //}}}
0133:
0134: //{{{ VFSBrowser constructor
0135: /**
0136: * Creates a new VFS browser.
0137: * @param view The view to open buffers in by default
0138: */
0139: public VFSBrowser(View view, String position) {
0140: this (view, null, BROWSER, true, position);
0141: } //}}}
0142:
0143: //{{{ VFSBrowser constructor
0144: /**
0145: * Creates a new VFS browser.
0146: * @param view The view to open buffers in by default
0147: * @param path The path to display
0148: * @param mode The browser mode
0149: * @param multipleSelection True if multiple selection should be allowed
0150: * @param position Where the browser is located
0151: * @since jEdit 4.2pre1
0152: */
0153: public VFSBrowser(View view, String path, int mode,
0154: boolean multipleSelection, String position) {
0155: super (new BorderLayout());
0156:
0157: listenerList = new EventListenerList();
0158:
0159: this .mode = mode;
0160: this .multipleSelection = multipleSelection;
0161: this .view = view;
0162:
0163: DockableWindowManager dwm = view.getDockableWindowManager();
0164: KeyListener keyListener = dwm.closeListener(NAME);
0165: addKeyListener(keyListener);
0166:
0167: currentEncoding = jEdit.getProperty("buffer.encoding", System
0168: .getProperty("file.encoding"));
0169: autoDetectEncoding = jEdit
0170: .getBooleanProperty("buffer.encodingAutodetect");
0171:
0172: ActionHandler actionHandler = new ActionHandler();
0173:
0174: topBox = new Box(BoxLayout.Y_AXIS);
0175: horizontalLayout = (mode != BROWSER
0176: || DockableWindowManager.TOP.equals(position) || DockableWindowManager.BOTTOM
0177: .equals(position));
0178:
0179: toolbarBox = new Box(horizontalLayout ? BoxLayout.X_AXIS
0180: : BoxLayout.Y_AXIS);
0181:
0182: topBox.add(toolbarBox);
0183:
0184: GridBagLayout layout = new GridBagLayout();
0185: pathAndFilterPanel = new JPanel(layout);
0186:
0187: GridBagConstraints cons = new GridBagConstraints();
0188: cons.gridwidth = cons.gridheight = 1;
0189: cons.gridx = cons.gridy = 0;
0190: cons.fill = GridBagConstraints.BOTH;
0191: cons.anchor = GridBagConstraints.EAST;
0192: JLabel label = new JLabel(
0193: jEdit.getProperty("vfs.browser.path"),
0194: SwingConstants.RIGHT);
0195: label.setBorder(new EmptyBorder(0, 0, 0, 12));
0196: layout.setConstraints(label, cons);
0197: pathAndFilterPanel.add(label);
0198:
0199: pathField = new HistoryTextField("vfs.browser.path");
0200: pathField.addKeyListener(keyListener);
0201: pathField.setInstantPopups(true);
0202: pathField.setEnterAddsToHistory(false);
0203: pathField.setSelectAllOnFocus(true);
0204:
0205: // because its preferred size can be quite wide, we
0206: // don't want it to make the browser way too big,
0207: // so set the preferred width to 0.
0208: Dimension prefSize = pathField.getPreferredSize();
0209: prefSize.width = 0;
0210: pathField.setPreferredSize(prefSize);
0211: pathField.addActionListener(actionHandler);
0212: cons.gridx = 1;
0213: cons.weightx = 1;
0214: cons.gridwidth = GridBagConstraints.REMAINDER;
0215:
0216: layout.setConstraints(pathField, cons);
0217: pathAndFilterPanel.add(pathField);
0218:
0219: filterCheckbox = new JCheckBox(jEdit
0220: .getProperty("vfs.browser.filter"));
0221: filterCheckbox.setMargin(new Insets(0, 0, 0, 0));
0222: filterCheckbox.setRequestFocusEnabled(false);
0223: filterCheckbox.setBorder(new EmptyBorder(0, 0, 0, 12));
0224: filterCheckbox.setSelected(jEdit
0225: .getBooleanProperty("vfs.browser.filter-enabled"));
0226:
0227: filterCheckbox.addActionListener(actionHandler);
0228: filterCheckbox.addKeyListener(keyListener);
0229: if (mode != CHOOSE_DIRECTORY_DIALOG) {
0230: cons.gridwidth = 1;
0231: cons.gridx = 0;
0232: cons.weightx = 0;
0233: cons.gridy = 1;
0234: layout.setConstraints(filterCheckbox, cons);
0235: pathAndFilterPanel.add(filterCheckbox);
0236: }
0237:
0238: filterField = new JComboBox();
0239: filterEditor = new HistoryComboBoxEditor("vfs.browser.filter");
0240: filterEditor.setToolTipText(jEdit.getProperty("glob.tooltip"));
0241: filterEditor.setInstantPopups(true);
0242: filterEditor.setSelectAllOnFocus(true);
0243: filterEditor.addActionListener(actionHandler);
0244: filterEditor.addKeyListener(keyListener);
0245: String filter;
0246: if (mode == BROWSER
0247: || !jEdit
0248: .getBooleanProperty("vfs.browser.currentBufferFilter")) {
0249: filter = jEdit.getProperty("vfs.browser.last-filter");
0250: if (filter == null)
0251: filter = jEdit
0252: .getProperty("vfs.browser.default-filter");
0253: } else {
0254: String ext = MiscUtilities.getFileExtension(view
0255: .getBuffer().getName());
0256: if (ext.length() == 0)
0257: filter = jEdit
0258: .getProperty("vfs.browser.default-filter");
0259: else
0260: filter = '*' + ext;
0261: }
0262:
0263: // filterField.getEditor().setItem(new GlobVFSFileFilter(filter));
0264: // filterField.addItem(filterField.getEditor().getItem());
0265: filterEditor.setItem(new GlobVFSFileFilter(filter));
0266: filterField.addItem(filterEditor.getItem());
0267: filterField.addItemListener(actionHandler);
0268: filterField.setRenderer(new VFSFileFilterRenderer());
0269:
0270: // loads the registered VFSFileFilter services.
0271: String[] _filters = ServiceManager
0272: .getServiceNames(VFSFileFilter.SERVICE_NAME);
0273: for (int i = 0; i < _filters.length; i++) {
0274: VFSFileFilter _filter = (VFSFileFilter) ServiceManager
0275: .getService(VFSFileFilter.SERVICE_NAME, _filters[i]);
0276: filterField.addItem(_filter);
0277: }
0278:
0279: if (mode != CHOOSE_DIRECTORY_DIALOG) {
0280: cons.gridwidth = GridBagConstraints.REMAINDER;
0281: cons.fill = GridBagConstraints.HORIZONTAL;
0282: cons.gridx = 1;
0283: cons.weightx = 1;
0284: if (filterField.getItemCount() > 1) {
0285: filterField.setEditor(filterEditor);
0286: filterField.setEditable(true);
0287: layout.setConstraints(filterField, cons);
0288: pathAndFilterPanel.add(filterField);
0289: } else {
0290: layout.setConstraints(filterEditor, cons);
0291: pathAndFilterPanel.add(filterEditor);
0292: }
0293: }
0294:
0295: topBox.add(pathAndFilterPanel);
0296: add(BorderLayout.NORTH, topBox);
0297:
0298: add(BorderLayout.CENTER, browserView = new BrowserView(this ));
0299:
0300: propertiesChanged();
0301:
0302: updateFilterEnabled();
0303:
0304: setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
0305: // see VFSBrowser.browseDirectory()
0306: if (path == null)
0307: path = jEdit.getProperty("vfs.browser.path.tmp");
0308:
0309: if (path == null || path.length() == 0) {
0310: String userHome = System.getProperty("user.home");
0311: String defaultPath = jEdit
0312: .getProperty("vfs.browser.defaultPath");
0313: if (defaultPath.equals("home"))
0314: path = userHome;
0315: else if (defaultPath.equals("working"))
0316: path = System.getProperty("user.dir");
0317: else if (defaultPath.equals("buffer")) {
0318: Buffer buffer = view.getBuffer();
0319: path = buffer.getDirectory();
0320: } else if (defaultPath.equals("last")) {
0321: HistoryModel pathModel = HistoryModel
0322: .getModel("vfs.browser.path");
0323: if (pathModel.getSize() == 0)
0324: path = "~";
0325: else
0326: path = pathModel.getItem(0);
0327: } else if (defaultPath.equals("favorites"))
0328: path = "favorites:";
0329: else {
0330: // unknown value??!!!
0331: path = userHome;
0332: }
0333: }
0334:
0335: final String _path = path;
0336:
0337: SwingUtilities.invokeLater(new Runnable() {
0338: public void run() {
0339: setDirectory(_path);
0340: }
0341: });
0342: } //}}}
0343:
0344: //{{{ focusOnDefaultComponent() method
0345: public void focusOnDefaultComponent() {
0346: pathField.requestFocus();
0347: // browserView.focusOnFileView();
0348: } //}}}
0349:
0350: //{{{ addNotify() method
0351: public void addNotify() {
0352: super .addNotify();
0353: EditBus.addToBus(this );
0354: } //}}}
0355:
0356: //{{{ removeNotify() method
0357: public void removeNotify() {
0358: super .removeNotify();
0359: jEdit.setBooleanProperty("vfs.browser.filter-enabled",
0360: filterCheckbox.isSelected());
0361: if (mode == BROWSER
0362: || !jEdit
0363: .getBooleanProperty("vfs.browser.currentBufferFilter")) {
0364: VFSFileFilter selectedFilter = (VFSFileFilter) filterField
0365: .getSelectedItem();
0366: if (selectedFilter instanceof GlobVFSFileFilter)
0367: jEdit.setProperty("vfs.browser.last-filter",
0368: ((GlobVFSFileFilter) selectedFilter).getGlob());
0369: }
0370: EditBus.removeFromBus(this );
0371: } //}}}
0372:
0373: //{{{ handleMessage() method
0374: public void handleMessage(EBMessage msg) {
0375: if (msg instanceof PropertiesChanged)
0376: propertiesChanged();
0377: else if (msg instanceof BufferUpdate) {
0378: BufferUpdate bmsg = (BufferUpdate) msg;
0379: if (bmsg.getWhat() == BufferUpdate.CREATED
0380: || bmsg.getWhat() == BufferUpdate.CLOSED)
0381: browserView.updateFileView();
0382: } else if (msg instanceof PluginUpdate) {
0383: PluginUpdate pmsg = (PluginUpdate) msg;
0384: if ((pmsg.getWhat() == PluginUpdate.LOADED || pmsg
0385: .getWhat() == PluginUpdate.UNLOADED)
0386: && plugins != null /* plugins can be null if the VFSBrowser menu bar is hidden */) {
0387: plugins.updatePopupMenu();
0388: }
0389: } else if (msg instanceof VFSUpdate) {
0390: maybeReloadDirectory(((VFSUpdate) msg).getPath());
0391: }
0392: } //}}}
0393:
0394: //{{{ getView() method
0395: public View getView() {
0396: return view;
0397: } //}}}
0398:
0399: //{{{ getMode() method
0400: public int getMode() {
0401: return mode;
0402: } //}}}
0403:
0404: //{{{ isMultipleSelectionEnabled() method
0405: public boolean isMultipleSelectionEnabled() {
0406: return multipleSelection;
0407: } //}}}
0408:
0409: //{{{ isHorizontalLayout() method
0410: public boolean isHorizontalLayout() {
0411: return horizontalLayout;
0412: } //}}}
0413:
0414: //{{{ getShowHiddenFiles() method
0415: public boolean getShowHiddenFiles() {
0416: return showHiddenFiles;
0417: } //}}}
0418:
0419: //{{{ setShowHiddenFiles() method
0420: public void setShowHiddenFiles(boolean showHiddenFiles) {
0421: this .showHiddenFiles = showHiddenFiles;
0422: } //}}}
0423:
0424: //{{{ getFilenameFilter() method
0425: /**
0426: * Returns the file name filter glob.
0427: * @since jEdit 3.2pre2
0428: * @deprecated Use {@link #getVFSFileFilter()} instead. This method
0429: * might return wrong information since jEdit 4.3pre6.
0430: */
0431: public String getFilenameFilter() {
0432: if (filterCheckbox.isSelected()) {
0433: String filter = filterField.getSelectedItem().toString();
0434: if (filter.length() == 0)
0435: return "*";
0436: else
0437: return filter;
0438: } else
0439: return "*";
0440: } //}}}
0441:
0442: //{{{ getVFSFileFilter() method
0443: /**
0444: * Returns the currently active VFSFileFilter.
0445: *
0446: * @since jEdit 4.3pre7
0447: */
0448: public VFSFileFilter getVFSFileFilter() {
0449: if (mode == CHOOSE_DIRECTORY_DIALOG)
0450: return new DirectoriesOnlyFilter();
0451: return (VFSFileFilter) filterField.getSelectedItem();
0452: } //}}}
0453:
0454: //{{{ addVFSFileFilter() method
0455: /**
0456: * Adds a file filter to the browser.
0457: *
0458: * @since jEdit 4.3pre7
0459: */
0460: public void addVFSFileFilter(VFSFileFilter filter) {
0461: filterField.addItem(filter);
0462: if (filterField.getItemCount() == 2) {
0463: filterField.setEditor(filterEditor);
0464: filterField.setEditable(true);
0465:
0466: GridBagLayout layout = (GridBagLayout) pathAndFilterPanel
0467: .getLayout();
0468: GridBagConstraints cons = layout
0469: .getConstraints(filterEditor);
0470: cons.gridwidth = GridBagConstraints.REMAINDER;
0471: cons.fill = GridBagConstraints.HORIZONTAL;
0472: cons.gridx = 1;
0473: cons.weightx = 1;
0474:
0475: pathAndFilterPanel.remove(filterEditor);
0476: layout.setConstraints(filterField, cons);
0477: pathAndFilterPanel.add(filterField);
0478: pathAndFilterPanel.validate();
0479: pathAndFilterPanel.repaint();
0480: }
0481: } //}}}
0482:
0483: //{{{ setFilenameFilter() method
0484: public void setFilenameFilter(String filter) {
0485: if (filter == null || filter.length() == 0
0486: || filter.equals("*"))
0487: filterCheckbox.setSelected(false);
0488: else {
0489: filterCheckbox.setSelected(true);
0490: filterEditor.setItem(new GlobVFSFileFilter(filter));
0491: }
0492: } //}}}
0493:
0494: //{{{ getDirectoryField() method
0495: public HistoryTextField getDirectoryField() {
0496: return pathField;
0497: } //}}}
0498:
0499: //{{{ getDirectory() method
0500: public String getDirectory() {
0501: return path;
0502: } //}}}
0503:
0504: //{{{ setDirectory() method
0505: public void setDirectory(String path) {
0506: if (path.startsWith("file:"))
0507: path = path.substring(5);
0508: path = MiscUtilities.expandVariables(path);
0509: pathField.setText(path);
0510:
0511: if (!startRequest())
0512: return;
0513:
0514: browserView.saveExpansionState();
0515: browserView.loadDirectory(null, path, true);
0516: this .path = path;
0517:
0518: VFSManager.runInAWTThread(new Runnable() {
0519: public void run() {
0520: endRequest();
0521: }
0522: });
0523: } //}}}
0524:
0525: //{{{ getRootDirectory() method
0526: public static String getRootDirectory() {
0527: if (OperatingSystem.isMacOS() || OperatingSystem.isDOSDerived())
0528: return FileRootsVFS.PROTOCOL + ':';
0529: else
0530: return "/";
0531: } //}}}
0532:
0533: //{{{ rootDirectory() method
0534: /**
0535: * Goes to the local drives directory.
0536: * @since jEdit 4.0pre4
0537: */
0538: public void rootDirectory() {
0539: setDirectory(getRootDirectory());
0540: } //}}}
0541:
0542: //{{{ reloadDirectory() method
0543: public void reloadDirectory() {
0544: // used by FTP plugin to clear directory cache
0545: VFSManager.getVFSForPath(path).reloadDirectory(path);
0546:
0547: browserView.saveExpansionState();
0548: browserView.loadDirectory(null, path, false);
0549: } //}}}
0550:
0551: //{{{ delete() method
0552: /**
0553: * Note that all files must be on the same VFS.
0554: * @since jEdit 4.3pre2
0555: */
0556: public void delete(VFSFile[] files) {
0557: String dialogType;
0558:
0559: if (MiscUtilities.isURL(files[0].getDeletePath())
0560: && FavoritesVFS.PROTOCOL.equals(MiscUtilities
0561: .getProtocolOfURL(files[0].getDeletePath()))) {
0562: dialogType = "vfs.browser.delete-favorites";
0563: } else {
0564: dialogType = "vfs.browser.delete-confirm";
0565: }
0566:
0567: StringBuilder buf = new StringBuilder();
0568: String typeStr = "files";
0569: for (int i = 0; i < files.length; i++) {
0570: buf.append(files[i].getPath());
0571: buf.append('\n');
0572: if (files[i].getType() == VFSFile.DIRECTORY)
0573: typeStr = "directories and their contents";
0574: }
0575:
0576: Object[] args = { buf.toString(), typeStr };
0577:
0578: int result = GUIUtilities.confirm(this , dialogType, args,
0579: JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
0580: if (result != JOptionPane.YES_OPTION)
0581: return;
0582:
0583: VFS vfs = VFSManager.getVFSForPath(files[0].getDeletePath());
0584:
0585: if (!startRequest())
0586: return;
0587:
0588: for (int i = 0; i < files.length; i++) {
0589: Object session = vfs.createVFSSession(files[i]
0590: .getDeletePath(), this );
0591: if (session == null)
0592: continue;
0593:
0594: VFSManager.runInWorkThread(new BrowserIORequest(
0595: BrowserIORequest.DELETE, this , session, vfs,
0596: files[i].getDeletePath(), null, null));
0597: }
0598:
0599: VFSManager.runInAWTThread(new Runnable() {
0600: public void run() {
0601: endRequest();
0602: }
0603: });
0604: } //}}}
0605:
0606: //{{{ rename() method
0607: public void rename(String from) {
0608: VFS vfs = VFSManager.getVFSForPath(from);
0609:
0610: String filename = vfs.getFileName(from);
0611: String[] args = { filename };
0612: String to = GUIUtilities.input(this , "vfs.browser.rename",
0613: args, filename);
0614: if (to == null)
0615: return;
0616:
0617: to = MiscUtilities.constructPath(vfs.getParentOfPath(from), to);
0618:
0619: Object session = vfs.createVFSSession(from, this );
0620: if (session == null)
0621: return;
0622:
0623: if (!startRequest())
0624: return;
0625:
0626: VFSManager.runInWorkThread(new BrowserIORequest(
0627: BrowserIORequest.RENAME, this , session, vfs, from, to,
0628: null));
0629:
0630: VFSManager.runInAWTThread(new Runnable() {
0631: public void run() {
0632: endRequest();
0633: }
0634: });
0635: } //}}}
0636:
0637: //{{{ mkdir() method
0638: public void mkdir() {
0639: String newDirectory = GUIUtilities.input(this ,
0640: "vfs.browser.mkdir", null);
0641: if (newDirectory == null)
0642: return;
0643:
0644: // if a directory is selected, create new dir in there.
0645: // if a file is selected, create new dir inside its parent.
0646: VFSFile[] selected = getSelectedFiles();
0647: String parent;
0648: if (selected.length == 0)
0649: parent = path;
0650: else if (selected[0].getType() == VFSFile.FILE) {
0651: parent = selected[0].getPath();
0652: parent = VFSManager.getVFSForPath(parent).getParentOfPath(
0653: parent);
0654: } else
0655: parent = selected[0].getPath();
0656:
0657: VFS vfs = VFSManager.getVFSForPath(parent);
0658:
0659: // path is the currently viewed directory in the browser
0660: newDirectory = MiscUtilities
0661: .constructPath(parent, newDirectory);
0662:
0663: Object session = vfs.createVFSSession(newDirectory, this );
0664: if (session == null)
0665: return;
0666:
0667: if (!startRequest())
0668: return;
0669:
0670: VFSManager.runInWorkThread(new BrowserIORequest(
0671: BrowserIORequest.MKDIR, this , session, vfs,
0672: newDirectory, null, null));
0673:
0674: VFSManager.runInAWTThread(new Runnable() {
0675: public void run() {
0676: endRequest();
0677: }
0678: });
0679: } //}}}
0680:
0681: //{{{ newFile() method
0682: /**
0683: * Creates a new file in the current directory.
0684: * @since jEdit 4.0pre2
0685: */
0686: public void newFile() {
0687: VFSFile[] selected = getSelectedFiles();
0688: if (selected.length >= 1) {
0689: VFSFile file = selected[0];
0690: if (file.getType() == VFSFile.DIRECTORY)
0691: jEdit.newFile(view, file.getPath());
0692: else {
0693: VFS vfs = VFSManager.getVFSForPath(file.getPath());
0694: jEdit
0695: .newFile(view, vfs.getParentOfPath(file
0696: .getPath()));
0697: }
0698: } else
0699: jEdit.newFile(view, path);
0700: } //}}}
0701:
0702: //{{{ searchInDirectory() method
0703: /**
0704: * Opens a directory search in the current directory.
0705: * @since jEdit 4.0pre2
0706: */
0707: public void searchInDirectory() {
0708: VFSFile[] selected = getSelectedFiles();
0709: if (selected.length >= 1) {
0710: VFSFile file = selected[0];
0711: searchInDirectory(file.getPath(),
0712: file.getType() != VFSFile.FILE);
0713: } else {
0714: searchInDirectory(path, true);
0715: }
0716: } //}}}
0717:
0718: //{{{ searchInDirectory() method
0719: /**
0720: * Opens a directory search in the specified directory.
0721: * @param path The path name
0722: * @param directory True if the path is a directory, false if it is a file
0723: * @since jEdit 4.2pre1
0724: */
0725: public void searchInDirectory(String path, boolean directory) {
0726: String filter;
0727: VFSFileFilter vfsff = getVFSFileFilter();
0728: if (vfsff instanceof GlobVFSFileFilter)
0729: filter = ((GlobVFSFileFilter) vfsff).getGlob();
0730: else
0731: filter = "*";
0732:
0733: if (!directory) {
0734: String name = MiscUtilities.getFileName(path);
0735: String ext = MiscUtilities.getFileExtension(name);
0736: filter = (ext == null || ext.length() == 0 ? filter
0737: : '*' + ext);
0738: path = MiscUtilities.getParentOfPath(path);
0739: }
0740:
0741: SearchAndReplace.setSearchFileSet(new DirectoryListSet(path,
0742: filter, true));
0743: SearchDialog.showSearchDialog(view, null,
0744: SearchDialog.DIRECTORY);
0745: } //}}}
0746:
0747: //{{{ getBrowserView() method
0748: public BrowserView getBrowserView() {
0749: return browserView;
0750: } //}}}
0751:
0752: //{{{ getSelectedFiles() method
0753: /**
0754: * @since jEdit 4.3pre2
0755: */
0756: public VFSFile[] getSelectedFiles() {
0757: return browserView.getSelectedFiles();
0758: } //}}}
0759:
0760: //{{{ locateFile() method
0761: /**
0762: * Goes to the given file's directory and selects the file in the list.
0763: * @param path The file
0764: * @since jEdit 4.2pre2
0765: */
0766: public void locateFile(final String path) {
0767: VFSFileFilter filter = getVFSFileFilter();
0768: if (!filter.accept(MiscUtilities.getFileName(path)))
0769: setFilenameFilter(null);
0770:
0771: setDirectory(MiscUtilities.getParentOfPath(path));
0772: VFSManager.runInAWTThread(new Runnable() {
0773: public void run() {
0774: browserView.getTable().selectFile(path);
0775: }
0776: });
0777: } //}}}
0778:
0779: //{{{ createPluginsMenu() method
0780: public JComponent createPluginsMenu(JComponent pluginMenu,
0781: boolean showManagerOptions) {
0782: ActionHandler actionHandler = new ActionHandler();
0783: if (showManagerOptions && getMode() == BROWSER) {
0784: pluginMenu.add(GUIUtilities.loadMenuItem("plugin-manager",
0785: false));
0786: pluginMenu.add(GUIUtilities.loadMenuItem("plugin-options",
0787: false));
0788: if (pluginMenu instanceof JMenu)
0789: ((JMenu) pluginMenu).addSeparator();
0790: else if (pluginMenu instanceof JPopupMenu)
0791: ((JPopupMenu) pluginMenu).addSeparator();
0792:
0793: } else
0794: /* we're in a modal dialog */;
0795:
0796: List<JMenuItem> vec = new ArrayList<JMenuItem>();
0797:
0798: //{{{ old API
0799: Enumeration<VFS> e = VFSManager.getFilesystems();
0800:
0801: while (e.hasMoreElements()) {
0802: VFS vfs = (VFS) e.nextElement();
0803: if ((vfs.getCapabilities() & VFS.BROWSE_CAP) == 0)
0804: continue;
0805:
0806: JMenuItem menuItem = new JMenuItem(jEdit.getProperty("vfs."
0807: + vfs.getName() + ".label"));
0808: menuItem.setActionCommand(vfs.getName());
0809: menuItem.addActionListener(actionHandler);
0810: vec.add(menuItem);
0811: } //}}}
0812:
0813: //{{{ new API
0814: EditPlugin[] plugins = jEdit.getPlugins();
0815: for (int i = 0; i < plugins.length; i++) {
0816: JMenuItem menuItem = plugins[i].createBrowserMenuItems();
0817: if (menuItem != null)
0818: vec.add(menuItem);
0819: } //}}}
0820:
0821: if (!vec.isEmpty()) {
0822: Collections.sort(vec, new MiscUtilities.MenuItemCompare());
0823: for (int i = 0; i < vec.size(); i++)
0824: pluginMenu.add(vec.get(i));
0825: } else {
0826: JMenuItem mi = new JMenuItem(
0827: jEdit
0828: .getProperty("vfs.browser.plugins.no-plugins.label"));
0829: mi.setEnabled(false);
0830: pluginMenu.add(mi);
0831: }
0832:
0833: return pluginMenu;
0834: } //}}}
0835:
0836: //{{{ addBrowserListener() method
0837: public void addBrowserListener(BrowserListener l) {
0838: listenerList.add(BrowserListener.class, l);
0839: } //}}}
0840:
0841: //{{{ removeBrowserListener() method
0842: public void removeBrowserListener(BrowserListener l) {
0843: listenerList.remove(BrowserListener.class, l);
0844: } //}}}
0845:
0846: //{{{ filesActivated() method
0847: // canDoubleClickClose set to false when ENTER pressed
0848: public static final int M_OPEN = 0;
0849: public static final int M_OPEN_NEW_VIEW = 1;
0850: public static final int M_OPEN_NEW_PLAIN_VIEW = 2;
0851: public static final int M_OPEN_NEW_SPLIT = 3;
0852: public static final int M_INSERT = 4;
0853:
0854: /**
0855: * This method does the "double-click" handling. It is public so that
0856: * <code>browser.actions.xml</code> can bind to it.
0857: * @since jEdit 4.2pre2
0858: */
0859: public void filesActivated(int mode, boolean canDoubleClickClose) {
0860: VFSFile[] selectedFiles = browserView.getSelectedFiles();
0861:
0862: Buffer buffer = null;
0863:
0864: check_selected: for (int i = 0; i < selectedFiles.length; i++) {
0865: VFSFile file = selectedFiles[i];
0866:
0867: if (file.getType() == VFSFile.DIRECTORY
0868: || file.getType() == VFSFile.FILESYSTEM) {
0869: if (mode == M_OPEN_NEW_VIEW && this .mode == BROWSER)
0870: browseDirectoryInNewWindow(view, file.getPath());
0871: else
0872: setDirectory(file.getPath());
0873: } else if (this .mode == BROWSER
0874: || this .mode == BROWSER_DIALOG) {
0875: if (mode == M_INSERT) {
0876: view.getBuffer().insertFile(view, file.getPath());
0877: continue check_selected;
0878: }
0879:
0880: Buffer _buffer = jEdit.getBuffer(file.getPath());
0881: if (_buffer == null) {
0882: Hashtable props = new Hashtable();
0883: props.put(JEditBuffer.ENCODING, currentEncoding);
0884: props.put(Buffer.ENCODING_AUTODETECT, Boolean
0885: .valueOf(autoDetectEncoding));
0886: _buffer = jEdit.openFile(view, null,
0887: file.getPath(), false, props);
0888: } else if (doubleClickClose && canDoubleClickClose
0889: && this .mode != BROWSER_DIALOG
0890: && selectedFiles.length == 1) {
0891: // close if this buffer is currently
0892: // visible in the view.
0893: EditPane[] editPanes = view.getEditPanes();
0894: for (int j = 0; j < editPanes.length; j++) {
0895: if (editPanes[j].getBuffer() == _buffer) {
0896: jEdit.closeBuffer(view, _buffer);
0897: return;
0898: }
0899: }
0900: }
0901:
0902: if (_buffer != null)
0903: buffer = _buffer;
0904: } else {
0905: // if a file is selected in OPEN_DIALOG or
0906: // SAVE_DIALOG mode, just let the listener(s)
0907: // handle it
0908: }
0909: }
0910:
0911: if (buffer != null) {
0912: switch (mode) {
0913: case M_OPEN:
0914: view.setBuffer(buffer);
0915: break;
0916: case M_OPEN_NEW_VIEW:
0917: jEdit.newView(view, buffer, false);
0918: break;
0919: case M_OPEN_NEW_PLAIN_VIEW:
0920: jEdit.newView(view, buffer, true);
0921: break;
0922: case M_OPEN_NEW_SPLIT:
0923: view.splitHorizontally().setBuffer(buffer);
0924: break;
0925: }
0926: }
0927:
0928: Object[] listeners = listenerList.getListenerList();
0929: for (int i = 0; i < listeners.length; i++) {
0930: if (listeners[i] == BrowserListener.class) {
0931: BrowserListener l = (BrowserListener) listeners[i + 1];
0932: l.filesActivated(this , selectedFiles);
0933: }
0934: }
0935: } //}}}
0936:
0937: //{{{ move() method
0938: public void move(String newPosition) {
0939: boolean horz = (mode != BROWSER
0940: || DockableWindowManager.TOP.equals(newPosition) || DockableWindowManager.BOTTOM
0941: .equals(newPosition));
0942: if (horz == horizontalLayout)
0943: return;
0944: horizontalLayout = horz;
0945: topBox.remove(toolbarBox);
0946: toolbarBox = new Box(horizontalLayout ? BoxLayout.X_AXIS
0947: : BoxLayout.Y_AXIS);
0948: topBox.add(toolbarBox, 0);
0949: propertiesChanged();
0950: } //}}}
0951:
0952: //{{{ Package-private members
0953: String currentEncoding;
0954: boolean autoDetectEncoding;
0955:
0956: //{{{ directoryLoaded() method
0957: void directoryLoaded(Object node, Object[] loadInfo,
0958: boolean addToHistory) {
0959: VFSManager.runInAWTThread(new DirectoryLoadedAWTRequest(node,
0960: loadInfo, addToHistory));
0961: } //}}}
0962:
0963: //{{{ filesSelected() method
0964: void filesSelected() {
0965: VFSFile[] selectedFiles = browserView.getSelectedFiles();
0966:
0967: if (mode == BROWSER) {
0968: for (int i = 0; i < selectedFiles.length; i++) {
0969: VFSFile file = selectedFiles[i];
0970: Buffer buffer = jEdit.getBuffer(file.getPath());
0971: if (buffer != null && view != null)
0972: view.setBuffer(buffer);
0973: }
0974: }
0975:
0976: Object[] listeners = listenerList.getListenerList();
0977: for (int i = 0; i < listeners.length; i++) {
0978: if (listeners[i] == BrowserListener.class) {
0979: BrowserListener l = (BrowserListener) listeners[i + 1];
0980: l.filesSelected(this , selectedFiles);
0981: }
0982: }
0983: } //}}}
0984:
0985: //{{{ endRequest() method
0986: void endRequest() {
0987: requestRunning = false;
0988: } //}}}
0989:
0990: //}}}
0991:
0992: //{{{ Private members
0993:
0994: private static ActionContext actionContext;
0995:
0996: static {
0997: actionContext = new BrowserActionContext();
0998:
0999: ActionSet builtInActionSet = new ActionSet(null, null, null,
1000: jEdit.class.getResource("browser.actions.xml"));
1001: builtInActionSet.setLabel(jEdit
1002: .getProperty("action-set.browser"));
1003: builtInActionSet.load();
1004: actionContext.addActionSet(builtInActionSet);
1005: }
1006:
1007: //{{{ Instance variables
1008: private EventListenerList listenerList;
1009: private View view;
1010: private boolean horizontalLayout;
1011: private String path;
1012: private JPanel pathAndFilterPanel;
1013: private HistoryTextField pathField;
1014: private JCheckBox filterCheckbox;
1015: private HistoryComboBoxEditor filterEditor;
1016: private JComboBox filterField;
1017: private Box toolbarBox;
1018: private Box topBox;
1019: private FavoritesMenuButton favorites;
1020: private PluginsMenuButton plugins;
1021: private BrowserView browserView;
1022: private int mode;
1023: private boolean multipleSelection;
1024:
1025: private boolean showHiddenFiles;
1026: private boolean sortMixFilesAndDirs;
1027: private boolean sortIgnoreCase;
1028: private boolean doubleClickClose;
1029:
1030: private boolean requestRunning;
1031: private boolean maybeReloadRequestRunning;
1032:
1033: //}}}
1034:
1035: //{{{ createMenuBar() method
1036: private JPanel createMenuBar() {
1037: JPanel menuBar = new JPanel();
1038: menuBar.setLayout(new BoxLayout(menuBar, BoxLayout.X_AXIS));
1039: menuBar.setBorder(new EmptyBorder(0, 1, 0, 3));
1040:
1041: menuBar.add(new CommandsMenuButton());
1042: menuBar.add(Box.createHorizontalStrut(3));
1043: menuBar.add(plugins = new PluginsMenuButton());
1044: menuBar.add(Box.createHorizontalStrut(3));
1045: menuBar.add(favorites = new FavoritesMenuButton());
1046:
1047: return menuBar;
1048: } //}}}
1049:
1050: //{{{ createToolBar() method
1051: private Box createToolBar() {
1052: if (mode == BROWSER)
1053: return GUIUtilities.loadToolBar(actionContext,
1054: "vfs.browser.toolbar-browser");
1055: else
1056: return GUIUtilities.loadToolBar(actionContext,
1057: "vfs.browser.toolbar-dialog");
1058: } //}}}
1059:
1060: //{{{ propertiesChanged() method
1061: private void propertiesChanged() {
1062: showHiddenFiles = jEdit
1063: .getBooleanProperty("vfs.browser.showHiddenFiles");
1064: sortMixFilesAndDirs = jEdit
1065: .getBooleanProperty("vfs.browser.sortMixFilesAndDirs");
1066: sortIgnoreCase = jEdit
1067: .getBooleanProperty("vfs.browser.sortIgnoreCase");
1068: doubleClickClose = jEdit
1069: .getBooleanProperty("vfs.browser.doubleClickClose");
1070:
1071: browserView.propertiesChanged();
1072:
1073: toolbarBox.removeAll();
1074:
1075: if (jEdit.getBooleanProperty("vfs.browser.showToolbar")) {
1076: Box toolbar = createToolBar();
1077: if (horizontalLayout)
1078: toolbarBox.add(toolbar);
1079: else {
1080: toolbar.add(Box.createGlue());
1081: toolbarBox.add(toolbar);
1082: }
1083: }
1084:
1085: if (jEdit.getBooleanProperty("vfs.browser.showMenubar")) {
1086: JPanel menubar = createMenuBar();
1087: if (horizontalLayout) {
1088: toolbarBox.add(Box.createHorizontalStrut(6));
1089: toolbarBox.add(menubar, 0);
1090: } else {
1091: menubar.add(Box.createGlue());
1092: toolbarBox.add(menubar);
1093: }
1094: } else {
1095: plugins = null;
1096: favorites = null;
1097: }
1098:
1099: toolbarBox.add(Box.createGlue());
1100:
1101: revalidate();
1102:
1103: if (path != null)
1104: reloadDirectory();
1105: } //}}}
1106:
1107: /* We do this stuff because the browser is not able to handle
1108: * more than one request yet */
1109:
1110: //{{{ startRequest() method
1111: private boolean startRequest() {
1112: if (requestRunning) {
1113: // dump stack trace for debugging purposes
1114: Log.log(Log.DEBUG, this , new Throwable(
1115: "For debugging purposes"));
1116:
1117: GUIUtilities.error(this , "browser-multiple-io", null);
1118: return false;
1119: } else {
1120: requestRunning = true;
1121: return true;
1122: }
1123: } //}}}
1124:
1125: //{{{ updateFilterEnabled() method
1126: private void updateFilterEnabled() {
1127: filterField.setEnabled(filterCheckbox.isSelected());
1128: filterEditor.setEnabled(filterCheckbox.isSelected());
1129: } //}}}
1130:
1131: //{{{ maybeReloadDirectory() method
1132: private void maybeReloadDirectory(String dir) {
1133: if (MiscUtilities.isURL(dir)
1134: && MiscUtilities.getProtocolOfURL(dir).equals(
1135: FavoritesVFS.PROTOCOL)) {
1136: if (favorites != null)
1137: favorites.popup = null;
1138: }
1139:
1140: // this is a dirty hack and it relies on the fact
1141: // that updates for parents are sent before updates
1142: // for the changed nodes themselves (if this was not
1143: // the case, the browser wouldn't be updated properly
1144: // on delete, etc).
1145: //
1146: // to avoid causing '> 1 request' errors, don't reload
1147: // directory if request already active
1148: if (maybeReloadRequestRunning) {
1149: //Log.log(Log.WARNING,this,"VFS update: request already in progress");
1150: return;
1151: }
1152:
1153: // save a file -> sends vfs update. if a VFS file dialog box
1154: // is shown from the same event frame as the save, the
1155: // VFSUpdate will be delivered before the directory is loaded,
1156: // and before the path is set.
1157: if (path != null) {
1158: try {
1159: maybeReloadRequestRunning = true;
1160:
1161: browserView.maybeReloadDirectory(dir);
1162: } finally {
1163: VFSManager.runInAWTThread(new Runnable() {
1164: public void run() {
1165: maybeReloadRequestRunning = false;
1166: }
1167: });
1168: }
1169: }
1170: } //}}}
1171:
1172: //}}}
1173:
1174: //{{{ Inner classes
1175:
1176: //{{{ ActionHandler class
1177: class ActionHandler implements ActionListener, ItemListener {
1178: public void actionPerformed(ActionEvent evt) {
1179: if (isProcessingEvent)
1180: return;
1181:
1182: Object source = evt.getSource();
1183:
1184: if (source == pathField || source == filterCheckbox) {
1185: isProcessingEvent = true;
1186: resetLater();
1187:
1188: updateFilterEnabled();
1189:
1190: String p = pathField.getText();
1191:
1192: if (p != null)
1193: setDirectory(p);
1194: browserView.focusOnFileView();
1195: }
1196:
1197: else if (source == filterField.getEditor()) {
1198: // force the editor to refresh.
1199: filterField.getEditor().setItem(
1200: filterField.getEditor().getItem());
1201: }
1202:
1203: // depending on Swing look & feel, filterField.getEditor()
1204: // returns some ComboBoxUI
1205: else if (source == filterEditor) {
1206: // force the editor to refresh.
1207: filterEditor.setItem(filterEditor.getItem());
1208: filterField.setSelectedItem(filterEditor.getItem());
1209: // ### ugly:
1210: // itemStateChanged does not seem to get fired
1211: itemStateChanged(new ItemEvent(filterField,
1212: ItemEvent.ITEM_STATE_CHANGED, filterEditor
1213: .getItem(), ItemEvent.SELECTED));
1214: }
1215: }
1216:
1217: public void itemStateChanged(ItemEvent e) {
1218: if (isProcessingEvent)
1219: return;
1220:
1221: if (e.getStateChange() != ItemEvent.SELECTED)
1222: return;
1223:
1224: isProcessingEvent = true;
1225: resetLater();
1226:
1227: filterField
1228: .setEditable(e.getItem() instanceof GlobVFSFileFilter);
1229: updateFilterEnabled();
1230: String path = pathField.getText();
1231: if (path != null)
1232: setDirectory(path);
1233:
1234: browserView.focusOnFileView();
1235: }
1236:
1237: /**
1238: * Why this method exists: since both actionPerformed()
1239: * and itemStateChanged() above can change the combo box,
1240: * executing one of them can cause a chain reaction causing
1241: * the other method to be called. This would cause the
1242: * VFS subsystem to be called several times, which would
1243: * cause a warning to show up if the first operation is
1244: * still in progress, or cause a second operation to happen
1245: * which is not really wanted especially if we're talking
1246: * about a remove VFS. So the methods set a flag saying
1247: * that something is going on, and this method resets
1248: * the flag after the AWT thread is done with the
1249: * current events.
1250: */
1251: private void resetLater() {
1252: SwingUtilities.invokeLater(new Runnable() {
1253: public void run() {
1254: isProcessingEvent = false;
1255: }
1256: });
1257: }
1258:
1259: private boolean isProcessingEvent;
1260:
1261: } //}}}
1262:
1263: //{{{ CommandsMenuButton class
1264: class CommandsMenuButton extends JButton {
1265: //{{{ CommandsMenuButton constructor
1266: CommandsMenuButton() {
1267: setText(jEdit.getProperty("vfs.browser.commands.label"));
1268: setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1269: setHorizontalTextPosition(SwingConstants.LEADING);
1270:
1271: popup = new BrowserCommandsMenu(VFSBrowser.this , null);
1272:
1273: CommandsMenuButton.this .setRequestFocusEnabled(false);
1274: setMargin(new Insets(1, 1, 1, 1));
1275: CommandsMenuButton.this
1276: .addMouseListener(new MouseHandler());
1277:
1278: if (OperatingSystem.isMacOSLF())
1279: CommandsMenuButton.this .putClientProperty(
1280: "JButton.buttonType", "toolbar");
1281: } //}}}
1282:
1283: BrowserCommandsMenu popup;
1284:
1285: //{{{ MouseHandler class
1286: class MouseHandler extends MouseAdapter {
1287: public void mousePressed(MouseEvent evt) {
1288: if (!popup.isVisible()) {
1289: popup.update();
1290:
1291: GUIUtilities.showPopupMenu(popup,
1292: CommandsMenuButton.this , 0,
1293: CommandsMenuButton.this .getHeight(), false);
1294: } else {
1295: popup.setVisible(false);
1296: }
1297: }
1298: } //}}}
1299: } //}}}
1300:
1301: //{{{ PluginsMenuButton class
1302: class PluginsMenuButton extends JButton {
1303: //{{{ PluginsMenuButton constructor
1304: PluginsMenuButton() {
1305: setText(jEdit.getProperty("vfs.browser.plugins.label"));
1306: setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1307: setHorizontalTextPosition(SwingConstants.LEADING);
1308:
1309: PluginsMenuButton.this .setRequestFocusEnabled(false);
1310: setMargin(new Insets(1, 1, 1, 1));
1311: PluginsMenuButton.this .addMouseListener(new MouseHandler());
1312:
1313: if (OperatingSystem.isMacOSLF())
1314: PluginsMenuButton.this .putClientProperty(
1315: "JButton.buttonType", "toolbar");
1316: } //}}}
1317:
1318: JPopupMenu popup;
1319:
1320: //{{{ updatePopupMenu() method
1321: void updatePopupMenu() {
1322: popup = null;
1323: } //}}}
1324:
1325: //{{{ createPopupMenu() method
1326: private void createPopupMenu() {
1327: if (popup != null)
1328: return;
1329:
1330: popup = (JPopupMenu) createPluginsMenu(new JPopupMenu(),
1331: true);
1332: } //}}}
1333:
1334: //{{{ MouseHandler class
1335: class MouseHandler extends MouseAdapter {
1336: public void mousePressed(MouseEvent evt) {
1337: createPopupMenu();
1338:
1339: if (!popup.isVisible()) {
1340: GUIUtilities.showPopupMenu(popup,
1341: PluginsMenuButton.this , 0,
1342: PluginsMenuButton.this .getHeight(), false);
1343: } else {
1344: popup.setVisible(false);
1345: }
1346: }
1347: } //}}}
1348: } //}}}
1349:
1350: //{{{ FavoritesMenuButton class
1351: class FavoritesMenuButton extends JButton {
1352: //{{{ FavoritesMenuButton constructor
1353: FavoritesMenuButton() {
1354: setText(jEdit.getProperty("vfs.browser.favorites.label"));
1355: setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1356: setHorizontalTextPosition(SwingConstants.LEADING);
1357:
1358: FavoritesMenuButton.this .setRequestFocusEnabled(false);
1359: setMargin(new Insets(1, 1, 1, 1));
1360: FavoritesMenuButton.this
1361: .addMouseListener(new MouseHandler());
1362:
1363: if (OperatingSystem.isMacOSLF())
1364: FavoritesMenuButton.this .putClientProperty(
1365: "JButton.buttonType", "toolbar");
1366: } //}}}
1367:
1368: JPopupMenu popup;
1369:
1370: //{{{ createPopupMenu() method
1371: void createPopupMenu() {
1372: popup = new JPopupMenu();
1373: ActionHandler actionHandler = new ActionHandler();
1374:
1375: JMenuItem mi = new JMenuItem(jEdit
1376: .getProperty("vfs.browser.favorites"
1377: + ".add-to-favorites.label"));
1378: mi.setActionCommand("add-to-favorites");
1379: mi.addActionListener(actionHandler);
1380: popup.add(mi);
1381:
1382: mi = new JMenuItem(jEdit
1383: .getProperty("vfs.browser.favorites"
1384: + ".edit-favorites.label"));
1385: mi.setActionCommand("dir@favorites:");
1386: mi.addActionListener(actionHandler);
1387: popup.add(mi);
1388:
1389: popup.addSeparator();
1390:
1391: VFSFile[] favorites = FavoritesVFS.getFavorites();
1392: if (favorites.length == 0) {
1393: mi = new JMenuItem(jEdit
1394: .getProperty("vfs.browser.favorites"
1395: + ".no-favorites.label"));
1396: mi.setEnabled(false);
1397: popup.add(mi);
1398: } else {
1399: Arrays.sort(favorites, new VFS.DirectoryEntryCompare(
1400: sortMixFilesAndDirs, sortIgnoreCase));
1401: for (int i = 0; i < favorites.length; i++) {
1402: VFSFile favorite = favorites[i];
1403: mi = new JMenuItem(favorite.getPath());
1404: mi.setIcon(FileCellRenderer.getIconForFile(
1405: favorite, false));
1406: String cmd = (favorite.getType() == VFSFile.FILE ? "file@"
1407: : "dir@")
1408: + favorite.getPath();
1409: mi.setActionCommand(cmd);
1410: mi.addActionListener(actionHandler);
1411: popup.add(mi);
1412: }
1413: }
1414: } //}}}
1415:
1416: //{{{ ActionHandler class
1417: class ActionHandler implements ActionListener {
1418: public void actionPerformed(ActionEvent evt) {
1419: String actionCommand = evt.getActionCommand();
1420: if (actionCommand.equals("add-to-favorites")) {
1421: // if any directories are selected, add
1422: // them, otherwise add current directory
1423: VFSFile[] selected = getSelectedFiles();
1424: if (selected == null || selected.length == 0) {
1425: if (path.equals(FavoritesVFS.PROTOCOL + ':')) {
1426: GUIUtilities.error(VFSBrowser.this ,
1427: "vfs.browser.recurse-favorites",
1428: null);
1429: } else {
1430: FavoritesVFS.addToFavorites(path,
1431: VFSFile.DIRECTORY);
1432: }
1433: } else {
1434: for (int i = 0; i < selected.length; i++) {
1435: VFSFile file = selected[i];
1436: FavoritesVFS.addToFavorites(file.getPath(),
1437: file.getType());
1438: }
1439: }
1440: } else if (actionCommand.startsWith("dir@")) {
1441: setDirectory(actionCommand.substring(4));
1442: } else if (actionCommand.startsWith("file@")) {
1443: switch (getMode()) {
1444: case BROWSER:
1445: jEdit
1446: .openFile(view, actionCommand
1447: .substring(5));
1448: break;
1449: default:
1450: locateFile(actionCommand.substring(5));
1451: break;
1452: }
1453: }
1454: }
1455: } //}}}
1456:
1457: //{{{ MouseHandler class
1458: class MouseHandler extends MouseAdapter {
1459: public void mousePressed(MouseEvent evt) {
1460: if (popup != null && popup.isVisible()) {
1461: popup.setVisible(false);
1462: return;
1463: }
1464:
1465: if (popup == null)
1466: createPopupMenu();
1467:
1468: GUIUtilities.showPopupMenu(popup,
1469: FavoritesMenuButton.this , 0,
1470: FavoritesMenuButton.this .getHeight(), false);
1471: }
1472: } //}}}
1473: } //}}}
1474:
1475: //{{{ DirectoryLoadedAWTRequest class
1476: class DirectoryLoadedAWTRequest implements Runnable {
1477: private Object node;
1478: private Object[] loadInfo;
1479: private boolean addToHistory;
1480:
1481: DirectoryLoadedAWTRequest(Object node, Object[] loadInfo,
1482: boolean addToHistory) {
1483: this .node = node;
1484: this .loadInfo = loadInfo;
1485: this .addToHistory = addToHistory;
1486: }
1487:
1488: public void run() {
1489: String path = (String) loadInfo[0];
1490: if (path == null) {
1491: // there was an error
1492: return;
1493: }
1494:
1495: VFSFile[] list = (VFSFile[]) loadInfo[1];
1496:
1497: if (node == null) {
1498: // This is the new, canonical path
1499: VFSBrowser.this .path = path;
1500: if (!pathField.getText().equals(path))
1501: pathField.setText(path);
1502: if (path.endsWith("/") || path.endsWith(File.separator)) {
1503: // ensure consistent history;
1504: // eg we don't want both
1505: // foo/ and foo
1506: path = path.substring(0, path.length() - 1);
1507: }
1508:
1509: if (addToHistory) {
1510: HistoryModel.getModel("vfs.browser.path").addItem(
1511: path);
1512: }
1513: }
1514:
1515: boolean filterEnabled = filterCheckbox.isSelected();
1516:
1517: ArrayList<VFSFile> directoryVector = new ArrayList<VFSFile>();
1518:
1519: int directories = 0;
1520: int files = 0;
1521: int invisible = 0;
1522:
1523: if (list != null) {
1524: VFSFileFilter filter = getVFSFileFilter();
1525:
1526: for (int i = 0; i < list.length; i++) {
1527: VFSFile file = list[i];
1528: if (file.isHidden() && !showHiddenFiles) {
1529: invisible++;
1530: continue;
1531: }
1532:
1533: if (filter != null
1534: && (filterEnabled || filter instanceof DirectoriesOnlyFilter)
1535: && !filter.accept(file)) {
1536: invisible++;
1537: continue;
1538: }
1539:
1540: if (file.getType() == VFSFile.FILE)
1541: files++;
1542: else
1543: directories++;
1544:
1545: directoryVector.add(file);
1546: }
1547:
1548: Collections.sort(directoryVector,
1549: new VFS.DirectoryEntryCompare(
1550: sortMixFilesAndDirs, sortIgnoreCase));
1551: }
1552:
1553: browserView.directoryLoaded(node, path, directoryVector);
1554:
1555: // to notify listeners that any existing
1556: // selection has been deactivated
1557:
1558: // turns out under some circumstances this
1559: // method can switch the current buffer in
1560: // BROWSER mode.
1561:
1562: // in any case, this is only needed for the
1563: // directory chooser (why?), so we add a
1564: // check. otherwise poor Rick will go insane.
1565: if (mode == CHOOSE_DIRECTORY_DIALOG)
1566: filesSelected();
1567: }
1568:
1569: public String toString() {
1570: return (String) loadInfo[0];
1571: }
1572: } //}}}
1573:
1574: //{{{ BrowserActionContext class
1575: static class BrowserActionContext extends ActionContext {
1576: /**
1577: * If event source hierarchy contains a VFSDirectoryEntryTable,
1578: * this is the currently selected files there. Otherwise, this
1579: * is the currently selected item in the parent directory list.
1580: */
1581: private static VFSFile[] getSelectedFiles(EventObject evt,
1582: VFSBrowser browser) {
1583: Component source = (Component) evt.getSource();
1584:
1585: if (GUIUtilities.getComponentParent(source, JList.class) != null) {
1586: Object[] selected = browser.getBrowserView()
1587: .getParentDirectoryList().getSelectedValues();
1588: VFSFile[] returnValue = new VFSFile[selected.length];
1589: System.arraycopy(selected, 0, returnValue, 0,
1590: selected.length);
1591: return returnValue;
1592: } else {
1593: return browser.getSelectedFiles();
1594: }
1595: }
1596:
1597: public void invokeAction(EventObject evt, EditAction action) {
1598: VFSBrowser browser = (VFSBrowser) GUIUtilities
1599: .getComponentParent((Component) evt.getSource(),
1600: VFSBrowser.class);
1601:
1602: VFSFile[] files = getSelectedFiles(evt, browser);
1603:
1604: // in the future we will want something better,
1605: // eg. having an 'evt' object passed to
1606: // EditAction.invoke().
1607:
1608: // for now, since all browser actions are
1609: // written in beanshell we set the 'browser'
1610: // variable directly.
1611: NameSpace global = BeanShell.getNameSpace();
1612: try {
1613: global.setVariable("browser", browser);
1614: global.setVariable("files", files);
1615:
1616: View view = browser.getView();
1617: // I guess ideally all browsers
1618: // should have views, but since they
1619: // don't, we just use the active view
1620: // in that case, since some actions
1621: // depend on a view being there and
1622: // I don't want to add checks to
1623: // them all
1624: if (view == null)
1625: view = jEdit.getActiveView();
1626: action.invoke(view);
1627: } catch (UtilEvalError err) {
1628: Log.log(Log.ERROR, this , err);
1629: } finally {
1630: try {
1631: global.setVariable("browser", null);
1632: global.setVariable("files", null);
1633: } catch (UtilEvalError err) {
1634: Log.log(Log.ERROR, this , err);
1635: }
1636: }
1637: }
1638: } //}}}
1639:
1640: //{{{ HistoryComboBoxEditor class
1641: private static class HistoryComboBoxEditor extends HistoryTextField
1642: implements ComboBoxEditor {
1643:
1644: HistoryComboBoxEditor(String key) {
1645: super (key);
1646: }
1647:
1648: public Object getItem() {
1649: if (current == null) {
1650: current = new GlobVFSFileFilter(getText());
1651: }
1652:
1653: if (!current.getGlob().equals(getText())) {
1654: current.setGlob(getText());
1655: }
1656:
1657: return current;
1658: }
1659:
1660: public void setItem(Object item) {
1661: if (item == current) {
1662: // if we keep the same object, swing
1663: // will cause an event to be fired
1664: // on the default button of the dialog,
1665: // causing a beep since no file is
1666: // selected...
1667: if (item != null) {
1668: GlobVFSFileFilter filter = (GlobVFSFileFilter) item;
1669: current = new GlobVFSFileFilter(filter.getGlob());
1670: setText(current.getGlob());
1671: }
1672: return;
1673: }
1674:
1675: // this happens when changing the selected item
1676: // in the combo; the combo has not yet fired an
1677: // itemStateChanged() event, so it's not put into
1678: // non-editable mode by the handler above.
1679: if (!(item instanceof GlobVFSFileFilter))
1680: return;
1681:
1682: if (item != null) {
1683: GlobVFSFileFilter filter = (GlobVFSFileFilter) item;
1684: filter = new GlobVFSFileFilter(filter.getGlob());
1685: setText(filter.getGlob());
1686: addCurrentToHistory();
1687: current = filter;
1688: } else {
1689: setText("*");
1690: current = new GlobVFSFileFilter("*");
1691: }
1692: }
1693:
1694: protected void processFocusEvent(FocusEvent e) {
1695: // AWT will call setItem() when the editor loses
1696: // focus; that can cause weird and unwanted things
1697: // to happen, so ignore lost focus events.
1698: if (e.getID() != FocusEvent.FOCUS_LOST)
1699: super .processFocusEvent(e);
1700: else {
1701: setCaretPosition(0);
1702: getCaret().setVisible(false);
1703: }
1704: }
1705:
1706: public Component getEditorComponent() {
1707: return this ;
1708: }
1709:
1710: private GlobVFSFileFilter current;
1711:
1712: } //}}}
1713:
1714: //{{{ VFSFileFilterRenderer class
1715: private static class VFSFileFilterRenderer extends
1716: DefaultListCellRenderer {
1717:
1718: public Component getListCellRendererComponent(JList list,
1719: Object value, int index, boolean isSelected,
1720: boolean cellHasFocus) {
1721: assert value instanceof VFSFileFilter : "Filter is not a VFSFileFilter";
1722: super .getListCellRendererComponent(list, value, index,
1723: isSelected, cellHasFocus);
1724: setText(((VFSFileFilter) value).getDescription());
1725: return this ;
1726: }
1727:
1728: } //}}}
1729:
1730: //{{{ DirectoriesOnlyFilter class
1731: public static class DirectoriesOnlyFilter implements VFSFileFilter {
1732:
1733: public boolean accept(VFSFile file) {
1734: return file.getType() == VFSFile.DIRECTORY
1735: || file.getType() == VFSFile.FILESYSTEM;
1736: }
1737:
1738: public boolean accept(String url) {
1739: return false;
1740: }
1741:
1742: public String getDescription() {
1743: return jEdit
1744: .getProperty("vfs.browser.file_filter.dir_only");
1745: }
1746:
1747: } //}}}
1748:
1749: //}}}
1750: }
|