/*
 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.awt.shell;

import javax.swing.*;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.*;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.concurrent.Callable;

Author:Michael Martak
Since:1.4
/** * @author Michael Martak * @since 1.4 */
public abstract class ShellFolder extends File { private static final String COLUMN_NAME = "FileChooser.fileNameHeaderText"; private static final String COLUMN_SIZE = "FileChooser.fileSizeHeaderText"; private static final String COLUMN_DATE = "FileChooser.fileDateHeaderText"; protected ShellFolder parent;
Create a file system shell folder from a file
/** * Create a file system shell folder from a file */
ShellFolder(ShellFolder parent, String pathname) { super((pathname != null) ? pathname : "ShellFolder"); this.parent = parent; }
Returns:Whether this is a file system shell folder
/** * @return Whether this is a file system shell folder */
public boolean isFileSystem() { return (!getPath().startsWith("ShellFolder")); }
This method must be implemented to make sure that no instances of ShellFolder are ever serialized. If isFileSystem() returns true, then the object should be representable with an instance of java.io.File instead. If not, then the object is most likely depending on some internal (native) state and cannot be serialized.
@returnsa java.io.File replacement object, or null if no suitable replacement can be found.
/** * This method must be implemented to make sure that no instances * of <code>ShellFolder</code> are ever serialized. If <code>isFileSystem()</code> returns * <code>true</code>, then the object should be representable with an instance of * <code>java.io.File</code> instead. If not, then the object is most likely * depending on some internal (native) state and cannot be serialized. * * @returns a <code>java.io.File</code> replacement object, or <code>null</code> * if no suitable replacement can be found. */
protected abstract Object writeReplace() throws java.io.ObjectStreamException;
Returns the path for this object's parent, or null if this object does not name a parent folder.
See Also:
Returns: the path as a String for this object's parent, or null if this object does not name a parent folder
Since:1.4
/** * Returns the path for this object's parent, * or <code>null</code> if this object does not name a parent * folder. * * @return the path as a String for this object's parent, * or <code>null</code> if this object does not name a parent * folder * * @see java.io.File#getParent() * @since 1.4 */
public String getParent() { if (parent == null && isFileSystem()) { return super.getParent(); } if (parent != null) { return (parent.getPath()); } else { return null; } }
Returns a File object representing this object's parent, or null if this object does not name a parent folder.
See Also:
Returns: a File object representing this object's parent, or null if this object does not name a parent folder
Since:1.4
/** * Returns a File object representing this object's parent, * or <code>null</code> if this object does not name a parent * folder. * * @return a File object representing this object's parent, * or <code>null</code> if this object does not name a parent * folder * * @see java.io.File#getParentFile() * @since 1.4 */
public File getParentFile() { if (parent != null) { return parent; } else if (isFileSystem()) { return super.getParentFile(); } else { return null; } } public File[] listFiles() { return listFiles(true); } public File[] listFiles(boolean includeHiddenFiles) { File[] files = super.listFiles(); if (!includeHiddenFiles) { Vector v = new Vector(); int nameCount = (files == null) ? 0 : files.length; for (int i = 0; i < nameCount; i++) { if (!files[i].isHidden()) { v.addElement(files[i]); } } files = (File[])v.toArray(new File[v.size()]); } return files; }
Returns:Whether this shell folder is a link
/** * @return Whether this shell folder is a link */
public abstract boolean isLink();
Returns:The shell folder linked to by this shell folder, or null if this shell folder is not a link
/** * @return The shell folder linked to by this shell folder, or null * if this shell folder is not a link */
public abstract ShellFolder getLinkLocation() throws FileNotFoundException;
Returns:The name used to display this shell folder
/** * @return The name used to display this shell folder */
public abstract String getDisplayName();
Returns:The type of shell folder as a string
/** * @return The type of shell folder as a string */
public abstract String getFolderType();
Returns:The executable type as a string
/** * @return The executable type as a string */
public abstract String getExecutableType();
Compares this ShellFolder with the specified ShellFolder for order.
See Also:
  • compareTo(Object)
/** * Compares this ShellFolder with the specified ShellFolder for order. * * @see #compareTo(Object) */
public int compareTo(File file2) { if (file2 == null || !(file2 instanceof ShellFolder) || ((file2 instanceof ShellFolder) && ((ShellFolder)file2).isFileSystem())) { if (isFileSystem()) { return super.compareTo(file2); } else { return -1; } } else { if (isFileSystem()) { return 1; } else { return getName().compareTo(file2.getName()); } } }
Params:
  • getLargeIcon – whether to return large icon (ignored in base implementation)
Returns:The icon used to display this shell folder
/** * @param getLargeIcon whether to return large icon (ignored in base implementation) * @return The icon used to display this shell folder */
public Image getIcon(boolean getLargeIcon) { return null; } // Static private static final ShellFolderManager shellFolderManager; private static final Invoker invoker; static { String managerClassName = (String)Toolkit.getDefaultToolkit(). getDesktopProperty("Shell.shellFolderManager"); Class managerClass = null; try { managerClass = Class.forName(managerClassName, false, null); if (!ShellFolderManager.class.isAssignableFrom(managerClass)) { managerClass = null; } // swallow the exceptions below and use default shell folder } catch(ClassNotFoundException e) { } catch(NullPointerException e) { } catch(SecurityException e) { } if (managerClass == null) { managerClass = ShellFolderManager.class; } try { shellFolderManager = (ShellFolderManager)managerClass.newInstance(); } catch (InstantiationException e) { throw new Error("Could not instantiate Shell Folder Manager: " + managerClass.getName()); } catch (IllegalAccessException e) { throw new Error ("Could not access Shell Folder Manager: " + managerClass.getName()); } invoker = shellFolderManager.createInvoker(); }
Return a shell folder from a file object
Throws:
  • FileNotFoundException – if file does not exist
/** * Return a shell folder from a file object * @exception FileNotFoundException if file does not exist */
public static ShellFolder getShellFolder(File file) throws FileNotFoundException { if (file instanceof ShellFolder) { return (ShellFolder)file; } if (!file.exists()) { throw new FileNotFoundException(); } return shellFolderManager.createShellFolder(file); }
Params:
  • key – a String
See Also:
Returns:An Object matching the string key.
/** * @param key a <code>String</code> * @return An Object matching the string <code>key</code>. * @see ShellFolderManager#get(String) */
public static Object get(String key) { return shellFolderManager.get(key); }
Does dir represent a "computer" such as a node on the network, or "My Computer" on the desktop.
/** * Does <code>dir</code> represent a "computer" such as a node on the network, or * "My Computer" on the desktop. */
public static boolean isComputerNode(File dir) { return shellFolderManager.isComputerNode(dir); }
Returns:Whether this is a file system root directory
/** * @return Whether this is a file system root directory */
public static boolean isFileSystemRoot(File dir) { return shellFolderManager.isFileSystemRoot(dir); }
Canonicalizes files that don't have symbolic links in their path. Normalizes files that do, preserving symbolic links from being resolved.
/** * Canonicalizes files that don't have symbolic links in their path. * Normalizes files that do, preserving symbolic links from being resolved. */
public static File getNormalizedFile(File f) throws IOException { File canonical = f.getCanonicalFile(); if (f.equals(canonical)) { // path of f doesn't contain symbolic links return canonical; } // preserve symbolic links from being resolved return new File(f.toURI().normalize()); } // Override File methods public static void sort(final List<? extends File> files) { if (files == null || files.size() <= 1) { return; } // To avoid loads of synchronizations with Invoker and improve performance we // synchronize the whole code of the sort method once invoke(new Callable<Void>() { public Void call() { // Check that we can use the ShellFolder.sortChildren() method: // 1. All files have the same non-null parent // 2. All files is ShellFolders File commonParent = null; for (File file : files) { File parent = file.getParentFile(); if (parent == null || !(file instanceof ShellFolder)) { commonParent = null; break; } if (commonParent == null) { commonParent = parent; } else { if (commonParent != parent && !commonParent.equals(parent)) { commonParent = null; break; } } } if (commonParent instanceof ShellFolder) { ((ShellFolder) commonParent).sortChildren(files); } else { Collections.sort(files, FILE_COMPARATOR); } return null; } }); } public void sortChildren(final List<? extends File> files) { // To avoid loads of synchronizations with Invoker and improve performance we // synchronize the whole code of the sort method once invoke(new Callable<Void>() { public Void call() { Collections.sort(files, FILE_COMPARATOR); return null; } }); } public boolean isAbsolute() { return (!isFileSystem() || super.isAbsolute()); } public File getAbsoluteFile() { return (isFileSystem() ? super.getAbsoluteFile() : this); } public boolean canRead() { return (isFileSystem() ? super.canRead() : true); // ((Fix?)) }
Returns true if folder allows creation of children. True for the "Desktop" folder, but false for the "My Computer" folder.
/** * Returns true if folder allows creation of children. * True for the "Desktop" folder, but false for the "My Computer" * folder. */
public boolean canWrite() { return (isFileSystem() ? super.canWrite() : false); // ((Fix?)) } public boolean exists() { // Assume top-level drives exist, because state is uncertain for // removable drives. return (!isFileSystem() || isFileSystemRoot(this) || super.exists()) ; } public boolean isDirectory() { return (isFileSystem() ? super.isDirectory() : true); // ((Fix?)) } public boolean isFile() { return (isFileSystem() ? super.isFile() : !isDirectory()); // ((Fix?)) } public long lastModified() { return (isFileSystem() ? super.lastModified() : 0L); // ((Fix?)) } public long length() { return (isFileSystem() ? super.length() : 0L); // ((Fix?)) } public boolean createNewFile() throws IOException { return (isFileSystem() ? super.createNewFile() : false); } public boolean delete() { return (isFileSystem() ? super.delete() : false); // ((Fix?)) } public void deleteOnExit() { if (isFileSystem()) { super.deleteOnExit(); } else { // Do nothing // ((Fix?)) } } public boolean mkdir() { return (isFileSystem() ? super.mkdir() : false); } public boolean mkdirs() { return (isFileSystem() ? super.mkdirs() : false); } public boolean renameTo(File dest) { return (isFileSystem() ? super.renameTo(dest) : false); // ((Fix?)) } public boolean setLastModified(long time) { return (isFileSystem() ? super.setLastModified(time) : false); // ((Fix?)) } public boolean setReadOnly() { return (isFileSystem() ? super.setReadOnly() : false); // ((Fix?)) } public String toString() { return (isFileSystem() ? super.toString() : getDisplayName()); } public static ShellFolderColumnInfo[] getFolderColumns(File dir) { ShellFolderColumnInfo[] columns = null; if (dir instanceof ShellFolder) { columns = ((ShellFolder) dir).getFolderColumns(); } if (columns == null) { columns = new ShellFolderColumnInfo[]{ new ShellFolderColumnInfo(COLUMN_NAME, 150, SwingConstants.LEADING, true, null, FILE_COMPARATOR), new ShellFolderColumnInfo(COLUMN_SIZE, 75, SwingConstants.RIGHT, true, null, DEFAULT_COMPARATOR, true), new ShellFolderColumnInfo(COLUMN_DATE, 130, SwingConstants.LEADING, true, null, DEFAULT_COMPARATOR, true) }; } return columns; } public ShellFolderColumnInfo[] getFolderColumns() { return null; } public static Object getFolderColumnValue(File file, int column) { if (file instanceof ShellFolder) { Object value = ((ShellFolder)file).getFolderColumnValue(column); if (value != null) { return value; } } if (file == null || !file.exists()) { return null; } switch (column) { case 0: // By default, file name will be rendered using getSystemDisplayName() return file; case 1: // size return file.isDirectory() ? null : Long.valueOf(file.length()); case 2: // date if (isFileSystemRoot(file)) { return null; } long time = file.lastModified(); return (time == 0L) ? null : new Date(time); default: return null; } } public Object getFolderColumnValue(int column) { return null; }
Invokes the task which doesn't throw checked exceptions from its call method. If invokation is interrupted then Thread.currentThread().isInterrupted() will be set and result will be null
/** * Invokes the {@code task} which doesn't throw checked exceptions * from its {@code call} method. If invokation is interrupted then Thread.currentThread().isInterrupted() will * be set and result will be {@code null} */
public static <T> T invoke(Callable<T> task) { try { return invoke(task, RuntimeException.class); } catch (InterruptedException e) { return null; } }
Invokes the task which throws checked exceptions from its call method. If invokation is interrupted then Thread.currentThread().isInterrupted() will be set and InterruptedException will be thrown as well.
/** * Invokes the {@code task} which throws checked exceptions from its {@code call} method. * If invokation is interrupted then Thread.currentThread().isInterrupted() will * be set and InterruptedException will be thrown as well. */
public static <T, E extends Throwable> T invoke(Callable<T> task, Class<E> exceptionClass) throws InterruptedException, E { try { return invoker.invoke(task); } catch (Exception e) { if (e instanceof RuntimeException) { // Rethrow unchecked exceptions throw (RuntimeException) e; } if (e instanceof InterruptedException) { // Set isInterrupted flag for current thread Thread.currentThread().interrupt(); // Rethrow InterruptedException throw (InterruptedException) e; } if (exceptionClass.isInstance(e)) { throw exceptionClass.cast(e); } throw new RuntimeException("Unexpected error", e); } }
Interface allowing to invoke tasks in different environments on different platforms.
/** * Interface allowing to invoke tasks in different environments on different platforms. */
public static interface Invoker {
Invokes a callable task.
Params:
  • task – a task to invoke
Throws:
  • ExceptionInterruptedException or an exception that was thrown from the task
Returns:the result of task's invokation
/** * Invokes a callable task. * * @param task a task to invoke * @throws Exception {@code InterruptedException} or an exception that was thrown from the {@code task} * @return the result of {@code task}'s invokation */
<T> T invoke(Callable<T> task) throws Exception; }
Provides a default comparator for the default column set
/** * Provides a default comparator for the default column set */
private static final Comparator DEFAULT_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { int gt; if (o1 == null && o2 == null) { gt = 0; } else if (o1 != null && o2 == null) { gt = 1; } else if (o1 == null && o2 != null) { gt = -1; } else if (o1 instanceof Comparable) { gt = ((Comparable) o1).compareTo(o2); } else { gt = 0; } return gt; } }; private static final Comparator<File> FILE_COMPARATOR = new Comparator<File>() { public int compare(File f1, File f2) { ShellFolder sf1 = null; ShellFolder sf2 = null; if (f1 instanceof ShellFolder) { sf1 = (ShellFolder) f1; if (sf1.isFileSystem()) { sf1 = null; } } if (f2 instanceof ShellFolder) { sf2 = (ShellFolder) f2; if (sf2.isFileSystem()) { sf2 = null; } } if (sf1 != null && sf2 != null) { return sf1.compareTo(sf2); } else if (sf1 != null) { // Non-file shellfolders sort before files return -1; } else if (sf2 != null) { return 1; } else { String name1 = f1.getName(); String name2 = f2.getName(); // First ignore case when comparing int diff = name1.compareToIgnoreCase(name2); if (diff != 0) { return diff; } else { // May differ in case (e.g. "mail" vs. "Mail") // We need this test for consistent sorting return name1.compareTo(name2); } } } }; }