blob: 1935c64c2b57639ac25e103989cebac6a1ad029a [file] [log] [blame]
/*
* 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;
import java.io.File;
import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.Sequence;
import org.apache.pivot.collections.immutable.ImmutableList;
import org.apache.pivot.io.FileList;
import org.apache.pivot.util.Filter;
import org.apache.pivot.util.ListenerList;
/**
* Component representing a file browser.
*/
public class FileBrowser extends Container {
/**
* File browser skin interface.
*/
public interface Skin extends org.apache.pivot.wtk.Skin {
public File getFileAt(int x, int y);
}
private static final String USER_HOME = System.getProperty("user.home");
private static class FileBrowserListenerList extends WTKListenerList<FileBrowserListener>
implements FileBrowserListener {
@Override
public void rootDirectoryChanged(FileBrowser fileBrowser, File previousRootDirectory) {
for (FileBrowserListener listener : this) {
listener.rootDirectoryChanged(fileBrowser, previousRootDirectory);
}
}
@Override
public void selectedFileAdded(FileBrowser fileBrowser, File file) {
for (FileBrowserListener listener : this) {
listener.selectedFileAdded(fileBrowser, file);
}
}
@Override
public void selectedFileRemoved(FileBrowser fileBrowser, File file) {
for (FileBrowserListener listener : this) {
listener.selectedFileRemoved(fileBrowser, file);
}
}
@Override
public void selectedFilesChanged(FileBrowser fileBrowser,
Sequence<File> previousSelectedFiles) {
for (FileBrowserListener listener : this) {
listener.selectedFilesChanged(fileBrowser, previousSelectedFiles);
}
}
@Override
public void multiSelectChanged(FileBrowser fileBrowser) {
for (FileBrowserListener listener : this) {
listener.multiSelectChanged(fileBrowser);
}
}
@Override
public void disabledFileFilterChanged(FileBrowser fileBrowser,
Filter<File> previousDisabledFileFilter) {
for (FileBrowserListener listener : this) {
listener.disabledFileFilterChanged(fileBrowser, previousDisabledFileFilter);
}
}
}
private File rootDirectory;
private FileList selectedFiles = new FileList();
private boolean multiSelect = false;
private Filter<File> disabledFileFilter = null;
private FileBrowserListenerList fileBrowserListeners = new FileBrowserListenerList();
/**
* Creates a new FileBrowser <p> Note that this version set by default mode
* to open.
*/
public FileBrowser() {
this(USER_HOME);
}
/**
* Creates a new FileBrowser <p> Note that this version of the constructor
* must be used when a custom root folder has to be set.
*
* @param rootFolder The root folder full name.
*/
public FileBrowser(String rootFolder) {
if (rootFolder == null) {
throw new IllegalArgumentException();
}
rootDirectory = new File(rootFolder);
if (!rootDirectory.isDirectory()) {
throw new IllegalArgumentException();
}
installSkin(FileBrowser.class);
}
/**
* Returns the current root directory.
*
* @return The current root directory.
*/
public File getRootDirectory() {
return rootDirectory;
}
/**
* Sets the root directory. Clears any existing file selection.
*
* @param rootDirectory The new root directory to browse in.
* @throws IllegalArgumentException if the argument is {@code null}
* or is not a directory.
*/
public void setRootDirectory(File rootDirectory) {
if (rootDirectory == null || !rootDirectory.isDirectory()) {
throw new IllegalArgumentException();
}
if (rootDirectory.exists()) {
File previousRootDirectory = this.rootDirectory;
if (!rootDirectory.equals(previousRootDirectory)) {
this.rootDirectory = rootDirectory;
selectedFiles.clear();
fileBrowserListeners.rootDirectoryChanged(this, previousRootDirectory);
}
} else {
setRootDirectory(rootDirectory.getParentFile());
}
}
/**
* Adds a file to the file selection.
*
* @param file The new file to add to the selection.
* @return <tt>true</tt> if the file was added; <tt>false</tt> if it was
* already selected.
* @throws IllegalArgumentException if the file argument is {@code null}
* or if the file is not in the current root directory.
*/
public boolean addSelectedFile(final File file) {
if (file == null) {
throw new IllegalArgumentException();
}
File fileMutable = file;
if (fileMutable.isAbsolute()) {
if (!fileMutable.getParentFile().equals(rootDirectory)) {
throw new IllegalArgumentException();
}
} else {
fileMutable = new File(rootDirectory, fileMutable.getPath());
}
int index = selectedFiles.add(fileMutable);
if (index != -1) {
fileBrowserListeners.selectedFileAdded(this, fileMutable);
}
return (index != -1);
}
/**
* Removes a file from the file selection.
*
* @param file The previously selected file to be removed from the selection.
* @return <tt>true</tt> if the file was removed; <tt>false</tt> if it was
* not already selected.
* @throws IllegalArgumentException if the file argument is {@code null}.
*/
public boolean removeSelectedFile(File file) {
if (file == null) {
throw new IllegalArgumentException();
}
int index = selectedFiles.remove(file);
if (index != -1) {
fileBrowserListeners.selectedFileRemoved(this, file);
}
return (index != -1);
}
/**
* When in single-select mode, returns the currently selected file.
*
* @return The currently selected file.
*/
public File getSelectedFile() {
if (multiSelect) {
throw new IllegalStateException("File browser is not in single-select mode.");
}
return (selectedFiles.getLength() == 0) ? null : selectedFiles.get(0);
}
/**
* Sets the selection to a single file.
*
* @param file The only file to select, or {@code null} to select nothing.
*/
public void setSelectedFile(File file) {
if (file == null) {
clearSelection();
} else {
if (file.isAbsolute()) {
setRootDirectory(file.getParentFile());
}
setSelectedFiles(new ArrayList<>(file));
}
}
/**
* Returns the currently selected files.
*
* @return An immutable list containing the currently selected files. Note
* that the returned list is a wrapper around the actual selection, not a
* copy. Any changes made to the selection state will be reflected in the
* list, but events will not be fired.
*/
public ImmutableList<File> getSelectedFiles() {
return new ImmutableList<>(selectedFiles);
}
/**
* Sets the selected files.
*
* @param selectedFiles The files to select.
* @return The files that were selected, with duplicates eliminated.
* @throws IllegalArgumentException if the selected files sequence is {@code null}
* or if the sequence is longer than one file and multi-select is not enabled, or
* if any entry is the sequence is {@code null} or whose parent is not the
* current root directory.
*/
public Sequence<File> setSelectedFiles(Sequence<File> selectedFiles) {
if (selectedFiles == null) {
throw new IllegalArgumentException("selectedFiles is null.");
}
if (!multiSelect && selectedFiles.getLength() > 1) {
throw new IllegalArgumentException("Multi-select is not enabled.");
}
// Update the selection
Sequence<File> previousSelectedFiles = getSelectedFiles();
FileList fileList = new FileList();
for (int i = 0, n = selectedFiles.getLength(); i < n; i++) {
File file = selectedFiles.get(i);
if (file == null) {
throw new IllegalArgumentException("file is null.");
}
if (!file.isAbsolute()) {
file = new File(rootDirectory, file.getPath());
}
if (!file.getParentFile().equals(rootDirectory)) {
throw new IllegalArgumentException();
}
fileList.add(file);
}
this.selectedFiles = fileList;
// Notify listeners
fileBrowserListeners.selectedFilesChanged(this, previousSelectedFiles);
return getSelectedFiles();
}
/**
* Clears the selection.
*/
public void clearSelection() {
setSelectedFiles(new ArrayList<File>());
}
public boolean isFileSelected(File file) {
return (selectedFiles.indexOf(file) != -1);
}
/**
* @return The file browser's multi-select state.
*/
public boolean isMultiSelect() {
return multiSelect;
}
/**
* Sets the file browser's multi-select state.
*
* @param multiSelect <tt>true</tt> if multi-select is enabled;
* <tt>false</tt>, otherwise.
*/
public void setMultiSelect(boolean multiSelect) {
if (this.multiSelect != multiSelect) {
// Clear any existing selection
selectedFiles.clear();
this.multiSelect = multiSelect;
fileBrowserListeners.multiSelectChanged(this);
}
}
/**
* Returns the current file filter.
*
* @return The current file filter, or <tt>null</tt> if no filter is set.
*/
public Filter<File> getDisabledFileFilter() {
return disabledFileFilter;
}
/**
* Sets the file filter.
*
* @param disabledFileFilter The file filter to use, or <tt>null</tt> for no
* filter.
*/
public void setDisabledFileFilter(Filter<File> disabledFileFilter) {
Filter<File> previousDisabledFileFilter = this.disabledFileFilter;
if (previousDisabledFileFilter != disabledFileFilter) {
this.disabledFileFilter = disabledFileFilter;
fileBrowserListeners.disabledFileFilterChanged(this, previousDisabledFileFilter);
}
}
public File getFileAt(int x, int y) {
FileBrowser.Skin fileBrowserSkin = (FileBrowser.Skin) getSkin();
return fileBrowserSkin.getFileAt(x, y);
}
public ListenerList<FileBrowserListener> getFileBrowserListeners() {
return fileBrowserListeners;
}
}