PageRenderTime 41ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/io/VFS.java

#
Java | 1035 lines | 463 code | 100 blank | 472 comment | 67 complexity | d597803a2e2d111a5e4f4ab4ae7d4e5f MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * VFS.java - Virtual filesystem implementation
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 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. package org.gjt.sp.jedit.io;
  23. //{{{ Imports
  24. import gnu.regexp.*;
  25. import java.awt.Color;
  26. import java.awt.Component;
  27. import java.io.*;
  28. import java.util.*;
  29. import org.gjt.sp.jedit.buffer.BufferIORequest;
  30. import org.gjt.sp.jedit.msg.PropertiesChanged;
  31. import org.gjt.sp.jedit.*;
  32. import org.gjt.sp.util.Log;
  33. //}}}
  34. /**
  35. * A virtual filesystem implementation.<p>
  36. *
  37. * Plugins can provide virtual file systems by defining entries in their
  38. * <code>services.xml</code> files like so:
  39. *
  40. * <pre>&lt;SERVICE CLASS="org.gjt.sp.jedit.io.VFS" NAME="<i>name</i>"&gt;
  41. * new <i>MyVFS</i>();
  42. *&lt;/SERVICE&gt;</pre>
  43. *
  44. * URLs of the form <code><i>name</i>:<i>path</i></code> will then be handled
  45. * by the VFS named <code><i>name</i></code>.<p>
  46. *
  47. * See {@link org.gjt.sp.jedit.ServiceManager} for details.<p>
  48. *
  49. * <h3>Session objects:</h3>
  50. *
  51. * A session is used to persist things like login information, any network
  52. * sockets, etc. File system implementations that do not need this kind of
  53. * persistence return a dummy object as a session.<p>
  54. *
  55. * Methods whose names are prefixed with "_" expect to be given a
  56. * previously-obtained session object. A session must be obtained from the AWT
  57. * thread in one of two ways:
  58. *
  59. * <ul>
  60. * <li>{@link #createVFSSession(String,Component)}</li>
  61. * <li>{@link #showBrowseDialog(Object[],Component)}</li>
  62. * </ul>
  63. *
  64. * When done, the session must be disposed of using
  65. * {@link #_endVFSSession(Object,Component)}.<p>
  66. *
  67. * <h3>Thread safety:</h3>
  68. *
  69. * The following methods cannot be called from an I/O thread:
  70. *
  71. * <ul>
  72. * <li>{@link #createVFSSession(String,Component)}</li>
  73. * <li>{@link #insert(View,Buffer,String)}</li>
  74. * <li>{@link #load(View,Buffer,String)}</li>
  75. * <li>{@link #save(View,Buffer,String)}</li>
  76. * <li>{@link #showBrowseDialog(Object[],Component)}</li>
  77. * </ul>
  78. *
  79. * All remaining methods are required to be thread-safe in subclasses.
  80. *
  81. * <h3>Implementing a VFS</h3>
  82. *
  83. * You can override as many or as few methods as you want. Make sure
  84. * {@link #getCapabilities()} returns a value reflecting the functionality
  85. * implemented by your VFS.
  86. *
  87. * @see VFSManager#getVFSForPath(String)
  88. * @see VFSManager#getVFSForProtocol(String)
  89. *
  90. * @author Slava Pestov
  91. * @author $Id: VFS.java 4881 2003-09-08 01:24:11Z spestov $
  92. */
  93. public abstract class VFS
  94. {
  95. //{{{ Capabilities
  96. /**
  97. * Read capability.
  98. * @since jEdit 2.6pre2
  99. */
  100. public static final int READ_CAP = 1 << 0;
  101. /**
  102. * Write capability.
  103. * @since jEdit 2.6pre2
  104. */
  105. public static final int WRITE_CAP = 1 << 1;
  106. /**
  107. * @deprecated Do not define this capability.<p>
  108. *
  109. * This was the official API for adding items to a file
  110. * system browser's <b>Plugins</b> menu in jEdit 4.1 and earlier. In
  111. * jEdit 4.2, there is a different way of doing this, you must provide
  112. * a <code>browser.actions.xml</code> file in your plugin JAR, and
  113. * define <code>plugin.<i>class</i>.browser-menu-item</code>
  114. * or <code>plugin.<i>class</i>.browser-menu</code> properties.
  115. * See {@link org.gjt.sp.jedit.EditPlugin} for details.
  116. */
  117. public static final int BROWSE_CAP = 1 << 2;
  118. /**
  119. * Delete file capability.
  120. * @since jEdit 2.6pre2
  121. */
  122. public static final int DELETE_CAP = 1 << 3;
  123. /**
  124. * Rename file capability.
  125. * @since jEdit 2.6pre2
  126. */
  127. public static final int RENAME_CAP = 1 << 4;
  128. /**
  129. * Make directory capability.
  130. * @since jEdit 2.6pre2
  131. */
  132. public static final int MKDIR_CAP = 1 << 5;
  133. /**
  134. * Low latency capability. If this is not set, then a confirm dialog
  135. * will be shown before doing a directory search in this VFS.
  136. * @since jEdit 4.1pre1
  137. */
  138. public static final int LOW_LATENCY_CAP = 1 << 6;
  139. /**
  140. * Case insensitive file system capability.
  141. * @since jEdit 4.1pre1
  142. */
  143. public static final int CASE_INSENSITIVE_CAP = 1 << 7;
  144. //}}}
  145. //{{{ Extended attributes
  146. /**
  147. * File type.
  148. * @since jEdit 4.2pre1
  149. */
  150. public static final String EA_TYPE = "type";
  151. /**
  152. * File status (read only, read write, etc).
  153. * @since jEdit 4.2pre1
  154. */
  155. public static final String EA_STATUS = "status";
  156. /**
  157. * File size.
  158. * @since jEdit 4.2pre1
  159. */
  160. public static final String EA_SIZE = "size";
  161. /**
  162. * File last modified date.
  163. * @since jEdit 4.2pre1
  164. */
  165. public static final String EA_MODIFIED = "modified";
  166. //}}}
  167. //{{{ VFS constructor
  168. /**
  169. * @deprecated Use the form where the constructor takes a capability
  170. * list.
  171. */
  172. public VFS(String name)
  173. {
  174. this(name,0);
  175. } //}}}
  176. //{{{ VFS constructor
  177. /**
  178. * Creates a new virtual filesystem.
  179. * @param name The name
  180. * @param caps The capabilities
  181. */
  182. public VFS(String name, int caps)
  183. {
  184. this.name = name;
  185. this.caps = caps;
  186. // reasonable defaults (?)
  187. this.extAttrs = new String[] { EA_SIZE, EA_TYPE };
  188. } //}}}
  189. //{{{ VFS constructor
  190. /**
  191. * Creates a new virtual filesystem.
  192. * @param name The name
  193. * @param caps The capabilities
  194. * @param extAttrs The extended attributes
  195. * @since jEdit 4.2pre1
  196. */
  197. public VFS(String name, int caps, String[] extAttrs)
  198. {
  199. this.name = name;
  200. this.caps = caps;
  201. this.extAttrs = extAttrs;
  202. } //}}}
  203. //{{{ getName() method
  204. /**
  205. * Returns this VFS's name. The name is used to obtain the
  206. * label stored in the <code>vfs.<i>name</i>.label</code>
  207. * property.
  208. */
  209. public String getName()
  210. {
  211. return name;
  212. } //}}}
  213. //{{{ getCapabilities() method
  214. /**
  215. * Returns the capabilities of this VFS.
  216. * @since jEdit 2.6pre2
  217. */
  218. public int getCapabilities()
  219. {
  220. return caps;
  221. } //}}}
  222. //{{{ getExtendedAttributes() method
  223. /**
  224. * Returns the extended attributes supported by this VFS.
  225. * @since jEdit 4.2pre1
  226. */
  227. public String[] getExtendedAttributes()
  228. {
  229. return extAttrs;
  230. } //}}}
  231. //{{{ showBrowseDialog() method
  232. /**
  233. * Displays a dialog box that should set up a session and return
  234. * the initial URL to browse.
  235. * @param session Where the VFS session will be stored
  236. * @param comp The component that will parent error dialog boxes
  237. * @return The URL
  238. * @since jEdit 2.7pre1
  239. */
  240. public String showBrowseDialog(Object[] session, Component comp)
  241. {
  242. return null;
  243. } //}}}
  244. //{{{ getFileName() method
  245. /**
  246. * Returns the file name component of the specified path.
  247. * @param path The path
  248. * @since jEdit 3.1pre4
  249. */
  250. public String getFileName(String path)
  251. {
  252. if(path.equals("/"))
  253. return path;
  254. if(path.endsWith("/") || path.endsWith(File.separator))
  255. path = path.substring(0,path.length() - 1);
  256. int index = Math.max(path.lastIndexOf('/'),
  257. path.lastIndexOf(File.separatorChar));
  258. if(index == -1)
  259. index = path.indexOf(':');
  260. // don't want getFileName("roots:") to return ""
  261. if(index == -1 || index == path.length() - 1)
  262. return path;
  263. return path.substring(index + 1);
  264. } //}}}
  265. //{{{ getParentOfPath() method
  266. /**
  267. * Returns the parent of the specified path. This must be
  268. * overridden to return a non-null value for browsing of this
  269. * filesystem to work.
  270. * @param path The path
  271. * @since jEdit 2.6pre5
  272. */
  273. public String getParentOfPath(String path)
  274. {
  275. // ignore last character of path to properly handle
  276. // paths like /foo/bar/
  277. int count = Math.max(0,path.length() - 2);
  278. int index = path.lastIndexOf(File.separatorChar,count);
  279. if(index == -1)
  280. index = path.lastIndexOf('/',count);
  281. if(index == -1)
  282. {
  283. // this ensures that getFileParent("protocol:"), for
  284. // example, is "protocol:" and not "".
  285. index = path.lastIndexOf(':');
  286. }
  287. return path.substring(0,index + 1);
  288. } //}}}
  289. //{{{ constructPath() method
  290. /**
  291. * Constructs a path from the specified directory and
  292. * file name component. This must be overridden to return a
  293. * non-null value, otherwise browsing this filesystem will
  294. * not work.<p>
  295. *
  296. * Unless you are writing a VFS, this method should not be called
  297. * directly. To ensure correct behavior, you <b>must</b> call
  298. * {@link org.gjt.sp.jedit.MiscUtilities#constructPath(String,String)}
  299. * instead.
  300. *
  301. * @param parent The parent directory
  302. * @param path The path
  303. * @since jEdit 2.6pre2
  304. */
  305. public String constructPath(String parent, String path)
  306. {
  307. return parent + path;
  308. } //}}}
  309. //{{{ getFileSeparator() method
  310. /**
  311. * Returns the file separator used by this VFS.
  312. * @since jEdit 2.6pre9
  313. */
  314. public char getFileSeparator()
  315. {
  316. return '/';
  317. } //}}}
  318. //{{{ getTwoStageSaveName() method
  319. /**
  320. * Returns a temporary file name based on the given path.
  321. *
  322. * By default jEdit first saves a file to <code>#<i>name</i>#save#</code>
  323. * and then renames it to the original file. However some virtual file
  324. * systems might not support the <code>#</code> character in filenames,
  325. * so this method permits the VFS to override this behavior.
  326. *
  327. * @param path The path name
  328. * @since jEdit 4.1pre7
  329. */
  330. public String getTwoStageSaveName(String path)
  331. {
  332. return MiscUtilities.constructPath(getParentOfPath(path),
  333. '#' + getFileName(path) + "#save#");
  334. } //}}}
  335. //{{{ reloadDirectory() method
  336. /**
  337. * Called before a directory is reloaded by the file system browser.
  338. * Can be used to flush a cache, etc.
  339. * @since jEdit 4.0pre3
  340. */
  341. public void reloadDirectory(String path) {} //}}}
  342. //{{{ createVFSSession() method
  343. /**
  344. * Creates a VFS session. This method is called from the AWT thread,
  345. * so it should not do any I/O. It could, however, prompt for
  346. * a login name and password, for example.
  347. * @param path The path in question
  348. * @param comp The component that will parent any dialog boxes shown
  349. * @return The session
  350. * @since jEdit 2.6pre3
  351. */
  352. public Object createVFSSession(String path, Component comp)
  353. {
  354. return new Object();
  355. } //}}}
  356. //{{{ load() method
  357. /**
  358. * Loads the specified buffer. The default implementation posts
  359. * an I/O request to the I/O thread.
  360. * @param view The view
  361. * @param buffer The buffer
  362. * @param path The path
  363. */
  364. public boolean load(View view, Buffer buffer, String path)
  365. {
  366. if((getCapabilities() & READ_CAP) == 0)
  367. {
  368. VFSManager.error(view,path,"vfs.not-supported.load",new String[] { name });
  369. return false;
  370. }
  371. Object session = createVFSSession(path,view);
  372. if(session == null)
  373. return false;
  374. if((getCapabilities() & WRITE_CAP) == 0)
  375. buffer.setReadOnly(true);
  376. BufferIORequest request = new BufferIORequest(
  377. BufferIORequest.LOAD,view,buffer,session,this,path);
  378. if(buffer.isTemporary())
  379. // this makes HyperSearch much faster
  380. request.run();
  381. else
  382. VFSManager.runInWorkThread(request);
  383. return true;
  384. } //}}}
  385. //{{{ save() method
  386. /**
  387. * Saves the specifies buffer. The default implementation posts
  388. * an I/O request to the I/O thread.
  389. * @param view The view
  390. * @param buffer The buffer
  391. * @param path The path
  392. */
  393. public boolean save(View view, Buffer buffer, String path)
  394. {
  395. if((getCapabilities() & WRITE_CAP) == 0)
  396. {
  397. VFSManager.error(view,path,"vfs.not-supported.save",new String[] { name });
  398. return false;
  399. }
  400. Object session = createVFSSession(path,view);
  401. if(session == null)
  402. return false;
  403. /* When doing a 'save as', the path to save to (path)
  404. * will not be the same as the buffer's previous path
  405. * (buffer.getPath()). In that case, we want to create
  406. * a backup of the new path, even if the old path was
  407. * backed up as well (BACKED_UP property set) */
  408. if(!path.equals(buffer.getPath()))
  409. buffer.unsetProperty(Buffer.BACKED_UP);
  410. VFSManager.runInWorkThread(new BufferIORequest(
  411. BufferIORequest.SAVE,view,buffer,session,this,path));
  412. return true;
  413. } //}}}
  414. //{{{ insert() method
  415. /**
  416. * Inserts a file into the specified buffer. The default implementation
  417. * posts an I/O request to the I/O thread.
  418. * @param view The view
  419. * @param buffer The buffer
  420. * @param path The path
  421. */
  422. public boolean insert(View view, Buffer buffer, String path)
  423. {
  424. if((getCapabilities() & READ_CAP) == 0)
  425. {
  426. VFSManager.error(view,path,"vfs.not-supported.load",new String[] { name });
  427. return false;
  428. }
  429. Object session = createVFSSession(path,view);
  430. if(session == null)
  431. return false;
  432. VFSManager.runInWorkThread(new BufferIORequest(
  433. BufferIORequest.INSERT,view,buffer,session,this,path));
  434. return true;
  435. } //}}}
  436. // A method name that starts with _ requires a session object
  437. //{{{ _canonPath() method
  438. /**
  439. * Returns the canonical form of the specified path name. For example,
  440. * <code>~</code> might be expanded to the user's home directory.
  441. * @param session The session
  442. * @param path The path
  443. * @param comp The component that will parent error dialog boxes
  444. * @exception IOException if an I/O error occurred
  445. * @since jEdit 4.0pre2
  446. */
  447. public String _canonPath(Object session, String path, Component comp)
  448. throws IOException
  449. {
  450. return path;
  451. } //}}}
  452. //{{{ _listDirectory() method
  453. /**
  454. * A convinience method that matches file names against globs, and can
  455. * optionally list the directory recursively.
  456. * @param session The session
  457. * @param directory The directory. Note that this must be a full
  458. * URL, including the host name, path name, and so on. The
  459. * username and password (if needed by the VFS) is obtained from the
  460. * session instance.
  461. * @param glob Only file names matching this glob will be returned
  462. * @param recursive If true, subdirectories will also be listed.
  463. * @param comp The component that will parent error dialog boxes
  464. * @exception IOException if an I/O error occurred
  465. * @since jEdit 4.1pre1
  466. */
  467. public String[] _listDirectory(Object session, String directory,
  468. String glob, boolean recursive, Component comp)
  469. throws IOException
  470. {
  471. Log.log(Log.DEBUG,this,"Listing " + directory);
  472. ArrayList files = new ArrayList(100);
  473. RE filter;
  474. try
  475. {
  476. filter = new RE(MiscUtilities.globToRE(glob),
  477. RE.REG_ICASE);
  478. }
  479. catch(REException e)
  480. {
  481. Log.log(Log.ERROR,this,e);
  482. return null;
  483. }
  484. _listDirectory(session,new ArrayList(),files,directory,filter,
  485. recursive,comp);
  486. String[] retVal = (String[])files.toArray(new String[files.size()]);
  487. Arrays.sort(retVal,new MiscUtilities.StringICaseCompare());
  488. return retVal;
  489. } //}}}
  490. //{{{ _listDirectory() method
  491. /**
  492. * Lists the specified directory.
  493. * @param session The session
  494. * @param directory The directory. Note that this must be a full
  495. * URL, including the host name, path name, and so on. The
  496. * username and password (if needed by the VFS) is obtained from the
  497. * session instance.
  498. * @param comp The component that will parent error dialog boxes
  499. * @exception IOException if an I/O error occurred
  500. * @since jEdit 2.7pre1
  501. */
  502. public DirectoryEntry[] _listDirectory(Object session, String directory,
  503. Component comp)
  504. throws IOException
  505. {
  506. VFSManager.error(comp,directory,"vfs.not-supported.list",new String[] { name });
  507. return null;
  508. } //}}}
  509. //{{{ _getDirectoryEntry() method
  510. /**
  511. * Returns the specified directory entry.
  512. * @param session The session
  513. * @param path The path
  514. * @param comp The component that will parent error dialog boxes
  515. * @exception IOException if an I/O error occurred
  516. * @return The specified directory entry, or null if it doesn't exist.
  517. * @since jEdit 2.7pre1
  518. */
  519. public DirectoryEntry _getDirectoryEntry(Object session, String path,
  520. Component comp)
  521. throws IOException
  522. {
  523. return null;
  524. } //}}}
  525. //{{{ DirectoryEntry class
  526. /**
  527. * A directory entry.
  528. * @since jEdit 2.6pre2
  529. */
  530. public static class DirectoryEntry implements Serializable
  531. {
  532. //{{{ File types
  533. public static final int FILE = 0;
  534. public static final int DIRECTORY = 1;
  535. public static final int FILESYSTEM = 2;
  536. //}}}
  537. //{{{ Instance variables
  538. public String name;
  539. public String path;
  540. /**
  541. * @since jEdit 4.2pre5
  542. */
  543. public String symlinkPath;
  544. public String deletePath;
  545. public int type;
  546. public long length;
  547. public boolean hidden;
  548. public boolean canRead;
  549. public boolean canWrite;
  550. //}}}
  551. //{{{ DirectoryEntry constructor
  552. /**
  553. * @since jEdit 4.2pre2
  554. */
  555. public DirectoryEntry()
  556. {
  557. } //}}}
  558. //{{{ DirectoryEntry constructor
  559. public DirectoryEntry(String name, String path, String deletePath,
  560. int type, long length, boolean hidden)
  561. {
  562. this.name = name;
  563. this.path = path;
  564. this.deletePath = deletePath;
  565. this.symlinkPath = path;
  566. this.type = type;
  567. this.length = length;
  568. this.hidden = hidden;
  569. if(path != null)
  570. {
  571. // maintain backwards compatibility
  572. VFS vfs = VFSManager.getVFSForPath(path);
  573. canRead = ((vfs.getCapabilities() & READ_CAP) != 0);
  574. canWrite = ((vfs.getCapabilities() & WRITE_CAP) != 0);
  575. }
  576. } //}}}
  577. protected boolean colorCalculated;
  578. protected Color color;
  579. //{{{ getExtendedAttribute() method
  580. /**
  581. * Returns the value of an extended attribute. Note that this
  582. * returns formatted strings (eg, "10 Mb" for a file size of
  583. * 1048576 bytes). If you need access to the raw data, access
  584. * fields and methods of this class.
  585. * @param name The extended attribute name
  586. * @since jEdit 4.2pre1
  587. */
  588. public String getExtendedAttribute(String name)
  589. {
  590. if(name.equals(EA_TYPE))
  591. {
  592. switch(type)
  593. {
  594. case FILE:
  595. return jEdit.getProperty("vfs.browser.type.file");
  596. case DIRECTORY:
  597. return jEdit.getProperty("vfs.browser.type.directory");
  598. case FILESYSTEM:
  599. return jEdit.getProperty("vfs.browser.type.filesystem");
  600. default:
  601. throw new IllegalArgumentException();
  602. }
  603. }
  604. else if(name.equals(EA_STATUS))
  605. {
  606. if(canRead)
  607. {
  608. if(canWrite)
  609. return jEdit.getProperty("vfs.browser.status.rw");
  610. else
  611. return jEdit.getProperty("vfs.browser.status.ro");
  612. }
  613. else
  614. {
  615. if(canWrite)
  616. return jEdit.getProperty("vfs.browser.status.append");
  617. else
  618. return jEdit.getProperty("vfs.browser.status.no");
  619. }
  620. }
  621. else if(name.equals(EA_SIZE))
  622. {
  623. if(type != FILE)
  624. return null;
  625. else
  626. return MiscUtilities.formatFileSize(length);
  627. }
  628. else
  629. return null;
  630. } //}}}
  631. //{{{ getColor() method
  632. public Color getColor()
  633. {
  634. if(!colorCalculated)
  635. {
  636. colorCalculated = true;
  637. color = getDefaultColorFor(name);
  638. }
  639. return color;
  640. } //}}}
  641. //{{{ toString() method
  642. public String toString()
  643. {
  644. return name;
  645. } //}}}
  646. } //}}}
  647. //{{{ _delete() method
  648. /**
  649. * Deletes the specified URL.
  650. * @param session The VFS session
  651. * @param path The path
  652. * @param comp The component that will parent error dialog boxes
  653. * @exception IOException if an I/O error occurs
  654. * @since jEdit 2.7pre1
  655. */
  656. public boolean _delete(Object session, String path, Component comp)
  657. throws IOException
  658. {
  659. return false;
  660. } //}}}
  661. //{{{ _rename() method
  662. /**
  663. * Renames the specified URL. Some filesystems might support moving
  664. * URLs between directories, however others may not. Do not rely on
  665. * this behavior.
  666. * @param session The VFS session
  667. * @param from The old path
  668. * @param to The new path
  669. * @param comp The component that will parent error dialog boxes
  670. * @exception IOException if an I/O error occurs
  671. * @since jEdit 2.7pre1
  672. */
  673. public boolean _rename(Object session, String from, String to,
  674. Component comp) throws IOException
  675. {
  676. return false;
  677. } //}}}
  678. //{{{ _mkdir() method
  679. /**
  680. * Creates a new directory with the specified URL.
  681. * @param session The VFS session
  682. * @param directory The directory
  683. * @param comp The component that will parent error dialog boxes
  684. * @exception IOException if an I/O error occurs
  685. * @since jEdit 2.7pre1
  686. */
  687. public boolean _mkdir(Object session, String directory, Component comp)
  688. throws IOException
  689. {
  690. return false;
  691. } //}}}
  692. //{{{ _backup() method
  693. /**
  694. * Backs up the specified file. This should only be overriden by
  695. * the local filesystem VFS.
  696. * @param session The VFS session
  697. * @param path The path
  698. * @param comp The component that will parent error dialog boxes
  699. * @exception IOException if an I/O error occurs
  700. * @since jEdit 3.2pre2
  701. */
  702. public void _backup(Object session, String path, Component comp)
  703. throws IOException
  704. {
  705. } //}}}
  706. //{{{ _createInputStream() method
  707. /**
  708. * Creates an input stream. This method is called from the I/O
  709. * thread.
  710. * @param session the VFS session
  711. * @param path The path
  712. * @param ignoreErrors If true, file not found errors should be
  713. * ignored
  714. * @param comp The component that will parent error dialog boxes
  715. * @exception IOException If an I/O error occurs
  716. * @since jEdit 2.7pre1
  717. */
  718. public InputStream _createInputStream(Object session,
  719. String path, boolean ignoreErrors, Component comp)
  720. throws IOException
  721. {
  722. VFSManager.error(comp,path,"vfs.not-supported.load",new String[] { name });
  723. return null;
  724. } //}}}
  725. //{{{ _createOutputStream() method
  726. /**
  727. * Creates an output stream. This method is called from the I/O
  728. * thread.
  729. * @param session the VFS session
  730. * @param path The path
  731. * @param comp The component that will parent error dialog boxes
  732. * @exception IOException If an I/O error occurs
  733. * @since jEdit 2.7pre1
  734. */
  735. public OutputStream _createOutputStream(Object session,
  736. String path, Component comp)
  737. throws IOException
  738. {
  739. VFSManager.error(comp,path,"vfs.not-supported.save",new String[] { name });
  740. return null;
  741. } //}}}
  742. //{{{ _saveComplete() method
  743. /**
  744. * Called after a file has been saved.
  745. * @param session The VFS session
  746. * @param buffer The buffer
  747. * @param path The path the buffer was saved to (can be different from
  748. * {@link org.gjt.sp.jedit.Buffer#getPath()} if the user invoked the
  749. * <b>Save a Copy As</b> command, for example).
  750. * @param comp The component that will parent error dialog boxes
  751. * @exception IOException If an I/O error occurs
  752. * @since jEdit 4.1pre9
  753. */
  754. public void _saveComplete(Object session, Buffer buffer, String path,
  755. Component comp) throws IOException {} //}}}
  756. //{{{ _endVFSSession() method
  757. /**
  758. * Finishes the specified VFS session. This must be called
  759. * after all I/O with this VFS is complete, to avoid leaving
  760. * stale network connections and such.
  761. * @param session The VFS session
  762. * @param comp The component that will parent error dialog boxes
  763. * @exception IOException if an I/O error occurred
  764. * @since jEdit 2.7pre1
  765. */
  766. public void _endVFSSession(Object session, Component comp)
  767. throws IOException
  768. {
  769. } //}}}
  770. //{{{ getDefaultColorFor() method
  771. /**
  772. * Returns color of the specified file name, by matching it against
  773. * user-specified regular expressions.
  774. * @since jEdit 4.0pre1
  775. */
  776. public static Color getDefaultColorFor(String name)
  777. {
  778. synchronized(lock)
  779. {
  780. if(colors == null)
  781. loadColors();
  782. for(int i = 0; i < colors.size(); i++)
  783. {
  784. ColorEntry entry = (ColorEntry)colors.elementAt(i);
  785. if(entry.re.isMatch(name))
  786. return entry.color;
  787. }
  788. return null;
  789. }
  790. } //}}}
  791. //{{{ DirectoryEntryCompare class
  792. /**
  793. * Implementation of {@link org.gjt.sp.jedit.MiscUtilities.Compare}
  794. * interface that compares {@link VFS.DirectoryEntry} instances.
  795. * @since jEdit 4.2pre1
  796. */
  797. public static class DirectoryEntryCompare implements MiscUtilities.Compare
  798. {
  799. private boolean sortIgnoreCase, sortMixFilesAndDirs;
  800. /**
  801. * Creates a new <code>DirectoryEntryCompare</code>.
  802. * @param sortMixFilesAndDirs If false, directories are
  803. * put at the top of the listing.
  804. * @param sortIgnoreCase If false, upper case comes before
  805. * lower case.
  806. */
  807. public DirectoryEntryCompare(boolean sortMixFilesAndDirs,
  808. boolean sortIgnoreCase)
  809. {
  810. this.sortMixFilesAndDirs = sortMixFilesAndDirs;
  811. this.sortIgnoreCase = sortIgnoreCase;
  812. }
  813. public int compare(Object obj1, Object obj2)
  814. {
  815. VFS.DirectoryEntry file1 = (VFS.DirectoryEntry)obj1;
  816. VFS.DirectoryEntry file2 = (VFS.DirectoryEntry)obj2;
  817. if(!sortMixFilesAndDirs)
  818. {
  819. if(file1.type != file2.type)
  820. return file2.type - file1.type;
  821. }
  822. return MiscUtilities.compareStrings(file1.name,
  823. file2.name,sortIgnoreCase);
  824. }
  825. } //}}}
  826. //{{{ Private members
  827. private String name;
  828. private int caps;
  829. private String[] extAttrs;
  830. private static Vector colors;
  831. private static Object lock = new Object();
  832. //{{{ Class initializer
  833. static
  834. {
  835. EditBus.addToBus(new EBComponent()
  836. {
  837. public void handleMessage(EBMessage msg)
  838. {
  839. if(msg instanceof PropertiesChanged)
  840. {
  841. synchronized(lock)
  842. {
  843. colors = null;
  844. }
  845. }
  846. }
  847. });
  848. } //}}}
  849. //{{{ _listDirectory() method
  850. private void _listDirectory(Object session, ArrayList stack,
  851. ArrayList files, String directory, RE glob, boolean recursive,
  852. Component comp) throws IOException
  853. {
  854. if(stack.contains(directory))
  855. {
  856. Log.log(Log.ERROR,this,
  857. "Recursion in _listDirectory(): "
  858. + directory);
  859. return;
  860. }
  861. else
  862. stack.add(directory);
  863. VFS.DirectoryEntry[] _files = _listDirectory(session,directory,
  864. comp);
  865. if(_files == null || _files.length == 0)
  866. return;
  867. for(int i = 0; i < _files.length; i++)
  868. {
  869. VFS.DirectoryEntry file = _files[i];
  870. if(file.type == VFS.DirectoryEntry.DIRECTORY
  871. || file.type == VFS.DirectoryEntry.FILESYSTEM)
  872. {
  873. if(recursive)
  874. {
  875. // resolve symlinks to avoid loops
  876. String canonPath = _canonPath(session,file.path,comp);
  877. if(!MiscUtilities.isURL(canonPath))
  878. canonPath = MiscUtilities.resolveSymlinks(canonPath);
  879. _listDirectory(session,stack,files,
  880. canonPath,glob,recursive,
  881. comp);
  882. }
  883. }
  884. else
  885. {
  886. if(!glob.isMatch(file.name))
  887. continue;
  888. Log.log(Log.DEBUG,this,file.path);
  889. files.add(file.path);
  890. }
  891. }
  892. } //}}}
  893. //{{{ loadColors() method
  894. private static void loadColors()
  895. {
  896. synchronized(lock)
  897. {
  898. colors = new Vector();
  899. if(!jEdit.getBooleanProperty("vfs.browser.colorize"))
  900. return;
  901. String glob;
  902. int i = 0;
  903. while((glob = jEdit.getProperty("vfs.browser.colors." + i + ".glob")) != null)
  904. {
  905. try
  906. {
  907. colors.addElement(new ColorEntry(
  908. new RE(MiscUtilities.globToRE(glob)),
  909. jEdit.getColorProperty(
  910. "vfs.browser.colors." + i + ".color",
  911. Color.black)));
  912. }
  913. catch(REException e)
  914. {
  915. Log.log(Log.ERROR,VFS.class,"Invalid regular expression: "
  916. + glob);
  917. Log.log(Log.ERROR,VFS.class,e);
  918. }
  919. i++;
  920. }
  921. }
  922. } //}}}
  923. //{{{ ColorEntry class
  924. static class ColorEntry
  925. {
  926. RE re;
  927. Color color;
  928. ColorEntry(RE re, Color color)
  929. {
  930. this.re = re;
  931. this.color = color;
  932. }
  933. } //}}}
  934. //}}}
  935. }