All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.schlichtherle.truezip.io.swing.FileComboBoxBrowser Maven / Gradle / Ivy

/*
 * Copyright (C) 2005-2013 Schlichtherle IT Services.
 * All rights reserved. Use is subject to license terms.
 */
package de.schlichtherle.truezip.io.swing;

import de.schlichtherle.truezip.swing.AbstractComboBoxBrowser;
import java.io.File;
import java.io.FilenameFilter;
import java.text.Collator;
import java.util.Arrays;
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.NotThreadSafe;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.filechooser.FileSystemView;

/**
 * Subclasses {@code AbstractComboBoxBrowser} to complete relative and
 * absolute path names of files and directories.
 * This class uses a {@link FileSystemView} in order to create file objects
 * for auto completion.
 * 

* To use it, use something like this: *

    JComboBox box = new JComboBox();
    new FileComboBoxBrowser(box);
    box.setEditable(true);
 * 
* * @author Christian Schlichtherle */ @NotThreadSafe public class FileComboBoxBrowser extends AbstractComboBoxBrowser { private static final long serialVersionUID = -6878885832542209810L; private transient @CheckForNull FileSystemView fileSystemView; private transient @CheckForNull File directory; /** * Constructs a new file combo box auto completion browser. * {@link #setComboBox} must be called in order to use this object. */ public FileComboBoxBrowser() { this(null, null); } public FileComboBoxBrowser(@CheckForNull JComboBox comboBox) { this(comboBox, null); } public FileComboBoxBrowser(@CheckForNull FileSystemView fileSystemView) { this(null, fileSystemView); } /** * Creates a new combo box auto completion browser. * * @param comboBox The combo box to enable browsing for auto completions. * May be {@code null}. */ public FileComboBoxBrowser( final @CheckForNull JComboBox comboBox, @CheckForNull FileSystemView fileSystemView) { super(comboBox); this.fileSystemView = fileSystemView; if (null != comboBox) { Object item = comboBox.getSelectedItem(); if (null == item || item instanceof String) update0((String) item); } } /** * Returns the directory which is used for autocompleting relative path * names. * If this property has been set to {@code null} before, it's reinitialized * by calling * {@link FileSystemView#createFileObject(String) createFileObject(".")} on * the current file system view, so {@code null} is never returned. * * @return The directory which is used for autocompleting relative path * names. */ public File getDirectory() { final File directory = this.directory; return null != directory ? directory : (this.directory = getFileSystemView().createFileObject(".")); } /** * Sets the directory which is used for autocompleting relative path names. * * @param directory The directory to use for autocompletion. * If this is {@code null}, the directory is reset to the * current directory. */ public void setDirectory(final @CheckForNull File directory) { this.directory = directory; } /** * Returns the file system view. * If this property has been set to {@code null} before, it's reinitialized * by calling {@link FileSystemView#getFileSystemView()}, so {@code null} * is never returned. * * @return The file system view. */ public FileSystemView getFileSystemView() { final FileSystemView fileSystemView = this.fileSystemView; return null != fileSystemView ? fileSystemView : (this.fileSystemView = FileSystemView.getFileSystemView()); } /** * Sets the file system view. * * @param fileSystemView the file system view. */ public void setFileSystemView(final @CheckForNull FileSystemView fileSystemView) { this.fileSystemView = fileSystemView; } /** * Interpretes the specified {@code initials} as the initial * characters of an absolute or relative path name of a node in the file * system and updates the contents of the combo box model with possible * completions. * The elements in the combo box model are sorted according to their * natural comparison order. * * @param initials The initial characters of a file or directory path name. * May be {@code null}. * @return {@code true} if and only if the file system contains a * node with {@code initials} as its initial characters and * hence the popup window with the completions should be shown. * @throws NullPointerException If the {@code comboBox} property is * {@code null}. */ @Override protected boolean update(@CheckForNull String initials) { return update0(initials); } private boolean update0(@CheckForNull String initials) { File dir = getDirectory(); // This is actually a pretty ugly piece of code, but I don't know // of any other way to implement this so that a user can use his // platform specific file separator (e.g. '\\' on Windows) // AND the standard URI name separator '/' in a file path // name. if (null == initials) initials = ""; // Identify the directory to list, the prefix of the elements we want // to find and the base string which prepends the elements we will find. final String prefix, base; if ("".equals(initials)) { prefix = base = ""; } else { File node = getFileSystemView().createFileObject(initials); if (node.isAbsolute()) { final boolean dirPath = node.getPath().length() < initials.length(); // TODO: Evaluate why this was needed in TrueZIP 6 and if it's // still required in TrueZIP 7. /*if (dirPath) PromptingKeyManager.resetCancelledPrompts();*/ // The test order is important here because isDirectory() may // actually prompt the user for a key if node is an RAES // encrypted ZIP file! if (dirPath && node.isDirectory()) { dir = node; prefix = ""; } else { dir = node.getParentFile(); if (dir == null) { dir = node; prefix = ""; } else { prefix = node.getName(); } } if (dir.getPath().endsWith(File.separator)) { // dir is the root of a file system. base = initials.substring(0, dir.getPath().length()); } else { // Otherwise keep the user provided file separator. base = initials.substring(0, dir.getPath().length() + 1); } } else { final File directory = dir; node = getFileSystemView().createFileObject(directory, initials); // copies archive detector from directory final boolean dirPath = node.getPath().length() < (directory.getPath() + File.separator + initials).length(); // TODO: Evaluate why this was needed in TrueZIP 6 and if it's // still required in TrueZIP 7. /*if (dirPath) PromptingKeyManager.resetCancelledPrompts();*/ // The test order is important here because isDirectory() may // actually prompt the user! if (dirPath && node.isDirectory()) { dir = node; prefix = ""; } else { dir = node.getParentFile(); assert dir != null : "node is child of directory"; prefix = node.getName(); } // Keep the platform specific file separator. base = initials.substring(0, dir.getPath().length() - directory.getPath().length()); } } final FilenameFilter filter; /*if (TFile.separatorChar != '\\') { // Consider case (Unix). filter = new FilenameFilter() { public boolean accept(java.io.TFile d, String child) { return child.startsWith(prefix); } }; } else {*/ // Ignore case (Windows). class Filter implements FilenameFilter { final int pl = prefix.length(); @Override public boolean accept(File d, String child) { if (child.length() >= pl) return prefix.equalsIgnoreCase(child.substring(0, pl)); else return false; } } // class Filter filter = new Filter(); //} final String[] children = dir.list(filter); // Update combo box model. // Note that the list MUST be cleared and repopulated because its // current content does not need to reflect the status of the edited // initials. final DefaultComboBoxModel model = (DefaultComboBoxModel) getComboBox().getModel(); try { model.removeAllElements(); final int l = null == children ? 0 : children.length; if (0 < l) { Arrays.sort(children, Collator.getInstance()); // get nice sorting order for (int i = 0; i < l; i++) model.addElement(base + children[i]); return true; // show popup } else { // Leave initials als sole content of the list. model.addElement(initials); return false; // hide popup } } finally { if (!initials.equals(model.getSelectedItem())) // check required! model.setSelectedItem(initials); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy