diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java | |
download | cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2 cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java')
-rw-r--r-- | libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java new file mode 100644 index 000000000..62657ad86 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -0,0 +1,586 @@ +/* BasicDirectoryModel.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; +import javax.swing.AbstractListModel; +import javax.swing.JFileChooser; +import javax.swing.SwingUtilities; +import javax.swing.event.ListDataEvent; +import javax.swing.filechooser.FileSystemView; + + +/** + * Implements an AbstractListModel for directories where the source + * of the files is a JFileChooser object. + * + * This class is used for sorting and ordering the file list in + * a JFileChooser L&F object. + */ +public class BasicDirectoryModel extends AbstractListModel + implements PropertyChangeListener +{ + /** The list of files itself */ + private Vector contents; + + /** + * The directories in the list. + */ + private Vector directories; + + /** + * The files in the list. + */ + private Vector files; + + /** The listing mode of the associated JFileChooser, + either FILES_ONLY, DIRECTORIES_ONLY or FILES_AND_DIRECTORIES */ + private int listingMode; + + /** The JFileCooser associated with this model */ + private JFileChooser filechooser; + + /** + * The thread that loads the file view. + */ + private DirectoryLoadThread loadThread; + + /** + * This thread is responsible for loading file lists from the + * current directory and updating the model. + */ + private class DirectoryLoadThread extends Thread + { + + /** + * Updates the Swing list model. + */ + private class UpdateSwingRequest + implements Runnable + { + + private List added; + private int addIndex; + private List removed; + private int removeIndex; + private boolean cancel; + + UpdateSwingRequest(List add, int ai, List rem, int ri) + { + added = add; + addIndex = ai; + removed = rem; + removeIndex = ri; + cancel = false; + } + + public void run() + { + if (! cancel) + { + int numRemoved = removed == null ? 0 : removed.size(); + int numAdded = added == null ? 0 : added.size(); + synchronized (contents) + { + if (numRemoved > 0) + contents.removeAll(removed); + if (numAdded > 0) + contents.addAll(added); + + files = null; + directories = null; + } + if (numRemoved > 0 && numAdded == 0) + fireIntervalRemoved(BasicDirectoryModel.this, removeIndex, + removeIndex + numRemoved - 1); + else if (numRemoved == 0 && numAdded > 0) + fireIntervalAdded(BasicDirectoryModel.this, addIndex, + addIndex + numAdded - 1); + else + fireContentsChanged(); + } + } + + void cancel() + { + cancel = true; + } + } + + /** + * The directory beeing loaded. + */ + File directory; + + /** + * Stores all UpdateSwingRequests that are sent to the event queue. + */ + private UpdateSwingRequest pending; + + /** + * Creates a new DirectoryLoadThread that loads the specified + * directory. + * + * @param dir the directory to load + */ + DirectoryLoadThread(File dir) + { + super("Basic L&F directory loader"); + directory = dir; + } + + public void run() + { + FileSystemView fsv = filechooser.getFileSystemView(); + File[] files = fsv.getFiles(directory, + filechooser.isFileHidingEnabled()); + + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + // Check list for accepted files. + Vector accepted = new Vector(); + for (int i = 0; i < files.length; i++) + { + if (filechooser.accept(files[i])) + accepted.add(files[i]); + } + + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + // Sort list. + sort(accepted); + + // Now split up directories from files so that we get the directories + // listed before the files. + Vector newFiles = new Vector(); + Vector newDirectories = new Vector(); + for (Iterator i = accepted.iterator(); i.hasNext();) + { + File f = (File) i.next(); + boolean traversable = filechooser.isTraversable(f); + if (traversable) + newDirectories.add(f); + else if (! traversable && filechooser.isFileSelectionEnabled()) + newFiles.add(f); + + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + } + + // Build up new file cache. Try to update only the changed elements. + // This will be important for actions like adding new files or + // directories inside a large file list. + Vector newCache = new Vector(newDirectories); + newCache.addAll(newFiles); + + int newSize = newCache.size(); + int oldSize = contents.size(); + if (newSize < oldSize) + { + // Check for removed interval. + int start = -1; + int end = -1; + boolean found = false; + for (int i = 0; i < newSize && !found; i++) + { + if (! newCache.get(i).equals(contents.get(i))) + { + start = i; + end = i + oldSize - newSize; + found = true; + } + } + if (start >= 0 && end > start + && contents.subList(end, oldSize) + .equals(newCache.subList(start, newSize))) + { + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + Vector removed = new Vector(contents.subList(start, end)); + UpdateSwingRequest r = new UpdateSwingRequest(null, 0, + removed, start); + invokeLater(r); + newCache = null; + } + } + else if (newSize > oldSize) + { + // Check for inserted interval. + int start = oldSize; + int end = newSize; + boolean found = false; + for (int i = 0; i < oldSize && ! found; i++) + { + if (! newCache.get(i).equals(contents.get(i))) + { + start = i; + boolean foundEnd = false; + for (int j = i; j < newSize && ! foundEnd; j++) + { + if (newCache.get(j).equals(contents.get(i))) + { + end = j; + foundEnd = true; + } + } + end = i + oldSize - newSize; + } + } + if (start >= 0 && end > start + && newCache.subList(end, newSize) + .equals(contents.subList(start, oldSize))) + { + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + List added = newCache.subList(start, end); + UpdateSwingRequest r = new UpdateSwingRequest(added, start, + null, 0); + invokeLater(r); + newCache = null; + } + } + + // Handle complete list changes (newCache != null). + if (newCache != null && ! contents.equals(newCache)) + { + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + UpdateSwingRequest r = new UpdateSwingRequest(newCache, 0, + contents, 0); + invokeLater(r); + } + } + + /** + * Wraps SwingUtilities.invokeLater() and stores the request in + * a Vector so that we can still cancel it later. + * + * @param update the request to invoke + */ + private void invokeLater(UpdateSwingRequest update) + { + pending = update; + SwingUtilities.invokeLater(update); + } + + /** + * Cancels all pending update requests that might be in the AWT + * event queue. + */ + void cancelPending() + { + if (pending != null) + pending.cancel(); + } + } + + /** A Comparator class/object for sorting the file list. */ + private Comparator comparator = new Comparator() + { + public int compare(Object o1, Object o2) + { + if (lt((File) o1, (File) o2)) + return -1; + else + return 1; + } + }; + + /** + * Creates a new BasicDirectoryModel object. + * + * @param filechooser DOCUMENT ME! + */ + public BasicDirectoryModel(JFileChooser filechooser) + { + this.filechooser = filechooser; + filechooser.addPropertyChangeListener(this); + listingMode = filechooser.getFileSelectionMode(); + contents = new Vector(); + validateFileCache(); + } + + /** + * Returns whether a given (File) object is included in the list. + * + * @param o - The file object to test. + * + * @return <code>true</code> if the list contains the given object. + */ + public boolean contains(Object o) + { + return contents.contains(o); + } + + /** + * Fires a content change event. + */ + public void fireContentsChanged() + { + fireContentsChanged(this, 0, getSize() - 1); + } + + /** + * Returns a Vector of (java.io.File) objects containing + * the directories in this list. + * + * @return a Vector + */ + public Vector<File> getDirectories() + { + // Synchronize this with the UpdateSwingRequest for the case when + // contents is modified. + synchronized (contents) + { + Vector dirs = directories; + if (dirs == null) + { + // Initializes this in getFiles(). + getFiles(); + dirs = directories; + } + return dirs; + } + } + + /** + * Returns the (java.io.File) object at + * an index in the list. + * + * @param index The list index + * @return a File object + */ + public Object getElementAt(int index) + { + if (index > getSize() - 1) + return null; + return contents.elementAt(index); + } + + /** + * Returns a Vector of (java.io.File) objects containing + * the files in this list. + * + * @return a Vector + */ + public Vector<File> getFiles() + { + synchronized (contents) + { + Vector f = files; + if (f == null) + { + f = new Vector(); + Vector d = new Vector(); // Directories; + for (Iterator i = contents.iterator(); i.hasNext();) + { + File file = (File) i.next(); + if (filechooser.isTraversable(file)) + d.add(file); + else + f.add(file); + } + files = f; + directories = d; + } + return f; + } + } + + /** + * Returns the size of the list, which only includes directories + * if the JFileChooser is set to DIRECTORIES_ONLY. + * + * Otherwise, both directories and files are included in the count. + * + * @return The size of the list. + */ + public int getSize() + { + return contents.size(); + } + + /** + * Returns the index of an (java.io.File) object in the list. + * + * @param o The object - normally a File. + * + * @return the index of that object, or -1 if it is not in the list. + */ + public int indexOf(Object o) + { + return contents.indexOf(o); + } + + /** + * Obsoleted method which does nothing. + */ + public void intervalAdded(ListDataEvent e) + { + // obsoleted + } + + /** + * Obsoleted method which does nothing. + */ + public void intervalRemoved(ListDataEvent e) + { + // obsoleted + } + + /** + * Obsoleted method which does nothing. + */ + public void invalidateFileCache() + { + // obsoleted + } + + /** + * Less than, determine the relative order in the list of two files + * for sorting purposes. + * + * The order is: directories < files, and thereafter alphabetically, + * using the default locale collation. + * + * @param a the first file + * @param b the second file + * + * @return <code>true</code> if a > b, <code>false</code> if a < b. + */ + protected boolean lt(File a, File b) + { + boolean aTrav = filechooser.isTraversable(a); + boolean bTrav = filechooser.isTraversable(b); + + if (aTrav == bTrav) + { + String aname = a.getName().toLowerCase(); + String bname = b.getName().toLowerCase(); + return (aname.compareTo(bname) < 0) ? true : false; + } + else + { + if (aTrav) + return true; + else + return false; + } + } + + /** + * Listens for a property change; the change in file selection mode of the + * associated JFileChooser. Reloads the file cache on that event. + * + * @param e - A PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + String property = e.getPropertyName(); + if (property.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_VIEW_CHANGED_PROPERTY) + ) + { + validateFileCache(); + } + } + + /** + * Renames a file - However, does <I>not</I> re-sort the list + * or replace the old file with the new one in the list. + * + * @param oldFile The old file + * @param newFile The new file name + * + * @return <code>true</code> if the rename succeeded + */ + public boolean renameFile(File oldFile, File newFile) + { + return oldFile.renameTo( newFile ); + } + + /** + * Sorts a Vector of File objects. + * + * @param v The Vector to sort. + */ + protected void sort(Vector<? extends File> v) + { + Collections.sort(v, comparator); + } + + /** + * Re-loads the list of files + */ + public void validateFileCache() + { + File dir = filechooser.getCurrentDirectory(); + if (dir != null) + { + // Cancel all pending requests. + if (loadThread != null) + { + loadThread.interrupt(); + loadThread.cancelPending(); + } + loadThread = new DirectoryLoadThread(dir); + loadThread.start(); + } + } +} |