Modified: 
pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraVFSBrowserSkin.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraVFSBrowserSkin.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- 
pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraVFSBrowserSkin.java
 (original)
+++ 
pivot/trunk/wtk-terra/src/org/apache/pivot/wtk/skin/terra/TerraVFSBrowserSkin.java
 Tue Oct 31 19:15:47 2023
@@ -1,1530 +1,1530 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License,
- * Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.pivot.wtk.skin.terra;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.text.DateFormat;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Date;
-
-import org.apache.commons.vfs2.FileFilter;
-import org.apache.commons.vfs2.FileName;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSelectInfo;
-import org.apache.commons.vfs2.FileSelector;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileType;
-import org.apache.pivot.beans.BXML;
-import org.apache.pivot.beans.BXMLSerializer;
-import org.apache.pivot.collections.ArrayList;
-import org.apache.pivot.collections.Dictionary;
-import org.apache.pivot.collections.List;
-import org.apache.pivot.collections.Sequence;
-import org.apache.pivot.serialization.SerializationException;
-import org.apache.pivot.text.FileSizeFormat;
-import org.apache.pivot.util.Filter;
-import org.apache.pivot.util.concurrent.AbortException;
-import org.apache.pivot.util.concurrent.Task;
-import org.apache.pivot.util.concurrent.TaskExecutionException;
-import org.apache.pivot.util.concurrent.TaskListener;
-import org.apache.pivot.wtk.ActivityIndicator;
-import org.apache.pivot.wtk.BoxPane;
-import org.apache.pivot.wtk.Button;
-import org.apache.pivot.wtk.ButtonPressListener;
-import org.apache.pivot.wtk.Component;
-import org.apache.pivot.wtk.ComponentKeyListener;
-import org.apache.pivot.wtk.ComponentMouseButtonListener;
-import org.apache.pivot.wtk.ComponentTooltipListener;
-import org.apache.pivot.wtk.Container;
-import org.apache.pivot.wtk.Dimensions;
-import org.apache.pivot.wtk.Display;
-import org.apache.pivot.wtk.FocusTraversalDirection;
-import org.apache.pivot.wtk.GridPane;
-import org.apache.pivot.wtk.HorizontalAlignment;
-import org.apache.pivot.wtk.ImageView;
-import org.apache.pivot.wtk.Insets;
-import org.apache.pivot.wtk.Keyboard;
-import org.apache.pivot.wtk.Keyboard.KeyCode;
-import org.apache.pivot.wtk.Keyboard.KeyLocation;
-import org.apache.pivot.wtk.Keyboard.Modifier;
-import org.apache.pivot.wtk.Label;
-import org.apache.pivot.wtk.ListButton;
-import org.apache.pivot.wtk.ListButtonSelectionListener;
-import org.apache.pivot.wtk.ListView;
-import org.apache.pivot.wtk.Mouse;
-import org.apache.pivot.wtk.Platform;
-import org.apache.pivot.wtk.Point;
-import org.apache.pivot.wtk.PushButton;
-import org.apache.pivot.wtk.ScrollPane;
-import org.apache.pivot.wtk.SortDirection;
-import org.apache.pivot.wtk.Span;
-import org.apache.pivot.wtk.StackPane;
-import org.apache.pivot.wtk.Style;
-import org.apache.pivot.wtk.TableView;
-import org.apache.pivot.wtk.TableViewSelectionListener;
-import org.apache.pivot.wtk.TableViewSortListener;
-import org.apache.pivot.wtk.TaskAdapter;
-import org.apache.pivot.wtk.TextArea;
-import org.apache.pivot.wtk.TextInput;
-import org.apache.pivot.wtk.TextInputContentListener;
-import org.apache.pivot.wtk.Tooltip;
-import org.apache.pivot.wtk.VFSBrowser;
-import org.apache.pivot.wtk.VerticalAlignment;
-import org.apache.pivot.wtk.media.Image;
-import org.apache.pivot.wtk.skin.VFSBrowserSkin;
-
-/**
- * Terra Commons VFS browser skin.
- */
-public class TerraVFSBrowserSkin extends VFSBrowserSkin {
-
-    /**
-     * Abstract renderer for displaying file system contents.
-     */
-    public abstract static class FileRenderer extends BoxPane {
-        protected ImageView imageView = new ImageView();
-        protected Label label = new Label();
-        protected VFSBrowser fileBrowser = null;
-
-        public static final int ICON_WIDTH = 16;
-        public static final int ICON_HEIGHT = 16;
-
-        public static final Image FOLDER_IMAGE;
-        public static final Image HOME_FOLDER_IMAGE;
-        public static final Image FILE_IMAGE;
-
-        static {
-            try {
-                FOLDER_IMAGE = 
Image.load(FileRenderer.class.getResource("folder.png"));
-                HOME_FOLDER_IMAGE = 
Image.load(FileRenderer.class.getResource("folder_home.png"));
-                FILE_IMAGE = 
Image.load(FileRenderer.class.getResource("page_white.png"));
-            } catch (TaskExecutionException exception) {
-                throw new RuntimeException(exception);
-            }
-        }
-
-        public FileRenderer() {
-            putStyle(Style.verticalAlignment, VerticalAlignment.CENTER);
-
-            add(imageView);
-            add(label);
-
-            imageView.setPreferredSize(ICON_WIDTH, ICON_HEIGHT);
-            imageView.putStyle(Style.backgroundColor, null);
-        }
-
-        @Override
-        public void setSize(int width, int height) {
-            super.setSize(width, height);
-
-            // Since this component doesn't have a parent, it won't be 
validated
-            // via layout; ensure that it is valid here
-            validate();
-        }
-
-        protected void setFileBrowser(VFSBrowser fileBrowser) {
-            this.fileBrowser = fileBrowser;
-        }
-
-        /**
-         * @return The icon to display for a given file.
-         *
-         * @param file The current file.
-         */
-        public Image getIcon(FileObject file) {
-            Image icon;
-            if (file.getName().getType() == FileType.FOLDER) {
-                icon = file.equals(fileBrowser.getHomeDirectory()) ? 
HOME_FOLDER_IMAGE
-                    : FOLDER_IMAGE;
-            } else {
-                icon = FILE_IMAGE;
-            }
-
-            return icon;
-        }
-
-    public boolean isFileHidden(FileObject file) {
-        try {
-            boolean hidden = false;
-            if (file != null) {
-                if (file.getName().getBaseName().length() != 0 && 
file.isHidden()) {
-                    hidden = true;
-                }
-            }
-            return hidden;
-        } catch (FileSystemException fse) {
-            throw new RuntimeException(fse);
-        }
-    }
-    }
-
-    /**
-     * List button file renderer.
-     */
-    public static class ListButtonFileRenderer extends FileRenderer implements 
Button.DataRenderer {
-        public ListButtonFileRenderer() {
-            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
-        }
-
-        @Override
-        public void render(Object data, Button button, boolean highlight) {
-            if (data != null) {
-                FileObject file = (FileObject) data;
-                boolean hidden = isFileHidden(file);
-
-                // Update the image view
-                imageView.setImage(getIcon(file));
-                imageView.putStyle(Style.opacity, button.isEnabled() && 
!hidden ? 1.0f : 0.5f);
-
-                // Update the label
-                String text = file.getName().getBaseName();
-                if (text.length() == 0) {
-                    text = FileName.ROOT_PATH;
-                }
-
-                label.setText(text);
-
-                Object color = null;
-                if (button.isEnabled() && !hidden) {
-                    color = button.getStyle(Style.color);
-                } else {
-                    color = button.getStyle(Style.disabledColor);
-                }
-
-                label.putStyle(Style.color, color);
-            }
-        }
-
-        @Override
-        public String toString(Object item) {
-            FileObject file = (FileObject) item;
-            String text = file.getName().getBaseName();
-            if (text.length() == 0) {
-                text = FileName.ROOT_PATH;
-            }
-
-            return text;
-        }
-    }
-
-    /**
-     * List view file renderer.
-     */
-    public static class ListViewFileRenderer extends FileRenderer implements 
ListView.ItemRenderer {
-        public ListViewFileRenderer() {
-            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
-            putStyle(Style.padding, new Insets(2, 3, 2, 3));
-        }
-
-        @Override
-        public void render(Object item, int index, ListView listView, boolean 
selected,
-            Button.State state, boolean highlighted, boolean disabled) {
-            boolean hidden = false;
-
-            label.copyStyle(Style.font, listView);
-
-            if (item != null) {
-                FileObject file = (FileObject) item;
-                hidden = isFileHidden(file);
-
-                // Update the image view
-                imageView.setImage(getIcon(file));
-                imageView.putStyle(Style.opacity,
-                    (listView.isEnabled() && !disabled && !hidden) ? 1.0f : 
0.5f);
-
-                // Update the label
-                String text = file.getName().getBaseName();
-                if (text.length() == 0) {
-                    text = FileName.ROOT_PATH;
-                }
-
-                label.setText(text);
-            }
-
-            Object color = null;
-            if (listView.isEnabled() && !disabled && !hidden) {
-                if (selected) {
-                    if (listView.isFocused()) {
-                        color = listView.getStyle(Style.selectionColor);
-                    } else {
-                        color = 
listView.getStyle(Style.inactiveSelectionColor);
-                    }
-                } else {
-                    color = listView.getStyle(Style.color);
-                }
-            } else {
-                color = listView.getStyle(Style.disabledColor);
-            }
-
-            label.putStyle(Style.color, color);
-        }
-
-        @Override
-        public String toString(Object item) {
-            FileObject file = (FileObject) item;
-            // TODO: should this be the full path or the base name?
-            String text = file.getName().getBaseName();
-            if (text.length() == 0) {
-                text = FileName.ROOT_PATH;
-            }
-
-            return text;
-        }
-    }
-
-    /**
-     * Table view file renderer.
-     */
-    public static class TableViewFileRenderer extends FileRenderer implements
-        TableView.CellRenderer {
-        public static final String NAME_KEY = "name";
-        public static final String SIZE_KEY = "size";
-        public static final String LAST_MODIFIED_KEY = "lastModified";
-
-        public TableViewFileRenderer() {
-            putStyle(Style.horizontalAlignment, HorizontalAlignment.CENTER);
-            putStyle(Style.padding, new Insets(2));
-        }
-
-        @Override
-        public void render(Object row, int rowIndex, int columnIndex, 
TableView tableView,
-            String columnName, boolean selected, boolean highlighted, boolean 
disabled) {
-            boolean hidden = false;
-
-            if (row != null) {
-                FileObject file = (FileObject) row;
-
-                String text = null;
-                Image icon = null;
-
-                try {
-                    FileType type = file.getType();
-                    hidden = isFileHidden(file);
-
-                    if (columnName.equals(NAME_KEY)) {
-                        text = file.getName().getBaseName();
-                        icon = getIcon(file);
-                        putStyle(Style.horizontalAlignment, 
HorizontalAlignment.LEFT);
-                    } else if (columnName.equals(SIZE_KEY)) {
-                        if (type == FileType.FOLDER || type == 
FileType.IMAGINARY) {
-                            text = "";
-                        } else {
-                            long length = file.getContent().getSize();
-                            text = FileSizeFormat.getInstance().format(length);
-                        }
-                        putStyle(Style.horizontalAlignment, 
HorizontalAlignment.RIGHT);
-                    } else if (columnName.equals(LAST_MODIFIED_KEY)) {
-                        if (type == FileType.FOLDER || type == 
FileType.IMAGINARY) {
-                            text = "";
-                        } else {
-                            long lastModified = 
file.getContent().getLastModifiedTime();
-                            Date lastModifiedDate = new Date(lastModified);
-                            text = DATE_FORMAT.format(lastModifiedDate);
-                            putStyle(Style.horizontalAlignment, 
HorizontalAlignment.RIGHT);
-                        }
-                    } else {
-                        System.err.println("Unexpected column name in " + 
getClass().getName()
-                            + ": " + columnName);
-                    }
-                } catch (FileSystemException fse) {
-                    // TODO: should we display an exception error here?
-                    throw new RuntimeException(fse);
-                }
-
-                label.setText(text);
-                imageView.setImage(icon);
-                imageView.putStyle(Style.opacity,
-                    (tableView.isEnabled() && !disabled && !hidden) ? 1.0f : 
0.5f);
-            }
-
-            label.copyStyle(Style.font, tableView);
-
-            Style colorStyle;
-            if (tableView.isEnabled() && !disabled && !hidden) {
-                if (selected) {
-                    if (tableView.isFocused()) {
-                        colorStyle = Style.selectionColor;
-                    } else {
-                        colorStyle = Style.inactiveSelectionColor;
-                    }
-                } else {
-                    colorStyle = Style.color;
-                }
-            } else {
-                colorStyle = Style.disabledColor;
-            }
-
-            label.putStyle(Style.color, tableView.getStyleColor(colorStyle));
-        }
-
-        @Override
-        public String toString(Object row, String columnName) {
-            String string;
-
-            FileObject file = (FileObject) row;
-            try {
-                FileType type = file.getType();
-                if (columnName.equals(NAME_KEY)) {
-                    string = file.getName().getBaseName();
-                } else if (columnName.equals(SIZE_KEY)) {
-                    if (type == FileType.FOLDER || type == FileType.IMAGINARY) 
{
-                        string = "";
-                    } else {
-                        long length = file.getContent().getSize();
-                        string = FileSizeFormat.getInstance().format(length);
-                    }
-                } else if (columnName.equals(LAST_MODIFIED_KEY)) {
-                    if (type == FileType.FOLDER || type == FileType.IMAGINARY) 
{
-                        string = "";
-                    } else {
-                        long lastModified = 
file.getContent().getLastModifiedTime();
-                        Date lastModifiedDate = new Date(lastModified);
-                        string = DATE_FORMAT.format(lastModifiedDate);
-                    }
-                } else {
-                    System.err.println("Unexpected column name in " + 
getClass().getName() + ": "
-                        + columnName);
-                    string = null;
-                }
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-
-            return string;
-        }
-    }
-
-    /**
-     * Abstract base class for drive renderers.
-     */
-    public abstract static class DriveRenderer extends BoxPane {
-        protected ImageView imageView = new ImageView();
-        protected Label label = new Label();
-
-        public static final int ICON_WIDTH = 16;
-        public static final int ICON_HEIGHT = 16;
-
-        public static final Image DRIVE_IMAGE;
-
-        static {
-            try {
-                DRIVE_IMAGE = 
Image.load(DriveRenderer.class.getResource("drive.png"));
-            } catch (TaskExecutionException exception) {
-                throw new RuntimeException(exception);
-            }
-        }
-
-        public DriveRenderer() {
-            putStyle(Style.verticalAlignment, VerticalAlignment.CENTER);
-
-            add(imageView);
-            add(label);
-
-            imageView.setPreferredSize(ICON_WIDTH, ICON_HEIGHT);
-            imageView.putStyle(Style.backgroundColor, null);
-        }
-
-        @Override
-        public void setSize(int width, int height) {
-            super.setSize(width, height);
-
-            // Since this component doesn't have a parent, it won't be 
validated
-            // via layout; ensure that it is valid here
-            validate();
-        }
-    }
-
-    /**
-     * List button drive renderer.
-     */
-    public static class ListButtonDriveRenderer extends DriveRenderer 
implements
-        Button.DataRenderer {
-        public ListButtonDriveRenderer() {
-            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
-        }
-
-        @Override
-        public void render(Object data, Button button, boolean highlight) {
-            if (data != null) {
-                FileObject file = (FileObject) data;
-
-                // Update the image view
-                imageView.setImage(DRIVE_IMAGE);
-                imageView.putStyle(Style.opacity, button.isEnabled() ? 1.0f : 
0.5f);
-
-                // Update the label
-                label.setText(file.toString());
-            }
-        }
-
-        @Override
-        public String toString(Object data) {
-            return null;
-        }
-    }
-
-    /**
-     * List view drive renderer.
-     */
-    public static class ListViewDriveRenderer extends DriveRenderer implements
-        ListView.ItemRenderer {
-        public ListViewDriveRenderer() {
-            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
-            putStyle(Style.padding, new Insets(2, 3, 2, 3));
-        }
-
-        @Override
-        public void render(Object item, int index, ListView listView, boolean 
selected,
-            Button.State state, boolean highlighted, boolean disabled) {
-            label.copyStyle(Style.font, listView);
-
-            Object color = null;
-            if (listView.isEnabled() && !disabled) {
-                if (selected) {
-                    if (listView.isFocused()) {
-                        color = listView.getStyle(Style.selectionColor);
-                    } else {
-                        color = 
listView.getStyle(Style.inactiveSelectionColor);
-                    }
-                } else {
-                    color = listView.getStyle(Style.color);
-                }
-            } else {
-                color = listView.getStyle(Style.disabledColor);
-            }
-
-            label.putStyle(Style.color, color);
-
-            if (item != null) {
-                FileObject file = (FileObject) item;
-
-                // Update the image view
-                imageView.setImage(DRIVE_IMAGE);
-                imageView.putStyle(Style.opacity,
-                    (listView.isEnabled() && !disabled) ? 1.0f : 0.5f);
-
-                // Update the label
-                label.setText(file.toString());
-            }
-        }
-
-        @Override
-        public String toString(Object item) {
-            return null;
-        }
-    }
-
-    public abstract static class FileComparator implements 
Comparator<FileObject>, Serializable {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public abstract int compare(FileObject f1, FileObject f2);
-    }
-
-    public static class FileNameAscendingComparator extends FileComparator {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public int compare(FileObject f1, FileObject f2) {
-            FileType f1Type = f1.getName().getType();
-            FileType f2Type = f2.getName().getType();
-            boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
-            boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
-
-            int result;
-            if (!file1IsFile && file2IsFile) {
-                result = -1;
-            } else if (file1IsFile && !file2IsFile) {
-                result = 1;
-            } else {
-                // Do the compare according to the rules of the file system
-                result = f1.compareTo(f2);
-            }
-            return result;
-        }
-    }
-
-    public static class FileNameDescendingComparator extends FileComparator {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public int compare(FileObject f1, FileObject f2) {
-            FileType f1Type = f1.getName().getType();
-            FileType f2Type = f2.getName().getType();
-            boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
-            boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
-
-            int result;
-            if (!file1IsFile && file2IsFile) {
-                result = -1;
-            } else if (file1IsFile && !file2IsFile) {
-                result = 1;
-            } else {
-                // Do the compare according to the rules of the file system
-                result = f2.compareTo(f1);
-            }
-            return result;
-        }
-    }
-
-    public static class FileSizeAscendingComparator extends FileComparator {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public int compare(FileObject f1, FileObject f2) {
-            try {
-                FileType f1Type = f1.getName().getType();
-                FileType f2Type = f2.getName().getType();
-                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
-                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
-                long size1 = file1IsFile ? f1.getContent().getSize() : 0L;
-                long size2 = file2IsFile ? f2.getContent().getSize() : 0L;
-                return Long.signum(size1 - size2);
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-        }
-    }
-
-    public static class FileSizeDescendingComparator extends FileComparator {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public int compare(FileObject f1, FileObject f2) {
-            try {
-                FileType f1Type = f1.getName().getType();
-                FileType f2Type = f2.getName().getType();
-                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
-                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
-                long size1 = file1IsFile ? f1.getContent().getSize() : 0L;
-                long size2 = file2IsFile ? f2.getContent().getSize() : 0L;
-                return Long.signum(size2 - size1);
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-        }
-    }
-
-    public static class FileDateAscendingComparator extends FileComparator {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public int compare(FileObject f1, FileObject f2) {
-            try {
-                FileType f1Type = f1.getName().getType();
-                FileType f2Type = f2.getName().getType();
-                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
-                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
-                long time1 = file1IsFile ? 
f1.getContent().getLastModifiedTime() : 0L;
-                long time2 = file2IsFile ? 
f2.getContent().getLastModifiedTime() : 0L;
-                return Long.signum(time1 - time2);
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-        }
-    }
-
-    public static class FileDateDescendingComparator extends FileComparator {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public int compare(FileObject f1, FileObject f2) {
-            try {
-                FileType f1Type = f1.getName().getType();
-                FileType f2Type = f2.getName().getType();
-                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
-                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
-                long time1 = file1IsFile ? 
f1.getContent().getLastModifiedTime() : 0L;
-                long time2 = file2IsFile ? 
f2.getContent().getLastModifiedTime() : 0L;
-                return Long.signum(time2 - time1);
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-        }
-    }
-
-    /**
-     * @return A new {@link FileObject} comparator for the given column and 
sort order.
-     * @param columnName Name of the column to sort on.
-     * @param sortDirection The sort order.
-     */
-    public static FileComparator getFileComparator(String columnName, 
SortDirection sortDirection) {
-        if (columnName.equals("name")) {
-            return sortDirection == SortDirection.ASCENDING ? new 
FileNameAscendingComparator()
-                : new FileNameDescendingComparator();
-        } else if (columnName.equals("size")) {
-            return sortDirection == SortDirection.ASCENDING ? new 
FileSizeAscendingComparator()
-                : new FileSizeDescendingComparator();
-        } else if (columnName.equals("lastModified")) {
-            return sortDirection == SortDirection.ASCENDING ? new 
FileDateAscendingComparator()
-                : new FileDateDescendingComparator();
-        } else {
-            throw new IllegalArgumentException("Invalid column name for file 
comparator.");
-        }
-    }
-
-    /**
-     * Include file filter.
-     */
-    public static class IncludeFileFilter implements Filter<FileObject> {
-        private String match;
-
-        public IncludeFileFilter() {
-            this(null);
-        }
-
-        public IncludeFileFilter(String match) {
-            this.match = (match == null ? null : match.toLowerCase());
-        }
-
-        @Override
-        public boolean include(FileObject file) {
-            boolean include = true;
-
-            if (match != null) {
-                String name = file.getName().getBaseName();
-                name = name.toLowerCase();
-
-                if (match.startsWith("*")) {
-                    if (match.length() == 1) {
-                        include = true;
-                    } else {
-                        include = name.contains(match.substring(1));
-                    }
-                } else {
-                    include = name.startsWith(match);
-                }
-            }
-
-            return include;
-        }
-    }
-
-    public static class FullFileSelector implements FileSelector {
-        private FileFilter hiddenFileFilter;
-        private Filter<FileObject> includeFileFilter;
-        private Filter<FileObject> excludeFileFilter;
-
-        public FullFileSelector(boolean showHiddenFiles, Filter<FileObject> 
includeFileFilter,
-            Filter<FileObject> excludeFileFilter) {
-            this.hiddenFileFilter = showHiddenFiles ? null : 
HIDDEN_FILE_FILTER;
-            this.includeFileFilter = includeFileFilter;
-            this.excludeFileFilter = excludeFileFilter;
-        }
-
-        @Override
-        public boolean includeFile(FileSelectInfo fileInfo) {
-            boolean include = hiddenFileFilter == null ? true : 
hiddenFileFilter.accept(fileInfo);
-            if (include && includeFileFilter != null) {
-                include = includeFileFilter.include(fileInfo.getFile());
-            }
-            if (include && excludeFileFilter != null) {
-                include = !excludeFileFilter.include(fileInfo.getFile());
-            }
-            // Don't include the base folder itself
-            if (include && fileInfo.getFile() == fileInfo.getBaseFolder()) {
-                include = false;
-            }
-            return include;
-        }
-
-        @Override
-        public boolean traverseDescendents(FileSelectInfo fileInfo) {
-            // Only traverse the first-level descendents
-            return fileInfo.getDepth() == 0;
-        }
-    }
-
-    private class RefreshFileListTask extends Task<ArrayList<FileObject>> {
-        private Filter<FileObject> includeFileFilter;
-        private Filter<FileObject> excludeFileFilter;
-        private FileComparator fileComparator;
-
-        public RefreshFileListTask(Filter<FileObject> includeFileFilter,
-            Filter<FileObject> excludeFileFilter, FileComparator 
fileComparator) {
-            this.includeFileFilter = includeFileFilter;
-            this.excludeFileFilter = excludeFileFilter;
-            this.fileComparator = fileComparator;
-        }
-
-        @Override
-        public ArrayList<FileObject> execute() {
-            VFSBrowser fileBrowser = (VFSBrowser) getComponent();
-
-            FileObject rootDirectory = fileBrowser.getRootDirectory();
-            if (abort) {
-                throw new AbortException();
-            }
-
-            try {
-                FileObject[] files = rootDirectory.findFiles(new 
FullFileSelector(
-                    showHiddenFiles, includeFileFilter, excludeFileFilter));
-                if (abort) {
-                    throw new AbortException();
-                }
-
-                Arrays.sort(files, fileComparator);
-
-                return new ArrayList<>(files, 0, files.length);
-
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-        }
-    }
-
-    private Component content = null;
-
-    @BXML
-    private BoxPane pushButtonPane = null;
-    @BXML
-    private ListButton driveListButton = null;
-    @BXML
-    private ListButton pathListButton = null;
-    @BXML
-    private PushButton goUpButton = null;
-    @BXML
-    private PushButton newFolderButton = null;
-    @BXML
-    private PushButton goHomeButton = null;
-    @BXML
-    private TextInput searchTextInput = null;
-
-    @BXML
-    private StackPane fileStackPane = null;
-    @BXML
-    private ScrollPane fileScrollPane = null;
-    @BXML
-    private TableView fileTableView = null;
-
-    private ActivityIndicator indicator = null;
-    private GridPane activityGrid = null;
-
-    private boolean keyboardFolderTraversalEnabled = true;
-    private boolean hideDisabledFiles = false;
-    private boolean showHiddenFiles = false;
-
-    private boolean updatingSelection = false;
-    private boolean refreshRoots = true;
-
-    private RefreshFileListTask refreshFileListTask = null;
-
-    private FileObject homeDirectory = null;
-
-    private static final FileFilter HIDDEN_FILE_FILTER = new FileFilter() {
-        @Override
-        public boolean accept(FileSelectInfo fileInfo) {
-            try {
-                return !fileInfo.getFile().isHidden();
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-        }
-    };
-
-    private static final DateFormat DATE_FORMAT = 
DateFormat.getDateTimeInstance(DateFormat.SHORT,
-        DateFormat.SHORT);
-
-    @Override
-    public void install(Component component) {
-        super.install(component);
-        final VFSBrowser fileBrowser = (VFSBrowser) component;
-        BXMLSerializer bxmlSerializer = new BXMLSerializer();
-        try {
-            content = (Component) 
bxmlSerializer.readObject(TerraVFSBrowserSkin.class,
-                "terra_vfs_browser_skin.bxml", true);
-        } catch (IOException exception) {
-            throw new RuntimeException(exception);
-        } catch (SerializationException exception) {
-            throw new RuntimeException(exception);
-        }
-        fileBrowser.add(content);
-
-        bxmlSerializer.bind(this, TerraVFSBrowserSkin.class);
-
-        // Notify all the renderers of which component they are dealing with
-        ((FileRenderer) 
pathListButton.getDataRenderer()).setFileBrowser(fileBrowser);
-        ((FileRenderer) 
pathListButton.getItemRenderer()).setFileBrowser(fileBrowser);
-        for (TableView.Column col : fileTableView.getColumns()) {
-            ((FileRenderer) col.getCellRenderer()).setFileBrowser(fileBrowser);
-        }
-
-        homeDirectory = fileBrowser.getHomeDirectory();
-
-        driveListButton.getListButtonSelectionListeners().add(
-            new ListButtonSelectionListener() {
-                @Override
-                public void selectedItemChanged(ListButton listButton, Object 
previousSelectedItem) {
-                    if (previousSelectedItem != null) {
-                        FileObject drive = (FileObject) 
listButton.getSelectedItem();
-                        try {
-                            if (drive.isReadable()) {
-                                fileBrowser.setRootDirectory(drive);
-                            } else {
-                                refreshRoots = true;
-                                
listButton.setSelectedItem(previousSelectedItem);
-                            }
-                        } catch (FileSystemException fse) {
-                            throw new RuntimeException(fse);
-                        }
-                    }
-                }
-            });
-
-        pathListButton.getListButtonSelectionListeners().add(
-            new ListButtonSelectionListener() {
-                @Override
-                public void selectedItemChanged(ListButton listButton, Object 
previousSelectedItem) {
-                    FileObject ancestorDirectory = (FileObject) 
listButton.getSelectedItem();
-
-                    if (ancestorDirectory != null) {
-                        try {
-                            fileBrowser.setRootDirectory(ancestorDirectory);
-                        } catch (FileSystemException fse) {
-                            throw new RuntimeException(fse);
-                        }
-                    }
-                }
-            });
-
-        goUpButton.getButtonPressListeners().add(new ButtonPressListener() {
-            @Override
-            public void buttonPressed(Button button) {
-                try {
-                    FileObject rootDirectory = fileBrowser.getRootDirectory();
-                    FileObject parentDirectory = rootDirectory.getParent();
-                    fileBrowser.setRootDirectory(parentDirectory);
-                } catch (FileSystemException fse) {
-                    throw new RuntimeException(fse);
-                }
-            }
-        });
-
-        newFolderButton.getButtonPressListeners().add(new 
ButtonPressListener() {
-            @Override
-            public void buttonPressed(Button button) {
-                // TODO
-            }
-        });
-
-        goHomeButton.getButtonPressListeners().add(new ButtonPressListener() {
-            @Override
-            public void buttonPressed(Button button) {
-                try {
-                    
fileBrowser.setRootDirectory(fileBrowser.getHomeDirectory());
-                } catch (FileSystemException fse) {
-                    throw new RuntimeException(fse);
-                }
-            }
-        });
-
-        /**
-         * {@link KeyCode#DOWN DOWN} Transfer focus to the file list and select
-         * the first item.<br> {@link KeyCode#ESCAPE ESCAPE} Clear the search
-         * field.
-         */
-        searchTextInput.getComponentKeyListeners().add(new 
ComponentKeyListener() {
-            @Override
-            public boolean keyPressed(Component componentArgument, int keyCode,
-                KeyLocation keyLocation) {
-                boolean consumed = false;
-
-                if (keyCode == KeyCode.ESCAPE) {
-                    searchTextInput.setText("");
-                    consumed = true;
-                } else if (keyCode == KeyCode.DOWN) {
-                    if (fileTableView.getTableData().getLength() > 0) {
-                        fileTableView.setSelectedIndex(0);
-                        fileTableView.requestFocus();
-                    }
-                }
-
-                return consumed;
-            }
-        });
-
-        searchTextInput.getTextInputContentListeners().add(new 
TextInputContentListener() {
-            @Override
-            public void textChanged(TextInput textInput) {
-                refreshFileList();
-            }
-        });
-
-        fileTableView.getTableViewSelectionListeners().add(new 
TableViewSelectionListener() {
-            @Override
-            public void selectedRangeAdded(TableView tableView, int 
rangeStart, int rangeEnd) {
-                if (!updatingSelection) {
-                    updatingSelection = true;
-
-                    try {
-                        for (int i = rangeStart; i <= rangeEnd; i++) {
-                            @SuppressWarnings("unchecked")
-                            List<FileObject> files = (List<FileObject>) 
fileTableView.getTableData();
-                            FileObject file = files.get(i);
-                            fileBrowser.addSelectedFile(file);
-                        }
-                    } catch (FileSystemException fse) {
-                        throw new RuntimeException(fse);
-                    }
-
-                    updatingSelection = false;
-                }
-            }
-
-            @Override
-            public void selectedRangeRemoved(TableView tableView, int 
rangeStart, int rangeEnd) {
-                if (!updatingSelection) {
-                    updatingSelection = true;
-
-                    for (int i = rangeStart; i <= rangeEnd; i++) {
-                        @SuppressWarnings("unchecked")
-                        List<FileObject> files = (List<FileObject>) 
fileTableView.getTableData();
-                        FileObject file = files.get(i);
-                        fileBrowser.removeSelectedFile(file);
-                    }
-
-                    updatingSelection = false;
-                }
-            }
-
-            @Override
-            public void selectedRangesChanged(TableView tableView,
-                Sequence<Span> previousSelectedRanges) {
-                if (!updatingSelection && previousSelectedRanges != null) {
-                    updatingSelection = true;
-
-                    @SuppressWarnings("unchecked")
-                    Sequence<FileObject> files = (Sequence<FileObject>) 
tableView.getSelectedRows();
-                    for (int i = 0, n = files.getLength(); i < n; i++) {
-                        FileObject file = files.get(i);
-                        files.update(i, file);
-                    }
-
-                    try {
-                        fileBrowser.setSelectedFiles(files);
-                    } catch (FileSystemException fse) {
-                        throw new RuntimeException(fse);
-                    }
-
-                    updatingSelection = false;
-                }
-            }
-
-            @Override
-            public void selectedRowChanged(TableView tableView, Object 
previousSelectedRow) {
-                // No-op
-            }
-        });
-
-        fileTableView.getTableViewSortListeners().add(new 
TableViewSortListener() {
-            @Override
-            public void sortChanged(TableView tableView) {
-                TableView.SortDictionary sort = fileTableView.getSort();
-
-                if (!sort.isEmpty()) {
-                    Dictionary.Pair<String, SortDirection> pair = 
fileTableView.getSort().get(0);
-                    @SuppressWarnings("unchecked")
-                    List<FileObject> files = (List<FileObject>) 
fileTableView.getTableData();
-                    files.setComparator(getFileComparator(pair.key, 
pair.value));
-                }
-            }
-        });
-
-        fileTableView.getComponentMouseButtonListeners().add(
-            new ComponentMouseButtonListener() {
-                private int index = -1;
-
-                @Override
-                public boolean mouseClick(Component componentArgument, 
Mouse.Button button, int x,
-                    int y, int count) {
-                    boolean consumed = false;
-
-                    if (count == 1) {
-                        index = fileTableView.getRowAt(y);
-                    } else if (count == 2) {
-                        int indexLocal = fileTableView.getRowAt(y);
-                        if (indexLocal != -1 && indexLocal == this.index
-                            && fileTableView.isRowSelected(indexLocal)) {
-                            FileObject file = (FileObject) 
fileTableView.getTableData().get(
-                                indexLocal);
-
-                            try {
-                                if (file.getName().getType() == 
FileType.FOLDER) {
-                                    fileBrowser.setRootDirectory(file);
-                                    consumed = true;
-                                }
-                            } catch (FileSystemException fse) {
-                                throw new RuntimeException(fse);
-                            }
-                        }
-                    }
-
-                    return consumed;
-                }
-            });
-
-        fileBrowser.setFocusTraversalPolicy(new IndexFocusTraversalPolicy() {
-            @Override
-            public Component getNextComponent(Container container, Component 
componentArgument,
-                FocusTraversalDirection direction) {
-                Component nextComponent;
-                if (componentArgument == null) {
-                    nextComponent = fileTableView;
-                } else {
-                    nextComponent = super.getNextComponent(container, 
componentArgument, direction);
-                }
-
-                return nextComponent;
-            }
-        });
-
-        fileTableView.setSort(TableViewFileRenderer.NAME_KEY, 
SortDirection.ASCENDING);
-        fileTableView.getComponentTooltipListeners().add(new 
ComponentTooltipListener() {
-
-            @Override
-            public void tooltipTriggered(Component comp, int x, int y) {
-
-                // Check that we are on the first column.
-                if (fileTableView.getColumnAt(x) != 0) {
-                    return;
-                }
-
-                // Gets the underlying file
-                int row = fileTableView.getRowAt(y);
-                if (row < 0) {
-                    return;
-                }
-                FileObject file = (FileObject) 
fileTableView.getTableData().get(row);
-
-                // Construct and show the tooltip.
-                final Tooltip tooltip = new Tooltip();
-
-                String text = null;
-
-                if (file != null) {
-                    text = file.getName().getBaseName();
-                }
-
-                if (text == null || text.isEmpty()) {
-                    return;
-                }
-
-                TextArea toolTipTextArea = new TextArea();
-
-                toolTipTextArea.setText(text);
-                toolTipTextArea.putStyle(Style.wrapText, true);
-                toolTipTextArea.putStyle(Style.backgroundColor, null);
-
-                tooltip.setContent(toolTipTextArea);
-
-                Point location = comp.getDisplay().getMouseLocation();
-                x = location.x;
-                y = location.y;
-
-                // Ensure that the tooltip stays on screen
-                Display display = comp.getDisplay();
-                int tooltipHeight = tooltip.getPreferredHeight();
-                if (y + tooltipHeight > display.getHeight()) {
-                    y -= tooltipHeight;
-                }
-
-                int tooltipXOffset = 16;
-                int padding = 15;
-
-                toolTipTextArea.setMaximumWidth(display.getWidth() - (x + 
tooltipXOffset + padding));
-                tooltip.setLocation(x + tooltipXOffset, y);
-                tooltip.open(comp.getWindow());
-            }
-        });
-
-        rootDirectoryChanged(fileBrowser, null);
-        selectedFilesChanged(fileBrowser, null);
-    }
-
-    @Override
-    public int getPreferredWidth(int height) {
-        return content.getPreferredWidth(height);
-    }
-
-    @Override
-    public int getPreferredHeight(int width) {
-        return content.getPreferredHeight(width);
-    }
-
-    @Override
-    public Dimensions getPreferredSize() {
-        return content.getPreferredSize();
-    }
-
-    @Override
-    public void layout() {
-        int width = getWidth();
-        int height = getHeight();
-
-        content.setLocation(0, 0);
-        content.setSize(width, height);
-    }
-
-    @Override
-    public FileObject getFileAt(int x, int y) {
-        FileObject file = null;
-
-        VFSBrowser fileBrowser = (VFSBrowser) getComponent();
-        Component component = fileBrowser.getDescendantAt(x, y);
-        if (component == fileTableView) {
-            Point location = fileTableView.mapPointFromAncestor(fileBrowser, 
x, y);
-
-            int index = fileTableView.getRowAt(location.y);
-            if (index != -1) {
-                file = (FileObject) fileTableView.getTableData().get(index);
-            }
-        }
-
-        return file;
-    }
-
-    @Override
-    public void addActionComponent(Component component) {
-        pushButtonPane.add(component);
-    }
-
-    public boolean isKeyboardFolderTraversalEnabled() {
-        return keyboardFolderTraversalEnabled;
-    }
-
-    public void setKeyboardFolderTraversalEnabled(boolean 
keyboardFolderTraversalEnabled) {
-        this.keyboardFolderTraversalEnabled = keyboardFolderTraversalEnabled;
-    }
-
-    public boolean isHideDisabledFiles() {
-        return hideDisabledFiles;
-    }
-
-    public void setHideDisabledFiles(boolean hideDisabledFiles) {
-        this.hideDisabledFiles = hideDisabledFiles;
-        refreshFileList();
-    }
-
-    /**
-     * @return Whether hidden files will be shown in the browser.
-     */
-    public boolean isShowHiddenFiles() {
-        return showHiddenFiles;
-    }
-
-    /**
-     * Set to determine if hidden files should be shown.
-     * @param showHiddenFiles Whether to show hidden files.
-     */
-    public void setShowHiddenFiles(boolean showHiddenFiles) {
-        this.showHiddenFiles = showHiddenFiles;
-        refreshFileList();
-    }
-
-    /**
-     * {@link KeyCode#ENTER ENTER} Change into the selected directory if
-     * {@link #keyboardFolderTraversalEnabled} is true.<br>
-     * {@link KeyCode#DELETE DELETE} or {@link KeyCode#BACKSPACE BACKSPACE}
-     * Change into the parent of the current directory.<br> {@link KeyCode#F5
-     * F5} Refresh the file list.
-     */
-    @Override
-    public boolean keyPressed(Component component, int keyCode, KeyLocation 
keyLocation) {
-        boolean consumed = super.keyPressed(component, keyCode, keyLocation);
-
-        VFSBrowser fileBrowser = (VFSBrowser) getComponent();
-
-        if (keyCode == KeyCode.ENTER && keyboardFolderTraversalEnabled) {
-            Sequence<FileObject> selectedFiles = 
fileBrowser.getSelectedFiles();
-
-            if (selectedFiles.getLength() == 1) {
-                FileObject selectedFile = selectedFiles.get(0);
-                try {
-                    if (selectedFile.getName().getType() == FileType.FOLDER) {
-                        fileBrowser.setRootDirectory(selectedFile);
-                        consumed = true;
-                    }
-                } catch (FileSystemException fse) {
-                    throw new RuntimeException(fse);
-                }
-            }
-        } else if (keyCode == KeyCode.DELETE || keyCode == KeyCode.BACKSPACE) {
-            FileObject rootDirectory = fileBrowser.getRootDirectory();
-            try {
-                FileObject parentDirectory = rootDirectory.getParent();
-                if (parentDirectory != null) {
-                    fileBrowser.setRootDirectory(parentDirectory);
-                    consumed = true;
-                }
-            } catch (FileSystemException fse) {
-                throw new RuntimeException(fse);
-            }
-        } else if (keyCode == KeyCode.F5) {
-            refreshFileList();
-            consumed = true;
-        }
-
-        return consumed;
-    }
-
-    /**
-     * CommandModifier + {@link KeyCode#F F} Transfers focus to the search
-     * TextInput.
-     *
-     * @see Platform#getCommandModifier()
-     */
-    @Override
-    public boolean keyReleased(Component component, int keyCode, KeyLocation 
keyLocation) {
-        boolean consumed = super.keyReleased(component, keyCode, keyLocation);
-
-        Modifier commandModifier = Platform.getCommandModifier();
-        if (keyCode == KeyCode.F && Keyboard.isPressed(commandModifier)) {
-            searchTextInput.requestFocus();
-            consumed = true;
-        }
-
-        return consumed;
-    }
-
-    @Override
-    public void managerChanged(VFSBrowser fileBrowser, FileSystemManager 
previousManager) {
-        // TODO: Is there anything to do here? Surely, but what?
-    }
-
-    @Override
-    public void rootDirectoryChanged(VFSBrowser fileBrowser, FileObject 
previousRootDirectory) {
-        ArrayList<FileObject> path = new ArrayList<>();
-
-        // FileSystemManager manager = fileBrowser.getManager();
-        FileObject rootDirectory = fileBrowser.getRootDirectory();
-
-        try {
-            FileObject ancestorDirectory = rootDirectory.getParent();
-            while (ancestorDirectory != null) {
-                path.add(ancestorDirectory);
-                ancestorDirectory = ancestorDirectory.getParent();
-            }
-        } catch (FileSystemException fse) {
-            throw new RuntimeException(fse);
-        }
-
-        @SuppressWarnings("unchecked")
-        ArrayList<FileObject> drives = (ArrayList<FileObject>) 
driveListButton.getListData();
-        if (refreshRoots) {
-            // TODO: this is ugly -- need to do much better at managing drive
-            // list with VFS
-            // There is an open question on the Dev list about adding
-            // "getFileRoots()" to the VFS API.
-            /*
-             * try { FileObject[] roots = new FileObject[1]; roots[0] =
-             * manager.resolveFile
-             * (manager.getBaseFile().getName().getRoot().getURI()); drives =
-             * new ArrayList<>(); for (int i = 0; i < roots.length; i++) {
-             * FileObject root = roots[i]; if (root.exists()) {
-             * drives.add(root); } } driveListButton.setListData(drives); }
-             * catch (FileSystemException fse) { throw new
-             * RuntimeException(fse); }
-             */
-            refreshRoots = false;
-        }
-
-        driveListButton.setVisible(drives.getLength() > 1);
-
-        FileObject drive;
-        if (path.getLength() == 0) {
-            drive = rootDirectory;
-        } else {
-            drive = path.get(path.getLength() - 1);
-        }
-
-        driveListButton.setSelectedItem(drive);
-
-        pathListButton.setListData(path);
-        pathListButton.setButtonData(rootDirectory);
-        pathListButton.setEnabled(rootDirectory.getName().getDepth() > 0);
-
-        goUpButton.setEnabled(pathListButton.isEnabled());
-
-        goHomeButton.setEnabled(!rootDirectory.equals(homeDirectory));
-
-        fileScrollPane.setScrollTop(0);
-        fileScrollPane.setScrollLeft(0);
-
-        searchTextInput.setText("");
-
-        fileTableView.requestFocus();
-    }
-
-    @Override
-    public void homeDirectoryChanged(VFSBrowser fileBrowser, FileObject 
previousHomeDirectory) {
-        this.homeDirectory = fileBrowser.getHomeDirectory();
-        
goHomeButton.setEnabled(!fileBrowser.getRootDirectory().equals(homeDirectory));
-        // Refresh the list in order to redo the icons correctly
-        refreshFileList();
-    }
-
-    @Override
-    public void selectedFileAdded(VFSBrowser fileBrowser, FileObject file) {
-        if (!updatingSelection) {
-            @SuppressWarnings("unchecked")
-            List<FileObject> files = (List<FileObject>) 
fileTableView.getTableData();
-            int index = files.indexOf(file);
-            if (index != -1) {
-                updatingSelection = true;
-                fileTableView.addSelectedIndex(index);
-                updatingSelection = false;
-            }
-        }
-    }
-
-    @Override
-    public void selectedFileRemoved(VFSBrowser fileBrowser, FileObject file) {
-        if (!updatingSelection) {
-            @SuppressWarnings("unchecked")
-            List<FileObject> files = (List<FileObject>) 
fileTableView.getTableData();
-            int index = files.indexOf(file);
-            if (index != -1) {
-                updatingSelection = true;
-                fileTableView.removeSelectedIndex(index);
-                updatingSelection = false;
-            }
-        }
-    }
-
-    @Override
-    public void selectedFilesChanged(VFSBrowser fileBrowser,
-        Sequence<FileObject> previousSelectedFiles) {
-        updateSelectedFiles(fileBrowser);
-    }
-
-    private void updateSelectedFiles(VFSBrowser fileBrowser) {
-        if (!updatingSelection) {
-            Sequence<FileObject> selectedFiles = 
fileBrowser.getSelectedFiles();
-
-            ArrayList<Span> selectedRanges = new ArrayList<>();
-            for (int i = 0, n = selectedFiles.getLength(); i < n; i++) {
-                FileObject selectedFile = selectedFiles.get(i);
-
-                @SuppressWarnings("unchecked")
-                List<FileObject> files = (List<FileObject>) 
fileTableView.getTableData();
-                int index = files.indexOf(selectedFile);
-                if (index != -1) {
-                    selectedRanges.add(new Span(index, index));
-                }
-            }
-
-            updatingSelection = true;
-            fileTableView.setSelectedRanges(selectedRanges);
-            updatingSelection = false;
-        }
-    }
-
-    @Override
-    public void multiSelectChanged(VFSBrowser fileBrowser) {
-        fileTableView.setSelectMode(fileBrowser.isMultiSelect() ? 
TableView.SelectMode.MULTI
-            : TableView.SelectMode.SINGLE);
-    }
-
-    @Override
-    public void disabledFileFilterChanged(VFSBrowser fileBrowser,
-        Filter<FileObject> previousDisabledFileFilter) {
-        
fileTableView.setDisabledRowFilter(fileBrowser.getDisabledFileFilter());
-        refreshFileList();
-    }
-
-    private void refreshFileList() {
-        // Cancel any outstanding task
-        if (refreshFileListTask != null) {
-            refreshFileListTask.abort();
-
-            if (indicator != null) {
-                indicator.setActive(false);
-                fileStackPane.remove(fileStackPane.getLength() - 1, 1);
-            }
-        }
-
-        if (indicator == null) {
-            indicator = new ActivityIndicator();
-            activityGrid = new GridPane(5);
-            GridPane.Row row1 = new GridPane.Row(activityGrid);
-            GridPane.Row row2 = new GridPane.Row(activityGrid);
-            GridPane.Row row3 = new GridPane.Row(activityGrid);
-            for (int i = 0; i < 5; i++) {
-                row1.add(new GridPane.Filler());
-                if (i == 2) {
-                    row2.add(indicator);
-                } else {
-                    row2.add(new GridPane.Filler());
-                }
-                row3.add(new GridPane.Filler());
-            }
-        }
-        fileStackPane.add(activityGrid);
-        indicator.setActive(true);
-
-        fileTableView.setTableData(new ArrayList<FileObject>());
-
-        String text = searchTextInput.getText().trim();
-        Filter<FileObject> disabledFileFilter = hideDisabledFiles
-            ? ((VFSBrowser) getComponent()).getDisabledFileFilter() : null;
-        Filter<FileObject> includeFileFilter = text.length() != 0
-            ? new IncludeFileFilter(text) : null;
-
-        TableView.SortDictionary sort = fileTableView.getSort();
-
-        final FileComparator fileComparator;
-        if (sort.isEmpty()) {
-            fileComparator = null;
-        } else {
-            Dictionary.Pair<String, SortDirection> pair = 
fileTableView.getSort().get(0);
-            fileComparator = getFileComparator(pair.key, pair.value);
-        }
-
-        refreshFileListTask = new RefreshFileListTask(includeFileFilter, 
disabledFileFilter,
-            fileComparator);
-        refreshFileListTask.execute(new TaskAdapter<>(new 
TaskListener<ArrayList<FileObject>>() {
-            @Override
-            public void taskExecuted(Task<ArrayList<FileObject>> task) {
-                if (task == refreshFileListTask) {
-                    indicator.setActive(false);
-                    fileStackPane.remove(fileStackPane.getLength() - 1, 1);
-
-                    ArrayList<FileObject> fileList = task.getResult();
-                    fileTableView.setTableData(fileList);
-
-                    updateSelectedFiles((VFSBrowser) getComponent());
-
-                    refreshFileListTask = null;
-                }
-            }
-
-            @Override
-            public void executeFailed(Task<ArrayList<FileObject>> task) {
-                if (task == refreshFileListTask) {
-                    indicator.setActive(false);
-                    fileStackPane.remove(fileStackPane.getLength() - 1, 1);
-
-                    refreshFileListTask = null;
-                }
-            }
-        }));
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.wtk.skin.terra;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+
+import org.apache.commons.vfs2.FileFilter;
+import org.apache.commons.vfs2.FileName;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSelectInfo;
+import org.apache.commons.vfs2.FileSelector;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileType;
+import org.apache.pivot.beans.BXML;
+import org.apache.pivot.beans.BXMLSerializer;
+import org.apache.pivot.collections.ArrayList;
+import org.apache.pivot.collections.Dictionary;
+import org.apache.pivot.collections.List;
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.serialization.SerializationException;
+import org.apache.pivot.text.FileSizeFormat;
+import org.apache.pivot.util.Filter;
+import org.apache.pivot.util.concurrent.AbortException;
+import org.apache.pivot.util.concurrent.Task;
+import org.apache.pivot.util.concurrent.TaskExecutionException;
+import org.apache.pivot.util.concurrent.TaskListener;
+import org.apache.pivot.wtk.ActivityIndicator;
+import org.apache.pivot.wtk.BoxPane;
+import org.apache.pivot.wtk.Button;
+import org.apache.pivot.wtk.ButtonPressListener;
+import org.apache.pivot.wtk.Component;
+import org.apache.pivot.wtk.ComponentKeyListener;
+import org.apache.pivot.wtk.ComponentMouseButtonListener;
+import org.apache.pivot.wtk.ComponentTooltipListener;
+import org.apache.pivot.wtk.Container;
+import org.apache.pivot.wtk.Dimensions;
+import org.apache.pivot.wtk.Display;
+import org.apache.pivot.wtk.FocusTraversalDirection;
+import org.apache.pivot.wtk.GridPane;
+import org.apache.pivot.wtk.HorizontalAlignment;
+import org.apache.pivot.wtk.ImageView;
+import org.apache.pivot.wtk.Insets;
+import org.apache.pivot.wtk.Keyboard;
+import org.apache.pivot.wtk.Keyboard.KeyCode;
+import org.apache.pivot.wtk.Keyboard.KeyLocation;
+import org.apache.pivot.wtk.Keyboard.Modifier;
+import org.apache.pivot.wtk.Label;
+import org.apache.pivot.wtk.ListButton;
+import org.apache.pivot.wtk.ListButtonSelectionListener;
+import org.apache.pivot.wtk.ListView;
+import org.apache.pivot.wtk.Mouse;
+import org.apache.pivot.wtk.Platform;
+import org.apache.pivot.wtk.Point;
+import org.apache.pivot.wtk.PushButton;
+import org.apache.pivot.wtk.ScrollPane;
+import org.apache.pivot.wtk.SortDirection;
+import org.apache.pivot.wtk.Span;
+import org.apache.pivot.wtk.StackPane;
+import org.apache.pivot.wtk.Style;
+import org.apache.pivot.wtk.TableView;
+import org.apache.pivot.wtk.TableViewSelectionListener;
+import org.apache.pivot.wtk.TableViewSortListener;
+import org.apache.pivot.wtk.TaskAdapter;
+import org.apache.pivot.wtk.TextArea;
+import org.apache.pivot.wtk.TextInput;
+import org.apache.pivot.wtk.TextInputContentListener;
+import org.apache.pivot.wtk.Tooltip;
+import org.apache.pivot.wtk.VFSBrowser;
+import org.apache.pivot.wtk.VerticalAlignment;
+import org.apache.pivot.wtk.media.Image;
+import org.apache.pivot.wtk.skin.VFSBrowserSkin;
+
+/**
+ * Terra Commons VFS browser skin.
+ */
+public class TerraVFSBrowserSkin extends VFSBrowserSkin {
+
+    /**
+     * Abstract renderer for displaying file system contents.
+     */
+    public abstract static class FileRenderer extends BoxPane {
+        protected ImageView imageView = new ImageView();
+        protected Label label = new Label();
+        protected VFSBrowser fileBrowser = null;
+
+        public static final int ICON_WIDTH = 16;
+        public static final int ICON_HEIGHT = 16;
+
+        public static final Image FOLDER_IMAGE;
+        public static final Image HOME_FOLDER_IMAGE;
+        public static final Image FILE_IMAGE;
+
+        static {
+            try {
+                FOLDER_IMAGE = 
Image.load(FileRenderer.class.getResource("folder.png"));
+                HOME_FOLDER_IMAGE = 
Image.load(FileRenderer.class.getResource("folder_home.png"));
+                FILE_IMAGE = 
Image.load(FileRenderer.class.getResource("page_white.png"));
+            } catch (TaskExecutionException exception) {
+                throw new RuntimeException(exception);
+            }
+        }
+
+        public FileRenderer() {
+            putStyle(Style.verticalAlignment, VerticalAlignment.CENTER);
+
+            add(imageView);
+            add(label);
+
+            imageView.setPreferredSize(ICON_WIDTH, ICON_HEIGHT);
+            imageView.putStyle(Style.backgroundColor, null);
+        }
+
+        @Override
+        public void setSize(int width, int height) {
+            super.setSize(width, height);
+
+            // Since this component doesn't have a parent, it won't be 
validated
+            // via layout; ensure that it is valid here
+            validate();
+        }
+
+        protected void setFileBrowser(VFSBrowser fileBrowser) {
+            this.fileBrowser = fileBrowser;
+        }
+
+        /**
+         * @return The icon to display for a given file.
+         *
+         * @param file The current file.
+         */
+        public Image getIcon(FileObject file) {
+            Image icon;
+            if (file.getName().getType() == FileType.FOLDER) {
+                icon = file.equals(fileBrowser.getHomeDirectory()) ? 
HOME_FOLDER_IMAGE
+                    : FOLDER_IMAGE;
+            } else {
+                icon = FILE_IMAGE;
+            }
+
+            return icon;
+        }
+
+    public boolean isFileHidden(FileObject file) {
+        try {
+            boolean hidden = false;
+            if (file != null) {
+                if (file.getName().getBaseName().length() != 0 && 
file.isHidden()) {
+                    hidden = true;
+                }
+            }
+            return hidden;
+        } catch (FileSystemException fse) {
+            throw new RuntimeException(fse);
+        }
+    }
+    }
+
+    /**
+     * List button file renderer.
+     */
+    public static class ListButtonFileRenderer extends FileRenderer implements 
Button.DataRenderer {
+        public ListButtonFileRenderer() {
+            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
+        }
+
+        @Override
+        public void render(Object data, Button button, boolean highlight) {
+            if (data != null) {
+                FileObject file = (FileObject) data;
+                boolean hidden = isFileHidden(file);
+
+                // Update the image view
+                imageView.setImage(getIcon(file));
+                imageView.putStyle(Style.opacity, button.isEnabled() && 
!hidden ? 1.0f : 0.5f);
+
+                // Update the label
+                String text = file.getName().getBaseName();
+                if (text.length() == 0) {
+                    text = FileName.ROOT_PATH;
+                }
+
+                label.setText(text);
+
+                Object color = null;
+                if (button.isEnabled() && !hidden) {
+                    color = button.getStyle(Style.color);
+                } else {
+                    color = button.getStyle(Style.disabledColor);
+                }
+
+                label.putStyle(Style.color, color);
+            }
+        }
+
+        @Override
+        public String toString(Object item) {
+            FileObject file = (FileObject) item;
+            String text = file.getName().getBaseName();
+            if (text.length() == 0) {
+                text = FileName.ROOT_PATH;
+            }
+
+            return text;
+        }
+    }
+
+    /**
+     * List view file renderer.
+     */
+    public static class ListViewFileRenderer extends FileRenderer implements 
ListView.ItemRenderer {
+        public ListViewFileRenderer() {
+            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
+            putStyle(Style.padding, new Insets(2, 3, 2, 3));
+        }
+
+        @Override
+        public void render(Object item, int index, ListView listView, boolean 
selected,
+            Button.State state, boolean highlighted, boolean disabled) {
+            boolean hidden = false;
+
+            label.copyStyle(Style.font, listView);
+
+            if (item != null) {
+                FileObject file = (FileObject) item;
+                hidden = isFileHidden(file);
+
+                // Update the image view
+                imageView.setImage(getIcon(file));
+                imageView.putStyle(Style.opacity,
+                    (listView.isEnabled() && !disabled && !hidden) ? 1.0f : 
0.5f);
+
+                // Update the label
+                String text = file.getName().getBaseName();
+                if (text.length() == 0) {
+                    text = FileName.ROOT_PATH;
+                }
+
+                label.setText(text);
+            }
+
+            Object color = null;
+            if (listView.isEnabled() && !disabled && !hidden) {
+                if (selected) {
+                    if (listView.isFocused()) {
+                        color = listView.getStyle(Style.selectionColor);
+                    } else {
+                        color = 
listView.getStyle(Style.inactiveSelectionColor);
+                    }
+                } else {
+                    color = listView.getStyle(Style.color);
+                }
+            } else {
+                color = listView.getStyle(Style.disabledColor);
+            }
+
+            label.putStyle(Style.color, color);
+        }
+
+        @Override
+        public String toString(Object item) {
+            FileObject file = (FileObject) item;
+            // TODO: should this be the full path or the base name?
+            String text = file.getName().getBaseName();
+            if (text.length() == 0) {
+                text = FileName.ROOT_PATH;
+            }
+
+            return text;
+        }
+    }
+
+    /**
+     * Table view file renderer.
+     */
+    public static class TableViewFileRenderer extends FileRenderer implements
+        TableView.CellRenderer {
+        public static final String NAME_KEY = "name";
+        public static final String SIZE_KEY = "size";
+        public static final String LAST_MODIFIED_KEY = "lastModified";
+
+        public TableViewFileRenderer() {
+            putStyle(Style.horizontalAlignment, HorizontalAlignment.CENTER);
+            putStyle(Style.padding, new Insets(2));
+        }
+
+        @Override
+        public void render(Object row, int rowIndex, int columnIndex, 
TableView tableView,
+            String columnName, boolean selected, boolean highlighted, boolean 
disabled) {
+            boolean hidden = false;
+
+            if (row != null) {
+                FileObject file = (FileObject) row;
+
+                String text = null;
+                Image icon = null;
+
+                try {
+                    FileType type = file.getType();
+                    hidden = isFileHidden(file);
+
+                    if (columnName.equals(NAME_KEY)) {
+                        text = file.getName().getBaseName();
+                        icon = getIcon(file);
+                        putStyle(Style.horizontalAlignment, 
HorizontalAlignment.LEFT);
+                    } else if (columnName.equals(SIZE_KEY)) {
+                        if (type == FileType.FOLDER || type == 
FileType.IMAGINARY) {
+                            text = "";
+                        } else {
+                            long length = file.getContent().getSize();
+                            text = FileSizeFormat.getInstance().format(length);
+                        }
+                        putStyle(Style.horizontalAlignment, 
HorizontalAlignment.RIGHT);
+                    } else if (columnName.equals(LAST_MODIFIED_KEY)) {
+                        if (type == FileType.FOLDER || type == 
FileType.IMAGINARY) {
+                            text = "";
+                        } else {
+                            long lastModified = 
file.getContent().getLastModifiedTime();
+                            Date lastModifiedDate = new Date(lastModified);
+                            text = DATE_FORMAT.format(lastModifiedDate);
+                            putStyle(Style.horizontalAlignment, 
HorizontalAlignment.RIGHT);
+                        }
+                    } else {
+                        System.err.println("Unexpected column name in " + 
getClass().getName()
+                            + ": " + columnName);
+                    }
+                } catch (FileSystemException fse) {
+                    // TODO: should we display an exception error here?
+                    throw new RuntimeException(fse);
+                }
+
+                label.setText(text);
+                imageView.setImage(icon);
+                imageView.putStyle(Style.opacity,
+                    (tableView.isEnabled() && !disabled && !hidden) ? 1.0f : 
0.5f);
+            }
+
+            label.copyStyle(Style.font, tableView);
+
+            Style colorStyle;
+            if (tableView.isEnabled() && !disabled && !hidden) {
+                if (selected) {
+                    if (tableView.isFocused()) {
+                        colorStyle = Style.selectionColor;
+                    } else {
+                        colorStyle = Style.inactiveSelectionColor;
+                    }
+                } else {
+                    colorStyle = Style.color;
+                }
+            } else {
+                colorStyle = Style.disabledColor;
+            }
+
+            label.putStyle(Style.color, tableView.getStyleColor(colorStyle));
+        }
+
+        @Override
+        public String toString(Object row, String columnName) {
+            String string;
+
+            FileObject file = (FileObject) row;
+            try {
+                FileType type = file.getType();
+                if (columnName.equals(NAME_KEY)) {
+                    string = file.getName().getBaseName();
+                } else if (columnName.equals(SIZE_KEY)) {
+                    if (type == FileType.FOLDER || type == FileType.IMAGINARY) 
{
+                        string = "";
+                    } else {
+                        long length = file.getContent().getSize();
+                        string = FileSizeFormat.getInstance().format(length);
+                    }
+                } else if (columnName.equals(LAST_MODIFIED_KEY)) {
+                    if (type == FileType.FOLDER || type == FileType.IMAGINARY) 
{
+                        string = "";
+                    } else {
+                        long lastModified = 
file.getContent().getLastModifiedTime();
+                        Date lastModifiedDate = new Date(lastModified);
+                        string = DATE_FORMAT.format(lastModifiedDate);
+                    }
+                } else {
+                    System.err.println("Unexpected column name in " + 
getClass().getName() + ": "
+                        + columnName);
+                    string = null;
+                }
+            } catch (FileSystemException fse) {
+                throw new RuntimeException(fse);
+            }
+
+            return string;
+        }
+    }
+
+    /**
+     * Abstract base class for drive renderers.
+     */
+    public abstract static class DriveRenderer extends BoxPane {
+        protected ImageView imageView = new ImageView();
+        protected Label label = new Label();
+
+        public static final int ICON_WIDTH = 16;
+        public static final int ICON_HEIGHT = 16;
+
+        public static final Image DRIVE_IMAGE;
+
+        static {
+            try {
+                DRIVE_IMAGE = 
Image.load(DriveRenderer.class.getResource("drive.png"));
+            } catch (TaskExecutionException exception) {
+                throw new RuntimeException(exception);
+            }
+        }
+
+        public DriveRenderer() {
+            putStyle(Style.verticalAlignment, VerticalAlignment.CENTER);
+
+            add(imageView);
+            add(label);
+
+            imageView.setPreferredSize(ICON_WIDTH, ICON_HEIGHT);
+            imageView.putStyle(Style.backgroundColor, null);
+        }
+
+        @Override
+        public void setSize(int width, int height) {
+            super.setSize(width, height);
+
+            // Since this component doesn't have a parent, it won't be 
validated
+            // via layout; ensure that it is valid here
+            validate();
+        }
+    }
+
+    /**
+     * List button drive renderer.
+     */
+    public static class ListButtonDriveRenderer extends DriveRenderer 
implements
+        Button.DataRenderer {
+        public ListButtonDriveRenderer() {
+            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
+        }
+
+        @Override
+        public void render(Object data, Button button, boolean highlight) {
+            if (data != null) {
+                FileObject file = (FileObject) data;
+
+                // Update the image view
+                imageView.setImage(DRIVE_IMAGE);
+                imageView.putStyle(Style.opacity, button.isEnabled() ? 1.0f : 
0.5f);
+
+                // Update the label
+                label.setText(file.toString());
+            }
+        }
+
+        @Override
+        public String toString(Object data) {
+            return null;
+        }
+    }
+
+    /**
+     * List view drive renderer.
+     */
+    public static class ListViewDriveRenderer extends DriveRenderer implements
+        ListView.ItemRenderer {
+        public ListViewDriveRenderer() {
+            putStyle(Style.horizontalAlignment, HorizontalAlignment.LEFT);
+            putStyle(Style.padding, new Insets(2, 3, 2, 3));
+        }
+
+        @Override
+        public void render(Object item, int index, ListView listView, boolean 
selected,
+            Button.State state, boolean highlighted, boolean disabled) {
+            label.copyStyle(Style.font, listView);
+
+            Object color = null;
+            if (listView.isEnabled() && !disabled) {
+                if (selected) {
+                    if (listView.isFocused()) {
+                        color = listView.getStyle(Style.selectionColor);
+                    } else {
+                        color = 
listView.getStyle(Style.inactiveSelectionColor);
+                    }
+                } else {
+                    color = listView.getStyle(Style.color);
+                }
+            } else {
+                color = listView.getStyle(Style.disabledColor);
+            }
+
+            label.putStyle(Style.color, color);
+
+            if (item != null) {
+                FileObject file = (FileObject) item;
+
+                // Update the image view
+                imageView.setImage(DRIVE_IMAGE);
+                imageView.putStyle(Style.opacity,
+                    (listView.isEnabled() && !disabled) ? 1.0f : 0.5f);
+
+                // Update the label
+                label.setText(file.toString());
+            }
+        }
+
+        @Override
+        public String toString(Object item) {
+            return null;
+        }
+    }
+
+    public abstract static class FileComparator implements 
Comparator<FileObject>, Serializable {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public abstract int compare(FileObject f1, FileObject f2);
+    }
+
+    public static class FileNameAscendingComparator extends FileComparator {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public int compare(FileObject f1, FileObject f2) {
+            FileType f1Type = f1.getName().getType();
+            FileType f2Type = f2.getName().getType();
+            boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
+            boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
+
+            int result;
+            if (!file1IsFile && file2IsFile) {
+                result = -1;
+            } else if (file1IsFile && !file2IsFile) {
+                result = 1;
+            } else {
+                // Do the compare according to the rules of the file system
+                result = f1.compareTo(f2);
+            }
+            return result;
+        }
+    }
+
+    public static class FileNameDescendingComparator extends FileComparator {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public int compare(FileObject f1, FileObject f2) {
+            FileType f1Type = f1.getName().getType();
+            FileType f2Type = f2.getName().getType();
+            boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
+            boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
+
+            int result;
+            if (!file1IsFile && file2IsFile) {
+                result = -1;
+            } else if (file1IsFile && !file2IsFile) {
+                result = 1;
+            } else {
+                // Do the compare according to the rules of the file system
+                result = f2.compareTo(f1);
+            }
+            return result;
+        }
+    }
+
+    public static class FileSizeAscendingComparator extends FileComparator {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public int compare(FileObject f1, FileObject f2) {
+            try {
+                FileType f1Type = f1.getName().getType();
+                FileType f2Type = f2.getName().getType();
+                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
+                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
+                long size1 = file1IsFile ? f1.getContent().getSize() : 0L;
+                long size2 = file2IsFile ? f2.getContent().getSize() : 0L;
+                return Long.signum(size1 - size2);
+            } catch (FileSystemException fse) {
+                throw new RuntimeException(fse);
+            }
+        }
+    }
+
+    public static class FileSizeDescendingComparator extends FileComparator {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public int compare(FileObject f1, FileObject f2) {
+            try {
+                FileType f1Type = f1.getName().getType();
+                FileType f2Type = f2.getName().getType();
+                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
+                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
+                long size1 = file1IsFile ? f1.getContent().getSize() : 0L;
+                long size2 = file2IsFile ? f2.getContent().getSize() : 0L;
+                return Long.signum(size2 - size1);
+            } catch (FileSystemException fse) {
+                throw new RuntimeException(fse);
+            }
+        }
+    }
+
+    public static class FileDateAscendingComparator extends FileComparator {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public int compare(FileObject f1, FileObject f2) {
+            try {
+                FileType f1Type = f1.getName().getType();
+                FileType f2Type = f2.getName().getType();
+                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
+                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
+                long time1 = file1IsFile ? 
f1.getContent().getLastModifiedTime() : 0L;
+                long time2 = file2IsFile ? 
f2.getContent().getLastModifiedTime() : 0L;
+                return Long.signum(time1 - time2);
+            } catch (FileSystemException fse) {
+                throw new RuntimeException(fse);
+            }
+        }
+    }
+
+    public static class FileDateDescendingComparator extends FileComparator {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public int compare(FileObject f1, FileObject f2) {
+            try {
+                FileType f1Type = f1.getName().getType();
+                FileType f2Type = f2.getName().getType();
+                boolean file1IsFile = f1Type == FileType.FILE || f1Type == 
FileType.FILE_OR_FOLDER;
+                boolean file2IsFile = f2Type == FileType.FILE || f2Type == 
FileType.FILE_OR_FOLDER;
+                long time1 = file1IsFile ? 
f1.getContent().getLastModifiedTime() : 0L;
+                long time2 = file2IsFile ? 
f2.getContent().getLastModifiedTime() : 0L;
+                return Long.signum(time2 - time1);
+            } catch (FileSystemException fse) {
+                throw new RuntimeException(fse);
+            }
+        }
+    }
+
+    /**
+     * @return A new {@link FileObject} comparator for the given column and 
sort order.
+     * @param columnName Name of the column to sort on.
+     * @param sortDirection The sort order.
+     */
+    public static FileComparator getFileComparator(String columnName, 
SortDirection sortDirection) {
+        if (columnName.equals("name")) {
+            return sortDirection == SortDirection.ASCENDING ? new 
FileNameAscendingComparator()
+                : new FileNameDescendingComparator();
+        } else if (columnName.equals("size")) {
+            return sortDirection == SortDirection.ASCENDING ? new 
FileSizeAscendingComparator()
+                : new FileSizeDescendingComparator();
+        } else if (columnName.equals("lastModified")) {
+            return sortDirection == SortDirection.ASCENDING ? new 
FileDateAscendingComparator()
+                : new FileDateDescendingComparator();
+        } else {
+            throw new IllegalArgumentException("Invalid column name for file 
comparator.");
+        }
+    }
+
+    /**
+     * Include file filter.
+     */
+    public static class IncludeFileFilter implements Filter<FileObject> {
+        private String match;
+
+        public IncludeFileFilter() {
+            this(null);
+        }
+
+        public IncludeFileFilter(String match) {
+            this.match = (match == null ? null : match.toLowerCase());
+        }
+
+        @Override
+        public boolean include(FileObject file) {
+            boolean include = true;
+
+            if (match != null) {
+                String name = file.getName().getBaseName();
+                name = name.toLowerCase();
+
+                if (match.startsWith("*")) {
+                    if (match.length() == 1) {
+                        include = true;
+                    } else {
+                        include = name.contains(match.substring(1));
+                    }
+                } else {
+                    include = name.startsWith(match);
+                }
+            }
+
+            return include;
+        }
+    }
+
+    public static class FullFileSelector implements FileSelector {
+        private FileFilter hiddenFileFilter;
+        private Filter<FileObject> includeFileFilter;
+        private Filter<FileObject> excludeFileFilter;
+
+        public FullFileSelector(boolean showHiddenFiles, Filter<FileObject> 
includeFileFilter,
+            Filter<FileObject> excludeFileFilter) {
+            this.hiddenFileFilter = showHiddenFiles ? null : 
HIDDEN_FILE_FILTER;
+            this.includeFileFilter = includeFileFilter;
+            this.excludeFileFilter = excludeFileFilter;
+        }
+
+        @Override
+        public boolean includeFile(FileSelectInfo fileInfo) {
+            boolean include = hiddenFileFilter == null ? true : 
hiddenFileFilter.accept(fileInfo);
+            if (include && includeFileFilter != null) {
+                include = includeFileFilter.include(fileInfo.getFile());
+            }
+            if (include && excludeFileFilter != null) {
+                include = !excludeFileFilter.include(fileInfo.getFile());
+            }
+            // Don't include the base folder itself
+            if (include && fileInfo.getFile() == fileInfo.getBaseFolder()) {
+                include = false;
+            }
+            return include;
+        }
+
+        @Override
+        public boolean traverseDescendents(FileSelectInfo fileInfo) {
+            // Only traverse the first-level descendents

[... 781 lines stripped ...]


Reply via email to