/** * Returns <code>true</code> for regular files (not directories) with an <code>exe</code> * extension (case-insensitive comparison). * * @param file the file to test * @return <code>true</code> for regular files (not directories) with an <code>exe</code> * extension (case-insensitive comparison). */ @Override public boolean isApplication(AbstractFile file) { String extension = file.getExtension(); // the isDirectory() test comes last as it is I/O bound return extension != null && extension.equalsIgnoreCase("exe") && !file.isDirectory(); }
/** * Empty the trash * * <p><b>Implementation notes:</b><br> * Simply free the <code>TRASH_PATH</code> directory * * @return True if everything went well */ @Override public boolean empty() { // Abort if there is no usable trash folder if (TRASH_FOLDER == null) return false; FileSet filesToDelete = new FileSet(TRASH_FOLDER); try { // delete real files filesToDelete.addAll(TRASH_FILES_SUBFOLDER.ls()); // delete spec files filesToDelete.addAll(TRASH_INFO_SUBFOLDER.ls()); } catch (java.io.IOException ex) { LOGGER.debug("Failed to list files", ex); return false; } if (filesToDelete.size() > 0) { // Starts deleting files MainFrame mainFrame = WindowManager.getCurrentMainFrame(); ProgressDialog progressDialog = new ProgressDialog(mainFrame, Translator.get("delete_dialog.deleting")); DeleteJob deleteJob = new DeleteJob(progressDialog, mainFrame, filesToDelete, false); progressDialog.start(deleteJob); } return true; }
/** * Return <code>true</code> if the specified file is a Xfce Trash folder, i.e. is a directory and * has two subdirectories named "info" and "files". * * @param file the file to test * @return <code>true</code> if the specified file is a Xfce Trash folder */ private static boolean isTrashFolder(AbstractFile file) { try { return file.isDirectory() && file.getChild("info").isDirectory() && file.getChild("files").isDirectory(); } catch (IOException e) { return false; } }
/** * Resolves the user Trash folder and its "info" and "files" subfolders once and for all. The * trash folder is created if it doesn't already exist. */ static { TRASH_FOLDER = getTrashFolder(); if (TRASH_FOLDER != null) { TRASH_INFO_SUBFOLDER = TRASH_FOLDER.getChildSilently("info"); TRASH_FILES_SUBFOLDER = TRASH_FOLDER.getChildSilently("files"); TRASH_VOLUME = TRASH_FOLDER.getVolume(); } else { TRASH_INFO_SUBFOLDER = null; TRASH_FILES_SUBFOLDER = null; TRASH_VOLUME = null; } }
/** * Forces this monitor to update current folder information. This method should be called when a * folder has been manually refreshed, so that this monitor doesn't detect changes and try to * refresh the table again. * * @param folder the new current folder */ private void updateFolderInfo(AbstractFile folder) { this.currentFolder = folder; this.currentFolderDate = currentFolder.getDate(); // Reset time average totalCheckTime = 0; nbSamples = 0; }
public Vector<String> getPossibleCompletions(String path) { Vector<String> result = new Vector<String>(); int index = Math.max(path.lastIndexOf('\\'), path.lastIndexOf('/')); if (index != -1) { String currentDirectoryName = path.substring(0, index + 1); AbstractFile currentDirectory = FileFactory.getFile(currentDirectoryName); if (currentDirectory != null && currentDirectory.exists()) { long currentDirectoryDate = currentDirectory.getDate(); if (cachedDirectoryName == null || !cachedDirectoryName.equals(currentDirectoryName) || currentDirectoryDate != cachedDirectoryDate) { AbstractFile[] currentDirectoryFiles; try { currentDirectoryFiles = getFiles(currentDirectory); } catch (IOException e) { LOGGER.debug("Caught exception", e); return new Vector<String>(); } int nbCurrentDirectoryFiles = currentDirectoryFiles.length; cachedDirectoryFileNames = new String[nbCurrentDirectoryFiles]; for (int i = 0; i < nbCurrentDirectoryFiles; i++) { AbstractFile abstractFileI = currentDirectoryFiles[i]; cachedDirectoryFileNames[i] = abstractFileI.getName() + (abstractFileI.isDirectory() ? abstractFileI.getSeparator() : ""); } Arrays.sort(cachedDirectoryFileNames, String.CASE_INSENSITIVE_ORDER); cachedDirectoryName = currentDirectory.getAbsolutePath() + (currentDirectory.isDirectory() ? "" : currentDirectory.getSeparator()); cachedDirectoryDate = currentDirectoryDate; } final String prefix = index == path.length() - 1 ? null : path.substring(index + 1).toLowerCase(); result = PrefixFilter.createPrefixFilter(prefix).filter(cachedDirectoryFileNames); } } return result; }
/** * Checks if current file table's folder has changed and if it hasn't, checks if current folder's * date has changed and if it has, refresh the file table. * * @return <code>true</code> if the folder was refreshed. */ private synchronized boolean checkAndRefresh() { if (paused || disableAutoRefreshFilter.match(currentFolder)) { return false; } // Update time average next loop long timeStamp = System.currentTimeMillis(); // Check folder's date long date = currentFolder.getDate(); totalCheckTime += System.currentTimeMillis() - timeStamp; nbSamples++; // Has date changed ? // Note that date will be 0 if the folder is no longer available, and thus yield a refresh: this // is exactly // what we want (the folder will be changed to a 'workable' folder). if (date != currentFolderDate) { LOGGER.debug( this + " (" + currentFolder.getName() + ") Detected changes in current folder, refreshing table!"); // Try and refresh current folder in a separate thread as to not lock monitor thread folderPanel.tryRefreshCurrentFolder(); } if (!forceRefreshFilePath.isEmpty()) { synchronized (forceRefreshFilePath) { String folderPath = currentFolder.getAbsolutePath(); for (String path : forceRefreshFilePath) { if (path.startsWith(folderPath)) { forceRefreshFilePath.remove(path); folderPanel.tryRefreshCurrentFolder(); break; } } } } return false; }
/** * Make a content of .trashinfo file * * @param file File for which the content is built * @return Final content */ private String getFileInfoContent(AbstractFile file) { synchronized (INFO_DATE_FORMAT) { // SimpleDateFormat is not thread safe return "[Trash Info]\n" + "Path=" + file.getAbsolutePath() + "\n" + "DeletionDate=" + INFO_DATE_FORMAT.format(new Date()); } }
/** * Creates a returns a temporary local file/directory with the same extension as the specified * file/directory (guaranteed), and the same filename as much as possible (best effort). This * method returns <code>null</code> if the temporary file/directory could not be created. * * @param nonLocalFile the non-local file for which to create a temporary file. * @return a temporary local file/directory with the same extension as the specified * file/directory */ protected LocalFile createTempLocalFile(AbstractFile nonLocalFile) { try { // Note: the returned temporary file may be an AbstractArchiveFile if the filename's extension // corresponds // to a registered archive format LocalFile tempFile = FileFactory.getTemporaryFile(nonLocalFile.getName(), false).getAncestor(LocalFile.class); // create a directory if (nonLocalFile.isDirectory()) { tempFile.mkdir(); } else { // create a regular file tempFile.getOutputStream().close(); } return tempFile; } catch (IOException e) { return null; } }
/** * Return trash files count * * <p>We assume the count of items in trash equals the count of files in <code> * TRASH_PATH + "/info"</code> folder. * * @return Count of files in trash */ @Override public int getItemCount() { // Abort if there is no usable trash folder if (TRASH_FOLDER == null) return -1; try { return TRASH_INFO_SUBFOLDER.ls().length; } catch (java.io.IOException ex) { // can't access trash folder return -1; } }
/** * Updates this window's title to show currently active folder and window number. This method is * called by this class and WindowManager. */ public void updateWindowTitle() { // Update window title String title = activeTable.getFolderPanel().getCurrentFolder().getAbsolutePath(); // Add the application name to window title on all OSs except MAC if (!OsFamily.MAC_OS_X.isCurrent()) title += " - muCommander"; java.util.List<MainFrame> mainFrames = WindowManager.getMainFrames(); if (mainFrames.size() > 1) title += " [" + (mainFrames.indexOf(this) + 1) + "]"; setTitle(title); // Use new Window decorations introduced in Mac OS X 10.5 (Leopard) if (OsFamily.MAC_OS_X.isCurrent() && OsVersion.MAC_OS_X_10_5.isCurrentOrHigher()) { // Displays the document icon in the window title bar, works only for local files AbstractFile currentFolder = activeTable.getFolderPanel().getCurrentFolder(); Object javaIoFile; if (currentFolder.getURL().getScheme().equals(FileProtocols.FILE)) { // If the current folder is an archive entry, display the archive file, this is the closest // we can get // with a java.io.File if (currentFolder.hasAncestor(AbstractArchiveEntryFile.class)) javaIoFile = currentFolder.getParentArchive().getUnderlyingFileObject(); else javaIoFile = currentFolder.getUnderlyingFileObject(); } else { // If the current folder is not a local file, use the special /Network directory which is // sort of // 'Network Neighborhood'. javaIoFile = new java.io.File("/Network"); } // Note that for some strange reason (looks like a bug), setting the property to null won't // remove // the previous icon. getRootPane().putClientProperty("Window.documentFile", javaIoFile); } }
@Override public final boolean isFileOperationSupported(FileOperation op) { Class<? extends AbstractFile> thisClass = getClass(); Method opMethod = op.getCorrespondingMethod(thisClass); // If the method corresponding to the file operation has been overridden by this class (a // ProxyFile subclass), // check the presence of the UnsupportedFileOperation annotation in this class. try { if (!thisClass .getMethod(opMethod.getName(), opMethod.getParameterTypes()) .getDeclaringClass() .equals(ProxyFile.class)) { return AbstractFile.isFileOperationSupported(op, thisClass); } } catch (Exception e) { // Should never happen, unless AbstractFile method signatures have changed and FileOperation // has not been updated LOGGER.warn("Exception caught, this should not have happened", e); } // Otherwise, check for the presence of the UnsupportedFileOperation annotation in the wrapped // AbstractFile. return file.isFileOperationSupported(op); }
public FolderChangeMonitor(FolderPanel folderPanel) { this.folderPanel = folderPanel; // Listen to folder changes to know when a folder is being / has been changed folderPanel.getLocationManager().addLocationListener(this); this.currentFolder = folderPanel.getCurrentFolder(); this.currentFolderDate = currentFolder.getDate(); // Folder contents is up-to-date let's wait before checking it for changes this.lastCheckTimestamp = System.currentTimeMillis(); this.waitBeforeCheckTime = waitAfterRefresh; folderPanel.getMainFrame().addWindowListener(this); instances.add(this); // create and start the monitor thread on first FolderChangeMonitor instance if (monitorThread == null && checkPeriod >= 0) { monitorThread = new Thread(this, getClass().getName()); monitorThread.setDaemon(true); monitorThread.start(); } }
public Icon getFileIcon(AbstractFile originalFile, Dimension preferredResolution) { // Specified file is a LocalFile or a ProxyFile proxying a LocalFile (e.g. an archive file): // let's simply get // the icon using #getLocalFileIcon(LocalFile) AbstractFile topFile = originalFile.getTopAncestor(); Icon icon; if (topFile instanceof LocalFile) { icon = getLocalFileIcon((LocalFile) topFile, originalFile, preferredResolution); } // File is a remote file: create a temporary local file (or directory) with the same extension // to grab the icon // and then delete the file. This operation is I/O bound and thus expensive, so an LRU is used // to cache // frequently-accessed file extensions. else { // create the temporary, local file LocalFile tempFile = createTempLocalFile(topFile); if (tempFile == null) { // No temp file, no icon! return null; } // Get the file icon icon = getLocalFileIcon(tempFile, originalFile, preferredResolution); // Delete the temporary file try { tempFile.delete(); } catch (IOException e) { // Not much to do } } return icon; }
/** * It is possible to add several files with same name to the Trash. These files are distinguished * by _N appended to the name, where _N is rising int number. <br> * This method tries to find first empty <code>filename_N.ext</code>. * * @param file File to be deleted * @return Suitable filename in trash (without .trashinfo extension) */ private String getUniqueFilename(AbstractFile file) throws IOException { // try if no previous file in trash exists if (!TRASH_FILES_SUBFOLDER.getChild(file.getName()).exists()) return file.getName(); String rawName = file.getNameWithoutExtension(); String extension = file.getExtension(); // find first empty filename in format filename_N.ext String filename; int count = 1; while (true) { filename = rawName + "_" + count++; if (extension != null) { filename += "." + extension; } if (!TRASH_FILES_SUBFOLDER.getChild(filename).exists()) return filename; } }
/** * Tries to find an existing user Trash folder and returns it. If no existing Trash folder was * found, creates the standard Xfce user Trash folder and returns it. * * @return the user Trash folder, <code>null</code> if no user trash folder could be found or * created */ private static AbstractFile getTrashFolder() { AbstractFile userHome = LocalFile.getUserHome(); AbstractFile trashDir = userHome.getChildSilently(".local/share/Trash/"); if (isTrashFolder(trashDir)) { return trashDir; } // No existing user trash was found: create the folder, only if it doesn't already exist. if (!trashDir.exists()) { try { trashDir.mkdirs(); trashDir.getChild("info").mkdir(); trashDir.getChild("files").mkdir(); return trashDir; } catch (IOException e) { // Will return null } } return null; }
public boolean equals(Object f) { return file.equals(f); }
/** * Copies recursively the given file or folder. * * @param file the file or folder to move * @param recurseParams destination folder where the given file will be copied (null for top level * files) * @return <code>true</code> if the file has been copied. */ @Override protected boolean processFile(AbstractFile file, Object recurseParams) { // Stop if interrupted if (getState() == INTERRUPTED) return false; // Destination folder AbstractFile destFolder = recurseParams == null ? baseDestFolder : (AbstractFile) recurseParams; // Is current file in base folder ? boolean isFileInBaseFolder = files.indexOf(file) != -1; // Determine filename in destination String destFileName; if (isFileInBaseFolder && newName != null) destFileName = newName; else destFileName = file.getName(); // Create destination AbstractFile instance AbstractFile destFile = createDestinationFile(destFolder, destFileName); if (destFile == null) return false; currentDestFile = destFile; // Do nothing if file is a symlink (skip file and return) if (file.isSymlink()) return true; destFile = checkForCollision(file, destFolder, destFile, false); if (destFile == null) return false; // Copy directory recursively if (file.isDirectory()) { // Create the folder in the destination folder if it doesn't exist if (!(destFile.exists() && destFile.isDirectory())) { // Loop for retry do { try { destFile.mkdir(); } catch (IOException e) { // Unable to create folder int ret = showErrorDialog( errorDialogTitle, Translator.get("cannot_create_folder", destFileName)); // Retry loops if (ret == RETRY_ACTION) continue; // Cancel or close dialog return false return false; // Skip continues } break; } while (true); } // and copy each file in this folder recursively do { // Loop for retry try { // for each file in folder... AbstractFile subFiles[] = file.ls(); // filesDiscovered(subFiles); for (int i = 0; i < subFiles.length && getState() != INTERRUPTED; i++) { // Notify job that we're starting to process this file (needed for recursive calls to // processFile) nextFile(subFiles[i]); processFile(subFiles[i], destFile); } // Set currentDestFile back to the enclosing folder in case an overridden processFile // method // needs to work with the folder after calling super.processFile. currentDestFile = destFile; // Only when finished with folder, set destination folder's date to match the original // folder one if (destFile.isFileOperationSupported(FileOperation.CHANGE_DATE)) { try { destFile.changeDate(file.getDate()); } catch (IOException e) { AppLogger.fine("failed to change the date of " + destFile, e); // Fail silently } } return true; } catch (IOException e) { // file.ls() failed int ret = showErrorDialog( errorDialogTitle, Translator.get("cannot_read_folder", file.getName())); // Retry loops if (ret == RETRY_ACTION) continue; // Cancel, skip or close dialog returns false return false; } } while (true); } // File is a regular file, copy it else { // Copy the file return tryCopyFile(file, destFile, append, errorDialogTitle); } }
@Override public AbstractFile getParent() { return file.getParent(); }
@Override public long getSize() { return file.getSize(); }
@Override public void changeDate(long lastModified) throws IOException { file.changeDate(lastModified); }
@Override public long getDate() { return file.getDate(); }
/** * Creates a new ProxyFile using the given file to delegate AbstractFile method calls to. * * @param file the file to be proxied */ public ProxyFile(AbstractFile file) { super(file.getURL()); this.file = file; }
@Override public void changeReplication(short replication) throws IOException { file.changeReplication(replication); }
@Override public long getBlocksize() throws UnsupportedFileOperationException { return file.getBlocksize(); }
@Override public short getReplication() throws UnsupportedFileOperationException { return file.getReplication(); }
public String toString() { return file.toString(); }
public int hashCode() { return file.hashCode(); }
@Override public boolean equalsCanonical(Object f) { return file.equalsCanonical(f); }
@Override public void deleteRecursively() throws IOException { file.deleteRecursively(); }