/* * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package sun.awt.X11; import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.awt.peer.*; import java.io.*; import java.util.Locale; import sun.util.logging.PlatformLogger; import sun.awt.AWTAccessor; /** * DirectoryDialogPeer for X-Windows. * * @author Costantino Cerbo (c.cerbo@gmail.com) */ class XDirectoryDialogPeer extends XDialogPeer implements DirectoryDialogPeer, ActionListener, ItemListener, KeyEventDispatcher, XChoicePeerListener { private static final PlatformLogger log = PlatformLogger .getLogger("sun.awt.X11.XFileDialogPeer"); private static final int PATH_CHOICE_WIDTH = 20; private DirectoryDialog directoryDialog; // ************** Components in the fileDialogWindow *************** private List directoryList; private Choice pathChoice; private TextField pathField; private String dir; XDirectoryDialogPeer(DirectoryDialog directoryDialog) { super((Dialog) directoryDialog); this.directoryDialog = directoryDialog; if (directoryDialog.getDirectory() == null) { AWTAccessor.getDirectoryDialogAccessor().setDirectory( directoryDialog, System.getProperty("user.dir")); } this.dir = directoryDialog.getDirectory(); Locale l = directoryDialog.getLocale(); UIDefaults uid = XToolkit.getUIDefaults(); GridBagLayout gbl = new GridBagLayout(); GridBagLayout gblButtons = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); directoryDialog.setLayout(gbl); directoryDialog.setMinimumSize(new Dimension(400, 400)); // create components Panel buttons = new Panel(); buttons.setLayout(gblButtons); Button openButton = new Button(uid.getString( "FileChooser.openButtonText", l)); openButton.setActionCommand("openButton"); Button cancelButton = new Button(uid.getString( "FileChooser.cancelButtonText", l)); cancelButton.setActionCommand("cancelButton"); directoryList = new List(); // the insets used by the components in the dialog Insets noInset = new Insets(0, 0, 0, 0); Insets textFieldInset = new Insets(0, 8, 0, 8); Insets leftListInset = new Insets(0, 8, 0, 4); Insets separatorInset = new Insets(8, 0, 0, 0); Insets labelInset = new Insets(0, 8, 0, 0); Insets buttonsInset = new Insets(10, 8, 10, 8); // add components to GridBagLayout "gbl" Font f = new Font(Font.DIALOG, Font.PLAIN, 12); Label label = new Label(uid.getString("FileChooser.pathLabelText", l)); label.setFont(f); addComponent(label, gbl, gbc, 0, 0, 1, GridBagConstraints.WEST, (Container) directoryDialog, 1, 0, GridBagConstraints.NONE, labelInset); pathField = new TextField(dir); listFolders(dir); pathChoice = new Choice() { @Override public Dimension getPreferredSize() { return new Dimension(PATH_CHOICE_WIDTH, pathField .getPreferredSize().height); } }; Panel pathPanel = new Panel(); pathPanel.setLayout(new BorderLayout()); pathPanel.add(pathField, BorderLayout.CENTER); pathPanel.add(pathChoice, BorderLayout.EAST); addComponent(pathPanel, gbl, gbc, 0, 1, 2, GridBagConstraints.WEST, (Container) directoryDialog, 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset); label = new Label(uid.getString("FileChooser.foldersLabelText", l)); label.setFont(f); addComponent(label, gbl, gbc, 0, 4, 1, GridBagConstraints.WEST, (Container) directoryDialog, 1, 0, GridBagConstraints.NONE, labelInset); addComponent(directoryList, gbl, gbc, 0, 5, 1, GridBagConstraints.WEST, (Container) directoryDialog, 1, 1, GridBagConstraints.BOTH, leftListInset); // Separator addComponent(new Separator(directoryDialog.getSize().width, 2, Separator.HORIZONTAL), gbl, gbc, 0, 8, 15, GridBagConstraints.WEST, (Container) directoryDialog, 1, 0, GridBagConstraints.HORIZONTAL, separatorInset); // add buttons to GridBagLayout Buttons addComponent(openButton, gblButtons, gbc, 0, 0, 1, GridBagConstraints.WEST, (Container) buttons, 1, 0, GridBagConstraints.NONE, noInset); addComponent(cancelButton, gblButtons, gbc, 2, 0, 1, GridBagConstraints.EAST, (Container) buttons, 1, 0, GridBagConstraints.NONE, noInset); // add ButtonPanel to the GridBagLayout of this class addComponent(buttons, gbl, gbc, 0, 9, 2, GridBagConstraints.WEST, (Container) directoryDialog, 1, 0, GridBagConstraints.HORIZONTAL, buttonsInset); directoryList.addActionListener(this); openButton.addActionListener(this); cancelButton.addActionListener(this); pathChoice.addItemListener(this); pathField.addActionListener(this); // b6227750 FileDialog is not disposed when clicking the 'close' (X) // button on the top right corner, XToolkit directoryDialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { handleCancel(); } }); } @Override public void updateIconImages() { if (winAttr.icons == null) { winAttr.iconsInherited = false; winAttr.icons = getDefaultIconInfo(); setIconHints(winAttr.icons); } } /** * add Component comp to the container cont. add the component to the * correct GridBagLayout */ private void addComponent(Component comp, GridBagLayout gb, GridBagConstraints c, int gridx, int gridy, int gridwidth, int anchor, Container cont, int weightx, int weighty, int fill, Insets in) { c.gridx = gridx; c.gridy = gridy; c.gridwidth = gridwidth; c.anchor = anchor; c.weightx = weightx; c.weighty = weighty; c.fill = fill; c.insets = in; gb.setConstraints(comp, c); cont.add(comp); } /** * handle the selection event */ private void handleSelection() { String newDir = pathField.getText() + File.separator; if (directoryList.getSelectedItem() != null) { if (!newDir.endsWith(File.separator)) { newDir += File.separator; } newDir += directoryList.getSelectedItem(); } if (newDir.equals(dir)) { return; } listFolders(newDir); setDirectory(newDir); } @Override public void setDirectory(String dir) { if (dir == null) { this.dir = null; return; } if (dir.equals(this.dir)) { return; } int i; if ((i = dir.indexOf("~")) != -1) { dir = dir.substring(0, i) + System.getProperty("user.home") + dir.substring(i + 1, dir.length()); } File fe = new File(dir).getAbsoluteFile(); log.fine("Current directory : " + fe); if (!fe.isDirectory()) { dir = "./"; fe = new File(dir).getAbsoluteFile(); if (!fe.isDirectory()) { return; } } try { dir = this.dir = fe.getCanonicalPath(); } catch (java.io.IOException ie) { dir = this.dir = fe.getAbsolutePath(); } pathField.setText(this.dir); if (dir.endsWith("/")) { this.dir = dir; } else { this.dir = dir + "/"; } AWTAccessor.getDirectoryDialogAccessor().setDirectory(directoryDialog, this.dir); } private void listFolders(String folder) { File[] files = new File(folder).listFiles(); java.util.Arrays.sort(files); directoryList.clear(); directoryList.addItem(".."); for (File file : files) { if (file.isDirectory()) { directoryList.addItem(file.getName() + "/"); } } } /** * handle the cancel event */ private void handleCancel() { KeyboardFocusManager.getCurrentKeyboardFocusManager() .removeKeyEventDispatcher(this); directoryList.clear(); AWTAccessor.getDirectoryDialogAccessor().setDirectory(directoryDialog, null); handleQuitButton(); } /** * handle the quit event */ private void handleQuitButton() { dir = null; directoryDialog.setVisible(false); } private String[] getDirList(String dir) { if (!dir.endsWith("/")) { dir = dir + "/"; } char[] charr = dir.toCharArray(); int numSlashes = 0; for (int i = 0; i < charr.length; i++) { if (charr[i] == '/') { numSlashes++; } } String[] starr = new String[numSlashes]; int j = 0; for (int i = charr.length - 1; i >= 0; i--) { if (charr[i] == '/') { starr[j++] = new String(charr, 0, i + 1); } } return starr; } /** * * @see java.awt.event.ItemEvent ItemEvent.ITEM_STATE_CHANGED */ public void itemStateChanged(ItemEvent itemEvent) { if (itemEvent.getID() != ItemEvent.ITEM_STATE_CHANGED || itemEvent.getStateChange() == ItemEvent.DESELECTED) { return; } Object source = itemEvent.getSource(); if (source == pathChoice) { /* * Update the selection ('folder name' text field) after the current * item changing in the unfurled choice by the arrow keys. See * 6259434, 6240074 for more information */ String selectedDir = pathChoice.getSelectedItem(); pathField.setText(selectedDir); handleSelection(); } } public void actionPerformed(ActionEvent actionEvent) { String actionCommand = actionEvent.getActionCommand(); Object source = actionEvent.getSource(); if (actionCommand.equals("openButton")) { handleQuitButton(); } else if (actionCommand.equals("cancelButton")) { handleCancel(); } else if (source == pathField || source == directoryList) { handleSelection(); } } public boolean dispatchKeyEvent(KeyEvent keyEvent) { int id = keyEvent.getID(); int keyCode = keyEvent.getKeyCode(); if (id == KeyEvent.KEY_PRESSED && keyCode == KeyEvent.VK_ESCAPE) { synchronized (directoryDialog.getTreeLock()) { Component comp = (Component) keyEvent.getSource(); while (comp != null) { // Fix for 6240084 Disposing a file dialog when the // drop-down is active does not dispose the dropdown menu, // on Xtoolkit // See also 6259493 if (comp == pathChoice) { XChoicePeer choicePeer = (XChoicePeer) pathChoice .getPeer(); if (choicePeer.isUnfurled()) { return false; } } if (comp.getPeer() == this) { handleCancel(); return true; } comp = comp.getParent(); } } } return false; } @Override public void dispose() { if (directoryDialog != null) { directoryDialog.removeAll(); } if (target != null) { ((Dialog) target).removeAll(); } super.dispose(); } // 03/02/2005 b5097243 Pressing 'ESC' on a file dlg does not dispose the dlg // on Xtoolkit @Override public void setVisible(boolean b) { super.setVisible(b); if (b == true) { // See 6240074 for more information XChoicePeer choicePeer = (XChoicePeer) pathChoice.getPeer(); choicePeer.setDrawSelectedItem(false); choicePeer.setAlignUnder(pathField); choicePeer.addXChoicePeerListener(this); KeyboardFocusManager.getCurrentKeyboardFocusManager() .addKeyEventDispatcher(this); } else { // See 6240074 for more information XChoicePeer choicePeer = (XChoicePeer) pathChoice.getPeer(); choicePeer.removeXChoicePeerListener(); KeyboardFocusManager.getCurrentKeyboardFocusManager() .removeKeyEventDispatcher(this); } } /* * Adding items to the path choice based on the text string See 6240074 for * more information */ public void addItemsToPathChoice(String text) { String dirList[] = getDirList(text); for (int i = 0; i < dirList.length; i++) { pathChoice.addItem(dirList[i]); } } /* * Refresh the unfurled choice at the time of the opening choice according * to the text of the path field See 6240074 for more information */ public void unfurledChoiceOpening(ListHelper choiceHelper) { // When the unfurled choice is opening the first time, we need only to // add elements, otherwise we've got exception if (choiceHelper.getItemCount() == 0) { addItemsToPathChoice(pathField.getText()); return; } // If the set of the directories the exactly same as the used to be then // dummy if (pathChoice.getItem(0).equals(pathField.getText())) { return; } pathChoice.removeAll(); addItemsToPathChoice(pathField.getText()); } /* * Refresh the file dialog at the time of the closing choice according to * the selected item of the choice See 6240074 for more information */ public void unfurledChoiceClosing() { // This is the exactly same code as invoking later at the time of the // itemStateChanged // Here is we restore Windows behaviour: change current directory if // user press 'ESC' String selectedDir = pathChoice.getSelectedItem(); directoryDialog.setDirectory(selectedDir); } }