Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/swing/plaf/synth/SynthFileChooserUI.java
38918 views
/*1* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package sun.swing.plaf.synth;2526import javax.swing.plaf.synth.*;27import java.awt.*;28import java.awt.event.*;29import java.beans.*;30import java.io.File;31import java.util.regex.*;3233import javax.swing.*;34import javax.swing.border.*;35import javax.swing.event.*;36import javax.swing.filechooser.*;37import javax.swing.plaf.*;38import javax.swing.plaf.basic.BasicFileChooserUI;3940/**41* Synth FileChooserUI.42*43* Note: This class is abstract. It does not actually create the file chooser GUI.44* <p>45* Note that the classes in the com.sun.java.swing.plaf.synth46* package are not47* part of the core Java APIs. They are a part of Sun's JDK and JRE48* distributions. Although other licensees may choose to distribute49* these classes, developers cannot depend on their availability in50* non-Sun implementations. Additionally this API may change in51* incompatible ways between releases. While this class is public, it52* shoud be considered an implementation detail, and subject to change.53*54* @author Leif Samuelsson55* @author Jeff Dinkins56*/57public abstract class SynthFileChooserUI extends BasicFileChooserUI implements58SynthUI {59private JButton approveButton, cancelButton;6061private SynthStyle style;6263// Some generic FileChooser functions64private Action fileNameCompletionAction = new FileNameCompletionAction();6566private FileFilter actualFileFilter = null;67private GlobFilter globFilter = null;6869public static ComponentUI createUI(JComponent c) {70return new SynthFileChooserUIImpl((JFileChooser)c);71}7273public SynthFileChooserUI(JFileChooser b) {74super(b);75}7677public SynthContext getContext(JComponent c) {78return new SynthContext(c, Region.FILE_CHOOSER, style,79getComponentState(c));80}8182protected SynthContext getContext(JComponent c, int state) {83Region region = SynthLookAndFeel.getRegion(c);84return new SynthContext(c, Region.FILE_CHOOSER, style, state);85}8687private Region getRegion(JComponent c) {88return SynthLookAndFeel.getRegion(c);89}9091private int getComponentState(JComponent c) {92if (c.isEnabled()) {93if (c.isFocusOwner()) {94return ENABLED | FOCUSED;95}96return ENABLED;97}98return DISABLED;99}100101private void updateStyle(JComponent c) {102SynthStyle newStyle = SynthLookAndFeel.getStyleFactory().getStyle(c,103Region.FILE_CHOOSER);104if (newStyle != style) {105if (style != null) {106style.uninstallDefaults(getContext(c, ENABLED));107}108style = newStyle;109SynthContext context = getContext(c, ENABLED);110style.installDefaults(context);111Border border = c.getBorder();112if (border == null || border instanceof UIResource) {113c.setBorder(new UIBorder(style.getInsets(context, null)));114}115116directoryIcon = style.getIcon(context, "FileView.directoryIcon");117fileIcon = style.getIcon(context, "FileView.fileIcon");118computerIcon = style.getIcon(context, "FileView.computerIcon");119hardDriveIcon = style.getIcon(context, "FileView.hardDriveIcon");120floppyDriveIcon = style.getIcon(context, "FileView.floppyDriveIcon");121122newFolderIcon = style.getIcon(context, "FileChooser.newFolderIcon");123upFolderIcon = style.getIcon(context, "FileChooser.upFolderIcon");124homeFolderIcon = style.getIcon(context, "FileChooser.homeFolderIcon");125detailsViewIcon = style.getIcon(context, "FileChooser.detailsViewIcon");126listViewIcon = style.getIcon(context, "FileChooser.listViewIcon");127}128}129130public void installUI(JComponent c) {131super.installUI(c);132SwingUtilities.replaceUIActionMap(c, createActionMap());133}134135public void installComponents(JFileChooser fc) {136SynthContext context = getContext(fc, ENABLED);137138cancelButton = new JButton(cancelButtonText);139cancelButton.setName("SynthFileChooser.cancelButton");140cancelButton.setIcon(context.getStyle().getIcon(context, "FileChooser.cancelIcon"));141cancelButton.setMnemonic(cancelButtonMnemonic);142cancelButton.setToolTipText(cancelButtonToolTipText);143cancelButton.addActionListener(getCancelSelectionAction());144145approveButton = new JButton(getApproveButtonText(fc));146approveButton.setName("SynthFileChooser.approveButton");147approveButton.setIcon(context.getStyle().getIcon(context, "FileChooser.okIcon"));148approveButton.setMnemonic(getApproveButtonMnemonic(fc));149approveButton.setToolTipText(getApproveButtonToolTipText(fc));150approveButton.addActionListener(getApproveSelectionAction());151152}153154public void uninstallComponents(JFileChooser fc) {155fc.removeAll();156}157158protected void installListeners(JFileChooser fc) {159super.installListeners(fc);160161getModel().addListDataListener(new ListDataListener() {162public void contentsChanged(ListDataEvent e) {163// Update the selection after JList has been updated164new DelayedSelectionUpdater();165}166public void intervalAdded(ListDataEvent e) {167new DelayedSelectionUpdater();168}169public void intervalRemoved(ListDataEvent e) {170}171});172173}174175private class DelayedSelectionUpdater implements Runnable {176DelayedSelectionUpdater() {177SwingUtilities.invokeLater(this);178}179180public void run() {181updateFileNameCompletion();182}183}184185protected abstract ActionMap createActionMap();186187188protected void installDefaults(JFileChooser fc) {189super.installDefaults(fc);190updateStyle(fc);191}192193protected void uninstallDefaults(JFileChooser fc) {194super.uninstallDefaults(fc);195196SynthContext context = getContext(getFileChooser(), ENABLED);197style.uninstallDefaults(context);198style = null;199}200201protected void installIcons(JFileChooser fc) {202// The icons are installed in updateStyle, not here203}204205public void update(Graphics g, JComponent c) {206SynthContext context = getContext(c);207208if (c.isOpaque()) {209g.setColor(style.getColor(context, ColorType.BACKGROUND));210g.fillRect(0, 0, c.getWidth(), c.getHeight());211}212213style.getPainter(context).paintFileChooserBackground(context,214g, 0, 0, c.getWidth(), c.getHeight());215paint(context, g);216}217218public void paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h) {219}220221public void paint(Graphics g, JComponent c) {222SynthContext context = getContext(c);223224paint(context, g);225}226227protected void paint(SynthContext context, Graphics g) {228}229230abstract public void setFileName(String fileName);231abstract public String getFileName();232233protected void doSelectedFileChanged(PropertyChangeEvent e) {234}235236protected void doSelectedFilesChanged(PropertyChangeEvent e) {237}238239protected void doDirectoryChanged(PropertyChangeEvent e) {240}241242protected void doAccessoryChanged(PropertyChangeEvent e) {243}244245protected void doFileSelectionModeChanged(PropertyChangeEvent e) {246}247248protected void doMultiSelectionChanged(PropertyChangeEvent e) {249if (!getFileChooser().isMultiSelectionEnabled()) {250getFileChooser().setSelectedFiles(null);251}252}253254protected void doControlButtonsChanged(PropertyChangeEvent e) {255if (getFileChooser().getControlButtonsAreShown()) {256approveButton.setText(getApproveButtonText(getFileChooser()));257approveButton.setToolTipText(getApproveButtonToolTipText(getFileChooser()));258approveButton.setMnemonic(getApproveButtonMnemonic(getFileChooser()));259}260}261262protected void doAncestorChanged(PropertyChangeEvent e) {263}264265public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {266return new SynthFCPropertyChangeListener();267}268269private class SynthFCPropertyChangeListener implements PropertyChangeListener {270public void propertyChange(PropertyChangeEvent e) {271String prop = e.getPropertyName();272if (prop.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {273doFileSelectionModeChanged(e);274} else if (prop.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {275doSelectedFileChanged(e);276} else if (prop.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) {277doSelectedFilesChanged(e);278} else if (prop.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {279doDirectoryChanged(e);280} else if (prop == JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY) {281doMultiSelectionChanged(e);282} else if (prop == JFileChooser.ACCESSORY_CHANGED_PROPERTY) {283doAccessoryChanged(e);284} else if (prop == JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY ||285prop == JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY ||286prop == JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY ||287prop == JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY) {288doControlButtonsChanged(e);289} else if (prop.equals("componentOrientation")) {290ComponentOrientation o = (ComponentOrientation)e.getNewValue();291JFileChooser cc = (JFileChooser)e.getSource();292if (o != (ComponentOrientation)e.getOldValue()) {293cc.applyComponentOrientation(o);294}295} else if (prop.equals("ancestor")) {296doAncestorChanged(e);297}298}299}300301302/**303* Responds to a File Name completion request (e.g. Tab)304*/305private class FileNameCompletionAction extends AbstractAction {306protected FileNameCompletionAction() {307super("fileNameCompletion");308}309310public void actionPerformed(ActionEvent e) {311JFileChooser chooser = getFileChooser();312313String fileName = getFileName();314315if (fileName != null) {316// Remove whitespace from beginning and end of filename317fileName = fileName.trim();318}319320resetGlobFilter();321322if (fileName == null || fileName.equals("") ||323(chooser.isMultiSelectionEnabled() && fileName.startsWith("\""))) {324return;325}326327FileFilter currentFilter = chooser.getFileFilter();328if (globFilter == null) {329globFilter = new GlobFilter();330}331try {332globFilter.setPattern(!isGlobPattern(fileName) ? fileName + "*" : fileName);333if (!(currentFilter instanceof GlobFilter)) {334actualFileFilter = currentFilter;335}336chooser.setFileFilter(null);337chooser.setFileFilter(globFilter);338fileNameCompletionString = fileName;339} catch (PatternSyntaxException pse) {340// Not a valid glob pattern. Abandon filter.341}342}343}344345private String fileNameCompletionString;346347private void updateFileNameCompletion() {348if (fileNameCompletionString != null) {349if (fileNameCompletionString.equals(getFileName())) {350File[] files = getModel().getFiles().toArray(new File[0]);351String str = getCommonStartString(files);352if (str != null && str.startsWith(fileNameCompletionString)) {353setFileName(str);354}355fileNameCompletionString = null;356}357}358}359360private String getCommonStartString(File[] files) {361String str = null;362String str2 = null;363int i = 0;364if (files.length == 0) {365return null;366}367while (true) {368for (int f = 0; f < files.length; f++) {369String name = files[f].getName();370if (f == 0) {371if (name.length() == i) {372return str;373}374str2 = name.substring(0, i+1);375}376if (!name.startsWith(str2)) {377return str;378}379}380str = str2;381i++;382}383}384385private void resetGlobFilter() {386if (actualFileFilter != null) {387JFileChooser chooser = getFileChooser();388FileFilter currentFilter = chooser.getFileFilter();389if (currentFilter != null && currentFilter.equals(globFilter)) {390chooser.setFileFilter(actualFileFilter);391chooser.removeChoosableFileFilter(globFilter);392}393actualFileFilter = null;394}395}396397private static boolean isGlobPattern(String fileName) {398return ((File.separatorChar == '\\' && fileName.indexOf('*') >= 0)399|| (File.separatorChar == '/' && (fileName.indexOf('*') >= 0400|| fileName.indexOf('?') >= 0401|| fileName.indexOf('[') >= 0)));402}403404405/* A file filter which accepts file patterns containing406* the special wildcard '*' on windows, plus '?', and '[ ]' on Unix.407*/408class GlobFilter extends FileFilter {409Pattern pattern;410String globPattern;411412public void setPattern(String globPattern) {413char[] gPat = globPattern.toCharArray();414char[] rPat = new char[gPat.length * 2];415boolean isWin32 = (File.separatorChar == '\\');416boolean inBrackets = false;417int j = 0;418419this.globPattern = globPattern;420421if (isWin32) {422// On windows, a pattern ending with *.* is equal to ending with *423int len = gPat.length;424if (globPattern.endsWith("*.*")) {425len -= 2;426}427for (int i = 0; i < len; i++) {428if (gPat[i] == '*') {429rPat[j++] = '.';430}431rPat[j++] = gPat[i];432}433} else {434for (int i = 0; i < gPat.length; i++) {435switch(gPat[i]) {436case '*':437if (!inBrackets) {438rPat[j++] = '.';439}440rPat[j++] = '*';441break;442443case '?':444rPat[j++] = inBrackets ? '?' : '.';445break;446447case '[':448inBrackets = true;449rPat[j++] = gPat[i];450451if (i < gPat.length - 1) {452switch (gPat[i+1]) {453case '!':454case '^':455rPat[j++] = '^';456i++;457break;458459case ']':460rPat[j++] = gPat[++i];461break;462}463}464break;465466case ']':467rPat[j++] = gPat[i];468inBrackets = false;469break;470471case '\\':472if (i == 0 && gPat.length > 1 && gPat[1] == '~') {473rPat[j++] = gPat[++i];474} else {475rPat[j++] = '\\';476if (i < gPat.length - 1 && "*?[]".indexOf(gPat[i+1]) >= 0) {477rPat[j++] = gPat[++i];478} else {479rPat[j++] = '\\';480}481}482break;483484default:485//if ("+()|^$.{}<>".indexOf(gPat[i]) >= 0) {486if (!Character.isLetterOrDigit(gPat[i])) {487rPat[j++] = '\\';488}489rPat[j++] = gPat[i];490break;491}492}493}494this.pattern = Pattern.compile(new String(rPat, 0, j), Pattern.CASE_INSENSITIVE);495}496497public boolean accept(File f) {498if (f == null) {499return false;500}501if (f.isDirectory()) {502return true;503}504return pattern.matcher(f.getName()).matches();505}506507public String getDescription() {508return globPattern;509}510}511512513// *******************************************************514// ************ FileChooser UI PLAF methods **************515// *******************************************************516517518// *****************************519// ***** Directory Actions *****520// *****************************521522public Action getFileNameCompletionAction() {523return fileNameCompletionAction;524}525526527protected JButton getApproveButton(JFileChooser fc) {528return approveButton;529}530531protected JButton getCancelButton(JFileChooser fc) {532return cancelButton;533}534535536// Overload to do nothing. We don't have and icon cache.537public void clearIconCache() { }538539// Copied as SynthBorder is package private in synth540private class UIBorder extends AbstractBorder implements UIResource {541private Insets _insets;542UIBorder(Insets insets) {543if (insets != null) {544_insets = new Insets(insets.top, insets.left, insets.bottom,545insets.right);546}547else {548_insets = null;549}550}551552public void paintBorder(Component c, Graphics g, int x, int y,553int width, int height) {554if (!(c instanceof JComponent)) {555return;556}557JComponent jc = (JComponent)c;558SynthContext context = getContext(jc);559SynthStyle style = context.getStyle();560if (style != null) {561style.getPainter(context).paintFileChooserBorder(562context, g, x, y, width, height);563}564}565566public Insets getBorderInsets(Component c, Insets insets) {567if (insets == null) {568insets = new Insets(0, 0, 0, 0);569}570if (_insets != null) {571insets.top = _insets.top;572insets.bottom = _insets.bottom;573insets.left = _insets.left;574insets.right = _insets.right;575}576else {577insets.top = insets.bottom = insets.right = insets.left = 0;578}579return insets;580}581public boolean isBorderOpaque() {582return false;583}584}585}586587588