/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.repository.gui; import java.awt.Component; import java.awt.Dialog; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; import com.rapidminer.gui.RapidMinerGUI; import com.rapidminer.gui.tools.ExtendedJScrollPane; import com.rapidminer.gui.tools.ResourceActionAdapter; import com.rapidminer.gui.tools.ResourceLabel; import com.rapidminer.gui.tools.SwingTools; import com.rapidminer.gui.tools.dialogs.ButtonDialog; import com.rapidminer.repository.DataEntry; import com.rapidminer.repository.Entry; import com.rapidminer.repository.Folder; import com.rapidminer.repository.MalformedRepositoryLocationException; import com.rapidminer.repository.RepositoryLocation; import com.rapidminer.tools.LogService; import com.rapidminer.tools.ParameterService; /** * A dialog that shows the repository tree. The static method {@link #selectLocation()} shows a dialog and returns the * location selected by the user. * * @author Simon Fischer, Tobias Malbrecht * */ public class RepositoryLocationChooser extends JPanel { private static final long serialVersionUID = 1L; private final RepositoryTree tree; private final JTextField locationField = new JTextField(30); private final RepositoryLocation resolveRelativeTo; private JCheckBox resolveBox; private final List<ChangeListener> listeners = new LinkedList<ChangeListener>(); private final JLabel resultLabel = new JLabel(); /** The entry the user last clicked on. (Not the selected entry, this is also influenced by the text field.) */ private Entry currentEntry; private boolean folderSelected; private static class RepositoryLocationChooserDialog extends ButtonDialog { private static final long serialVersionUID = -726540444296013310L; private RepositoryLocationChooser chooser = null; private String userSelection = null; public RepositoryLocationChooserDialog(RepositoryLocation resolveRelativeTo, String initialValue, final boolean allowEntries, final boolean allowFolders) { super("repository_chooser", true); final JButton okButton = makeOkButton(); chooser = new RepositoryLocationChooser(this, resolveRelativeTo, initialValue, allowEntries, allowFolders); chooser.tree.addRepositorySelectionListener(new RepositorySelectionListener() { @Override public void repositoryLocationSelected(RepositorySelectionEvent e) { // called on double click Entry entry = e.getEntry(); if (allowEntries && entry instanceof DataEntry) { userSelection = entry.getLocation().toString(); dispose(); } } }); chooser.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { okButton.setEnabled(chooser.hasSelection(allowFolders) && (allowFolders || !chooser.folderSelected)); } }); okButton.setEnabled(chooser.hasSelection(allowFolders) && (allowFolders || !chooser.folderSelected)); layoutDefault(chooser, NORMAL, okButton, makeCancelButton()); } @Override protected void ok() { try { chooser.getRepositoryLocation(); super.ok(); } catch (MalformedRepositoryLocationException e) { SwingTools.showSimpleErrorMessage("malformed_repository_location", e, e.getMessage()); } } } // public RepositoryLocationChooser(RepositoryLocation resolveRelativeTo, String initialValue) { // this(null, resolveRelativeTo, initialValue); // } public RepositoryLocationChooser(Dialog owner, RepositoryLocation resolveRelativeTo, String initialValue) { this(owner, resolveRelativeTo, initialValue, true, false); } public RepositoryLocationChooser(Dialog owner, RepositoryLocation resolveRelativeTo, String initialValue, final boolean allowEntries, final boolean allowFolders) { if (initialValue != null) { try { RepositoryLocation repositoryLocation = new RepositoryLocation(resolveRelativeTo, initialValue); locationField.setText(repositoryLocation.getName()); resultLabel.setText(repositoryLocation.toString()); } catch (Exception e) { } } this.resolveRelativeTo = resolveRelativeTo; tree = new RepositoryTree(owner, !allowEntries); if (initialValue != null) { if (tree.expandIfExists(resolveRelativeTo, initialValue)) { locationField.setText(""); } } tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { if (e.getPath() != null) { currentEntry = (Entry) e.getPath().getLastPathComponent(); if (currentEntry instanceof Folder) { // && allowFolders)) { locationField.setText(""); } else if ((!(currentEntry instanceof Folder)) && allowEntries) { // if (true) { // //!(currentEntry instanceof Folder)) { locationField.setText(currentEntry.getLocation().getName()); } updateResult(); } } }); locationField.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { updateResult(); } @Override public void keyTyped(KeyEvent e) { TreePath selectionPath = tree.getSelectionPath(); if (selectionPath != null) { Entry selectedEntry = (Entry) selectionPath.getLastPathComponent(); if (!(selectedEntry instanceof Folder)) { tree.setSelectionPath(selectionPath.getParentPath()); } } } }); setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(0, 0, 0, 0); c.fill = GridBagConstraints.BOTH; c.weightx = 1; c.weighty = 1; c.anchor = GridBagConstraints.FIRST_LINE_START; c.gridwidth = GridBagConstraints.REMAINDER; JScrollPane treePane = new ExtendedJScrollPane(tree); treePane.setBorder(ButtonDialog.createBorder()); add(treePane, c); c.insets = new Insets(ButtonDialog.GAP, 0, 0, ButtonDialog.GAP); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 0; c.weighty = 0; c.gridwidth = GridBagConstraints.RELATIVE; c.weightx = 0; JLabel label = new ResourceLabel("repository_chooser.entry_name"); label.setLabelFor(locationField); add(label, c); c.weightx = 1; c.insets = new Insets(ButtonDialog.GAP, 0, 0, 0); c.weightx = 1; c.gridwidth = GridBagConstraints.REMAINDER; add(locationField, c); c.gridwidth = GridBagConstraints.RELATIVE; c.weightx = 0; c.insets = new Insets(ButtonDialog.GAP, 0, 0, ButtonDialog.GAP); add(new ResourceLabel("repository_chooser.location"), c); c.weightx = 1; c.insets = new Insets(ButtonDialog.GAP, 0, 0, 0); c.gridwidth = GridBagConstraints.REMAINDER; add(resultLabel, c); if (resolveRelativeTo != null) { resolveBox = new JCheckBox(new ResourceActionAdapter("repository_chooser.resolve", resolveRelativeTo.getAbsoluteLocation())); resolveBox.setSelected(ParameterService.getParameterValue(RapidMinerGUI.PROPERTY_RESOLVE_RELATIVE_REPOSITORY_LOCATIONS).equals("true")); add(resolveBox, c); resolveBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateResult(); } }); } } public String getRepositoryLocation() throws MalformedRepositoryLocationException { if (tree.getSelectionPath() != null) { Entry selectedEntry = (Entry) tree.getSelectionPath().getLastPathComponent(); RepositoryLocation selectedLocation = selectedEntry.getLocation(); if (selectedEntry instanceof Folder) { selectedLocation = new RepositoryLocation(selectedLocation, locationField.getText()); } if (RepositoryLocationChooser.this.resolveRelativeTo != null && resolveBox.isSelected()) { return selectedLocation.makeRelative(RepositoryLocationChooser.this.resolveRelativeTo); } else { return selectedLocation.getAbsoluteLocation(); } } else { return locationField.getText(); } } /** Same as {@link #hasSelection(boolean)} with parameter false. */ public boolean hasSelection() { return hasSelection(false); } /** Returns true iff the user entered a valid, non-empty repository location. */ public boolean hasSelection(boolean allowFolders) { if (!allowFolders && locationField.getText().isEmpty()) { return false; } else { try { getRepositoryLocation(); return true; } catch (MalformedRepositoryLocationException e) { LogService.getRoot().warning("Malformed repository location: " + e); return false; } } } public boolean resolveRelative() { return resolveBox.isSelected(); } public void addChangeListener(ChangeListener l) { listeners.add(l); } public void removeChangeListener(ChangeListener l) { listeners.remove(l); } /** * This will open a window to select a repository entry that is an entry or returns * null if the user aborts the operation. */ public static String selectEntry(RepositoryLocation resolveRelativeTo, Component c) { return selectLocation(resolveRelativeTo, null, c, true, false); } /** * This will open a window to select a repository entry that is a folder or null if * the user chooses to abort. */ public static String selectFolder(RepositoryLocation resolveRelativeTo, Component c) { return selectLocation(resolveRelativeTo, null, c, false, true); } public static String selectLocation(RepositoryLocation resolveRelativeTo, Component c) { return selectLocation(resolveRelativeTo, null, c, true, true); } public static String selectLocation(RepositoryLocation resolveRelativeTo, String initialValue, Component c, final boolean selectEntries, final boolean selectFolder) { final RepositoryLocationChooserDialog dialog = new RepositoryLocationChooserDialog(resolveRelativeTo, initialValue, selectEntries, selectFolder); dialog.setVisible(true); // if user has used double click to submit if (dialog.userSelection != null) { return dialog.userSelection; } if (dialog.wasConfirmed()) { if (resolveRelativeTo != null) { ParameterService.setParameterValue(RapidMinerGUI.PROPERTY_RESOLVE_RELATIVE_REPOSITORY_LOCATIONS, dialog.chooser.resolveRelative() ? "true" : "false"); ParameterService.saveParameters(); } String text; try { text = dialog.chooser.getRepositoryLocation(); } catch (MalformedRepositoryLocationException e) { // this should not happen since the dialog would not have disposed without an error message. throw new RuntimeException(e); } if (text.length() > 0) { return text; } else { return null; } } else { return null; } } private void updateResult() { try { String repositoryLocation = getRepositoryLocation(); resultLabel.setText(repositoryLocation); } catch (MalformedRepositoryLocationException e) { LogService.getRoot().log(Level.WARNING, "Malformed location: " + e, e); } if ((currentEntry instanceof Folder) && locationField.getText().isEmpty()) { this.folderSelected = true; } else { this.folderSelected = false; } for (ChangeListener l : listeners) { l.stateChanged(new ChangeEvent(this)); } } }