Java tutorial
/* * org.openmicroscopy.shoola.agents.fsimporter.chooser.LocationDialog * *------------------------------------------------------------------------------ * Copyright (C) 2006-2013 University of Dundee & Open Microscopy Environment. * All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.agents.fsimporter.chooser; import info.clearthought.layout.TableLayout; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.DefaultComboBoxModel; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.border.Border; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.apache.commons.collections.CollectionUtils; import org.openmicroscopy.shoola.agents.fsimporter.IconManager; import org.openmicroscopy.shoola.agents.fsimporter.ImporterAgent; import org.openmicroscopy.shoola.agents.fsimporter.util.ObjectToCreate; import org.openmicroscopy.shoola.agents.fsimporter.view.ImportLocationDetails; import org.openmicroscopy.shoola.agents.fsimporter.view.Importer; import org.openmicroscopy.shoola.agents.util.ComboBoxToolTipRenderer; import org.openmicroscopy.shoola.agents.util.EditorUtil; import org.openmicroscopy.shoola.agents.util.ViewerSorter; import org.openmicroscopy.shoola.agents.util.browser.DataNode; import org.openmicroscopy.shoola.agents.util.browser.TreeImageDisplay; import org.openmicroscopy.shoola.agents.util.ui.EditorDialog; import org.openmicroscopy.shoola.agents.util.ui.JComboBoxImageObject; import org.openmicroscopy.shoola.agents.util.ui.JComboBoxImageRenderer; import org.openmicroscopy.shoola.env.LookupNames; import org.openmicroscopy.shoola.util.ui.Selectable; import org.openmicroscopy.shoola.util.ui.SelectableComboBoxModel; import org.openmicroscopy.shoola.util.ui.UIUtilities; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import pojos.DataObject; import pojos.DatasetData; import pojos.ExperimenterData; import pojos.GroupData; import pojos.PermissionData; import pojos.ProjectData; import pojos.ScreenData; /** * Provides the user with the options to select the location to import data. * * @author Jean-Marie Burel <a * href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author Donald MacDonald <a * href="mailto:donald@lifesci.dundee.ac.uk" * >donald@lifesci.dundee.ac.uk</a> * @author Scott Littlewood <a * href="mailto:sylittlewood@dundee.ac.uk" * >sylittlewood@dundee.ac.uk</a> * @version 3.0 <small> (<b>Internal version:</b> $Revision: $Date: $) </small> * @since 3.0-Beta4 */ class LocationDialog extends JDialog implements ActionListener, PropertyChangeListener, ChangeListener, ItemListener { /** Default GAP value for UI components */ private static final int UI_GAP = 5; /** Template for a table layout with a GAP on all 4 sides */ private static final double[][] TABLE_GAP = new double[][] { { UI_GAP, TableLayout.FILL, UI_GAP }, { UI_GAP, TableLayout.FILL, UI_GAP } }; /** Helper setting for TableLayout.PREFERRED*/ private static final double[] TABLE_PREF = { TableLayout.PREFERRED }; /** Table template for 2 settings of Preferred width / height */ private static final double[] TABLE_PREF_PREF = { TableLayout.PREFERRED, TableLayout.PREFERRED }; /** Table template for 3 settings of Preferred width / height */ private static final double[] TABLE_PREF_PREF_PREF = { TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED }; /** Table template for expandable middle column / row */ private static final double[] TABLE_PREF_FILL_PREF = { TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED }; // other constants /** Minimum width of the dialog in pixels */ private static final int MIN_WIDTH = 640; /** The preferred size of the selection box.*/ private static final Dimension SELECTION_BOX_SIZE = new Dimension(200, 130); // String constants /** The title of the dialog. */ private static String TEXT_TITLE = "Import Location - Select where to import your data."; /** Text for import as a user */ private static final String TEXT_IMPORT_AS = "Import For"; /** Text for projects */ private static final String TEXT_PROJECTS = "Projects"; /** Text for screens */ private static final String TEXT_SCREENS = "Screens"; /** Text for Screens tab */ private static final String TOOLTIP_SCREENS_TAB = "Import settings for Screens"; /** Text for Projects tab */ private static final String TOOLTIP_PROJECTS_TAB = "Import settings for Projects"; /** Text for a project. */ private static final String TEXT_PROJECT = "Project"; /** Text for a dataset. */ private static final String TEXT_DATASET = "Dataset"; /** Text for a screen. */ private static final String TEXT_SCREEN = "Screen"; /** Text for a group. */ private static final String TEXT_GROUP = "Group"; /** Tooltip text for New Screen button */ private static final String TOOLTIP_NEW_SCREEN = "Create a new Screen."; /** Tooltip text for New Dataset button */ private static final String TOOLTIP_NEW_DATASET = "Create a new Dataset."; /** Tooltip text for New Project button */ private static final String TOOLTIP_NEW_PROJECT = "Create a new Project."; /** Tooltip for Reload button */ private static final String TEXT_REFRESH = "Refresh"; /** Tooltip for Reload button */ private static final String TOOLTIP_REFRESH = "Reload the Groups, Projects, Datasets and/or Screens."; /** Text for New buttons */ private static final String TEXT_NEW = "New..."; /** Text for Close button */ private static final String TEXT_CLOSE = "Close"; /** Tooltip text for Close button */ private static final String TOOLTIP_CLOSE_DIALOGUE = "Close the dialog and do not add the files to the queue."; /** Text for Add button */ private static final String TEXT_QUEUE_ITEMS = "Add to the Queue"; /** Tooltip text for Add button */ private static final String TOOLTIP_QUEUE_ITEMS = "Add the files to the queue."; // Icon constants /** Reference to the <code>Group Private</code> icon. */ private static final Icon GROUP_PRIVATE_ICON; /** Reference to the <code>Group RWR---</code> icon. */ private static final Icon GROUP_READ_ONLY_ICON; /** Reference to the <code>Group RWRA--</code> icon. */ private static final Icon GROUP_READ_LINK_ICON; /** Reference to the <code>Group RWRW--</code> icon. */ private static final Icon GROUP_READ_WRITE_ICON; /** Reference to the <code>Group</code> icon. */ private static final Icon GROUP_PUBLIC_READ_ICON; /** Reference to the <code>Group</code> icon. */ private static final Icon GROUP_PUBLIC_READ_WRITE_ICON; static { IconManager icons = IconManager.getInstance(); GROUP_PRIVATE_ICON = icons.getIcon(IconManager.PRIVATE_GROUP); GROUP_READ_ONLY_ICON = icons.getIcon(IconManager.READ_GROUP); GROUP_READ_LINK_ICON = icons.getIcon(IconManager.READ_LINK_GROUP); GROUP_READ_WRITE_ICON = icons.getIcon(IconManager.READ_WRITE_GROUP); GROUP_PUBLIC_READ_ICON = icons.getIcon(IconManager.PUBLIC_GROUP); GROUP_PUBLIC_READ_WRITE_ICON = icons.getIcon(IconManager.PUBLIC_GROUP); } // Command constants /** Action id indicating to create a new project. */ private static final int CMD_CREATE_PROJECT = 1; /** Action id indicating to create a new dataset. */ private static final int CMD_CREATE_DATASET = 2; /** Action id indicating to create a new screen. */ private static final int CMD_CREATE_SCREEN = 3; /** User has chosen to force a refresh of the containers */ private static final int CMD_REFRESH_DISPLAY = 4; /** User has selected to add the files. */ final static int CMD_ADD = 5; /** User has selected to cancel. */ final static int CMD_CLOSE = 6; /** Action button command Id chosen by the user. */ private int userSelectedActionCommandId; // UI Components /** The Project panel tab. */ private JPanel projectPanel; /** The Screen panel tab. */ private JPanel screenPanel; /** Component indicating to add to the queue. */ private JButton addButton; /** Component indicating to close the dialog. */ private JButton closeButton; /** Component used to select the import group. */ private JComboBox groupsBox; /** Component used to select the import user. */ private JComboBox usersBox; /** Component used to select the default project. */ private JComboBox projectsBox; /** Component used to select the default dataset. */ private JComboBox datasetsBox; /** Component used to select the default screen. */ private JComboBox screensBox; /** Button to create a new project. */ private JButton newProjectButton; /** Button to create a new dataset. */ private JButton newDatasetButton; /** Button to create a new screen. */ private JButton newScreenButton; /** Button used to refresh the groups/projects/datasets & screens */ private JButton refreshButton; /** Tab pane used to hose the Project/Screen selection UI component. */ private JTabbedPane tabbedPane; // Operational variables & constants /** Constant value for no data type */ private static final int NO_DATA_TYPE = -1; /** Sorts the objects from the display. */ private ViewerSorter sorter; /** A reference to the selected target for import data. */ private TreeImageDisplay container; /** The id of the import data type (Screen/Project) */ private int dataType = NO_DATA_TYPE; /** Internal list of available groups. */ private Collection<GroupData> groups; /** The current possible import location nodes. */ private Collection<TreeImageDisplay> objects; /** The list of currently available Projects */ private List<DataNode> projects = new ArrayList<DataNode>(); /** The list of currently available Screens */ private List<DataNode> screens = new ArrayList<DataNode>(); /** The projects -> dataset map of currently available Datasets */ private Map<DataNode, List<DataNode>> datasets = new Hashtable<DataNode, List<DataNode>>(); /** The currently selected Project */ private DataNode currentProject; /** The currently selected Dataset */ private DataNode currentDataset; /** The currently selected Screen */ private DataNode currentScreen; /** Reference to the model.*/ private Importer model; /** * Creates a new instance. * * @param parent The parent of the dialog. * @param selectedContainer The container selected by the user. * @param objects The screens / projects to be shown. * @param model Reference to the model. * @param currentGroupId The id of the current user group. * @param userId The user to select when importing as. */ LocationDialog(JFrame parent, TreeImageDisplay selectedContainer, int importDataType, Collection<TreeImageDisplay> objects, Importer model, long currentGroupId) { super(parent); this.container = selectedContainer; this.dataType = importDataType; this.objects = objects; this.groups = model.getAvailableGroups(); this.model = model; setModal(true); setTitle(TEXT_TITLE); initUIComponents(); layoutUI(); populateUIWithDisplayData(findWithId(groups, currentGroupId), model.getImportFor()); } /** * Populates the various components. * * @param selectedGroup The selected group. * @param userID The id of the selected user. */ private void populateUIWithDisplayData(GroupData selectedGroup, long userID) { convertToDisplayData(objects); populateGroupBox(sort(groups), selectedGroup, userID); populateLocationComboBoxes(); displayViewFor(dataType); } /** * Returns the loaded experimenter corresponding to the specified user. * if the user is not loaded. Returns <code>null</code> if no user * can be found. * * @param owner The experimenter to handle. * @return see above. */ private ExperimenterData getExperimenter(ExperimenterData owner) { if (owner == null) return null; if (owner.isLoaded()) return owner; List l = (List) ImporterAgent.getRegistry().lookup(LookupNames.USERS_DETAILS); if (l == null) return null; Iterator i = l.iterator(); ExperimenterData exp; long id = owner.getId(); while (i.hasNext()) { exp = (ExperimenterData) i.next(); if (exp.getId() == id) return exp; } return null; } /** * Swaps the data view that is currently active. * @param dataType The id of the data type (Screen/Project) */ private void displayViewFor(int dataType) { switch (dataType) { case Importer.PROJECT_TYPE: this.tabbedPane.setSelectedComponent(projectPanel); break; case Importer.SCREEN_TYPE: this.tabbedPane.setSelectedComponent(screenPanel); } } /** * Scans the DataObjects provided and returns the Object with matching id. * <null> if not found * @param dataObjects The list of DataObjects. * @param id The id of the object to find. * @return The DataObject in the list with matching id, <null> if not found. */ private <T extends DataObject> T findWithId(Collection<T> dataObjects, long id) { for (T dataObject : dataObjects) { if (dataObject.getId() == id) return dataObject; } return null; } /** * Scans the DataNodes provided and returns the Object with matching id. * <null> if not found * @param dataObjects The list of DataObjects. * @param id The id of the object to find. * @return The DataObject in the list with matching id, <null> if not found. */ private DataNode findDataNodeById(Collection<DataNode> nodes, long id) { if (CollectionUtils.isEmpty(nodes)) return null; for (DataNode node : nodes) { if (getIdOf(node) == id) return node; } return null; } /** * Initializes the UI components of the dialog. */ private void initUIComponents() { sorter = new ViewerSorter(); // main components groupsBox = new JComboBox(); usersBox = new JComboBox(); //Currently only for the administrator otherwise to do show the option usersBox.setVisible(ImporterAgent.isAdministrator()); refreshButton = new JButton(TEXT_REFRESH); refreshButton.setBackground(UIUtilities.BACKGROUND); refreshButton.setToolTipText(TOOLTIP_REFRESH); refreshButton.setActionCommand("" + CMD_REFRESH_DISPLAY); refreshButton.addActionListener(this); projectsBox = new JComboBox(); projectsBox.addItemListener(this); datasetsBox = new JComboBox(); datasetsBox.addItemListener(this); screensBox = new JComboBox(); screensBox.addItemListener(this); // main location panel buttons newProjectButton = new JButton(TEXT_NEW); newProjectButton.setToolTipText(TOOLTIP_NEW_PROJECT); newProjectButton.setActionCommand("" + CMD_CREATE_PROJECT); newProjectButton.addActionListener(this); newDatasetButton = new JButton(TEXT_NEW); newDatasetButton.setToolTipText(TOOLTIP_NEW_DATASET); newDatasetButton.setActionCommand("" + CMD_CREATE_DATASET); newDatasetButton.addActionListener(this); newScreenButton = new JButton(TEXT_NEW); newScreenButton.setToolTipText(TOOLTIP_NEW_SCREEN); newScreenButton.setActionCommand("" + CMD_CREATE_SCREEN); newScreenButton.addActionListener(this); // main action buttons addButton = new JButton(TEXT_QUEUE_ITEMS); addButton.setToolTipText(TOOLTIP_QUEUE_ITEMS); addButton.addActionListener(this); addButton.setActionCommand("" + CMD_ADD); closeButton = new JButton(TEXT_CLOSE); closeButton.setToolTipText(TOOLTIP_CLOSE_DIALOGUE); closeButton.addActionListener(this); closeButton.setActionCommand("" + CMD_CLOSE); getRootPane().setDefaultButton(addButton); } /** * Builds a JPanel holding the main action buttons * @return The JPanel holding the lower main action buttons. */ private JPanel buildLowerButtonPanel() { TableLayout buttonLayout = createTableLayout(TABLE_PREF_FILL_PREF, TABLE_PREF); JPanel buttonPanel = new JPanel(buttonLayout); buttonPanel.add(closeButton, "0, 0, l, c"); buttonPanel.add(refreshButton, "1, 0, l, c"); buttonPanel.add(addButton, "2, 0, r, c"); JPanel buttonWrapper = wrapInPaddedPanel(buttonPanel, UI_GAP, 0, 0, 0); Border border = BorderFactory.createMatteBorder(1, 0, 0, 0, Color.BLACK); buttonWrapper.setBorder(border); return buttonWrapper; } /** * Builds a TabbedPane holding the Screen / Project import sections * @return The tab panel for Screen / Project selection */ private JPanel buildDataTypeTabbedPane() { IconManager icons = IconManager.getInstance(); Icon projectIcon = icons.getIcon(IconManager.PROJECT); projectPanel = buildProjectSelectionPanel(); Icon screenIcon = icons.getIcon(IconManager.SCREEN); screenPanel = buildScreenSelectionPanel(); tabbedPane = new JTabbedPane(); tabbedPane.addTab(TEXT_PROJECTS, projectIcon, projectPanel, TOOLTIP_PROJECTS_TAB); tabbedPane.addTab(TEXT_SCREENS, screenIcon, screenPanel, TOOLTIP_SCREENS_TAB); tabbedPane.addChangeListener(this); return wrapInGapPanel(tabbedPane); } /** * Builds a JPanel holding the group selection section. * @return JPanel holding the group selection UI elements */ private JPanel buildGroupSelectionPanel() { TableLayout groupLayout = createTableLayout(TABLE_PREF_PREF_PREF, TABLE_PREF_PREF); final JPanel groupPanel = new JPanel(groupLayout); String c1 = "0, 0, r, c"; String c2 = "1, 0"; if (groups.size() > 1) { groupPanel.add(UIUtilities.setTextFont(TEXT_GROUP), "0, 0, r, c"); groupPanel.add(groupsBox, "1, 0"); c1 = "0, 1, r, c"; c2 = "1, 1"; } if (usersBox.isVisible()) { groupPanel.add(UIUtilities.setTextFont(TEXT_IMPORT_AS), c1); groupPanel.add(usersBox, c2); } return groupPanel; } /** * Builds a JPanel holding the project selection section. * * @return JPanel holding the project selection UI elements */ private JPanel buildProjectSelectionPanel() { TableLayout projectLayout = createTableLayout(TABLE_PREF_FILL_PREF, TABLE_PREF_PREF_PREF); JPanel projectPanel = new JPanel(projectLayout); projectPanel.add(UIUtilities.setTextFont(TEXT_PROJECT), "0, 0, r, c"); projectPanel.add(projectsBox, "1, 0"); projectPanel.add(newProjectButton, "2, 0, c, c"); projectPanel.add(UIUtilities.setTextFont(TEXT_DATASET), "0, 1, r, c"); projectPanel.add(datasetsBox, "1, 1"); projectPanel.add(newDatasetButton, "2, 1, c, c"); return wrapInGapPanel(projectPanel); } /** * Builds a JPanel holding the screen selection section. * * @return JPanel holding the screen selection UI elements */ private JPanel buildScreenSelectionPanel() { TableLayout screenLayout = createTableLayout(TABLE_PREF_FILL_PREF, TABLE_PREF); JPanel screenPanel = new JPanel(screenLayout); screenPanel.add(UIUtilities.setTextFont(TEXT_SCREEN), "0, 0, r, c"); screenPanel.add(screensBox, "1, 0"); screenPanel.add(newScreenButton, "2, 0, c, c"); return wrapInGapPanel(screenPanel); } /** * Builds the toolbar when the importer is the entry point. * * @param availableGroups The available group. * @param selectedGroup The selected group. * @param userID The selected user. * @return See above. */ private void populateGroupBox(Collection<GroupData> availableGroups, GroupData selectedGroup, long userID) { groupsBox.removeItemListener(this); groupsBox.removeAllItems(); JComboBoxImageObject selectedGroupItem = null; JComboBoxImageObject item; List<String> tooltips = new ArrayList<String>(availableGroups.size()); List<String> lines; for (GroupData group : availableGroups) { item = new JComboBoxImageObject(group, getGroupIcon(group)); lines = new ArrayList<String>(); lines.addAll(UIUtilities.wrapStyleWord(group.getName())); tooltips.add(UIUtilities.formatToolTipText(lines)); groupsBox.addItem(item); if (selectedGroup != null && selectedGroup.getId() == group.getId()) selectedGroupItem = item; } if (selectedGroupItem != null) { groupsBox.setSelectedItem(selectedGroupItem); displayUsers(usersBox, selectedGroup, this, userID); } JComboBoxImageRenderer renderer = new JComboBoxImageRenderer(); renderer.setTooltips(tooltips); renderer.setPreferredSize(SELECTION_BOX_SIZE); groupsBox.setRenderer(renderer); groupsBox.addItemListener(this); } /** * Determines if the logged in user is allowed to import data for the user * in to the selected group. Returns true if the logged in user is the user, * is a system administrator or is an owner of the group. * * @param user The user to import data for. * @param selectedGroup The group to import data in to. * @return See above. */ private boolean canImportForUserInGroup(ExperimenterData user, GroupData selectedGroup) { ExperimenterData loggedInUser = ImporterAgent.getUserDetails(); if (user.getId() == loggedInUser.getId()) return true; if (selectedGroup.getPermissions().getPermissionsLevel() == GroupData.PERMISSIONS_PRIVATE) return false; boolean isGroupOwner = false; Set<ExperimenterData> leaders = (Set<ExperimenterData>) selectedGroup.getLeaders(); for (ExperimenterData leader : leaders) { if (leader.getId() == loggedInUser.getId()) isGroupOwner = true; } return ImporterAgent.isAdministrator() || isGroupOwner; } /** * Returns the icon associated to the group. * @param group The group to handle. * @return See above. */ private Icon getGroupIcon(GroupData group) { switch (group.getPermissions().getPermissionsLevel()) { case GroupData.PERMISSIONS_PRIVATE: return GROUP_PRIVATE_ICON; case GroupData.PERMISSIONS_GROUP_READ: return GROUP_READ_ONLY_ICON; case GroupData.PERMISSIONS_GROUP_READ_LINK: return GROUP_READ_LINK_ICON; case GroupData.PERMISSIONS_GROUP_READ_WRITE: return GROUP_READ_WRITE_ICON; case GroupData.PERMISSIONS_PUBLIC_READ: return GROUP_PUBLIC_READ_ICON; case GroupData.PERMISSIONS_PUBLIC_READ_WRITE: return GROUP_PUBLIC_READ_WRITE_ICON; } return null; } /** * Builds and lays out the UI. */ private void layoutUI() { BorderLayout layout = new BorderLayout(); layout.setHgap(UI_GAP); layout.setVgap(UI_GAP); JPanel mainPanel = new JPanel(layout); mainPanel.add(buildGroupSelectionPanel(), BorderLayout.NORTH); mainPanel.add(buildDataTypeTabbedPane(), BorderLayout.CENTER); mainPanel.add(buildLowerButtonPanel(), BorderLayout.SOUTH); TableLayout containerLayout = createTableLayout(TABLE_GAP); Container contentPane = this.getContentPane(); contentPane.setLayout(containerLayout); contentPane.add(mainPanel, "1, 1"); // resize the window to minimum size setMinimumSize(); } /** * Resizes the window and sets the minimum size to the * size required by all components. */ private void setMinimumSize() { this.pack(); int minHeight = this.getHeight(); Dimension minSize = new Dimension(MIN_WIDTH, minHeight); this.setMinimumSize(minSize); this.setPreferredSize(minSize); this.setSize(minSize); } /** * Creates a TableLayout based on the design passed in * with a HGap and VGap set to UI_GAP. * * @param design the column / row template * @return A table layout with the design & spacing applied */ private TableLayout createTableLayout(double[][] design) { TableLayout tableLayout = new TableLayout(design); tableLayout.setHGap(UI_GAP); tableLayout.setVGap(UI_GAP); return tableLayout; } /** * Creates a TableLayout based on the design passed in * with a HGap and VGap set to UI_GAP * @param columns the column template to use for the table design * @param rows the row template to use for the table design * @return A table layout with the design & spacing applied */ private TableLayout createTableLayout(double[] columns, double[] rows) { double[][] design = new double[][] { columns, rows }; return createTableLayout(design); } /** * Wraps the container in a JPanel with a bordered TableLayout * with a border of UI_GAP * @param container the container to wrap * @return The JPanel wrapping the container */ private <T extends Container> JPanel wrapInGapPanel(T container) { TableLayout paddedLayout = createTableLayout(TABLE_GAP); JPanel gapPanel = new JPanel(paddedLayout); gapPanel.add(container, "1, 1"); return gapPanel; } /** * Wraps the container in a JPanel with a bordered TableLayout * with the border width specified * @param container * @param top The amount of padding on the top of the container * @param left The amount of padding on the left of the container * @param bottom The amount of padding on the bottom of the container * @param right The amount of padding on the right of the container * @return The JPanel wrapping the container */ private <T extends Container> JPanel wrapInPaddedPanel(T container, int top, int left, int bottom, int right) { double[][] spacedLayout = new double[][] { { left, TableLayout.FILL, right }, { top, TableLayout.FILL, bottom } }; TableLayout paddedLayout = createTableLayout(spacedLayout); JPanel gapPanel = new JPanel(paddedLayout); gapPanel.add(container, "1, 1"); return gapPanel; } /** * Closes the dialog. */ private void close() { setVisible(false); dispose(); } /** * Shows the message box and returns the option selected by the user. * @return The option selected by the user. */ int centerLocation() { UIUtilities.centerAndShow(this); return userSelectedActionCommandId; } /** * Shows the message box and returns the option selected by the user. * @param location The location of the top-left corner of the dialog. * @return The option selected by the user. */ int showLocation(Point location) { setLocation(location); setVisible(true); return userSelectedActionCommandId; } /** * Sets the option. * @see ActionListener#actionPerformed(ActionEvent) */ public void actionPerformed(ActionEvent ae) { String actionCommand = ae.getActionCommand(); try { int commandId = Integer.parseInt(actionCommand); DataObject newDataObject = null; switch (commandId) { case CMD_CREATE_PROJECT: newDataObject = new ProjectData(); break; case CMD_CREATE_DATASET: newDataObject = new DatasetData(); break; case CMD_CREATE_SCREEN: newDataObject = new ScreenData(); break; case CMD_ADD: case CMD_CLOSE: userSelectedActionCommandId = commandId; close(); break; case CMD_REFRESH_DISPLAY: storeCurrentSelections(); firePropertyChange(ImportDialog.REFRESH_LOCATION_PROPERTY, null, new ImportLocationDetails(dataType)); } if (newDataObject != null) { EditorDialog editor = new EditorDialog((JFrame) getOwner(), newDataObject, false); editor.addPropertyChangeListener(this); editor.setModal(true); UIUtilities.centerAndShow(editor); } } catch (NumberFormatException nfe) { } } /** * Switches to display the projects/datasets/screens from the selected * group. */ private void switchToSelectedGroup() { GroupData selectedNewGroup = getSelectedGroup(); setInputsEnabled(false); firePropertyChange(ImportDialog.PROPERTY_GROUP_CHANGED, null, selectedNewGroup); } /** * Switches to display the projects/datasets/screens from the selected user. */ private void switchToSelectedUser() { populateLocationComboBoxes(); //setInputsEnabled(false); //firePropertyChange(ImportDialog.REFRESH_LOCATION_PROPERTY, null, // new ImportLocationDetails(dataType, getSelectedUser().getId())); } /** * Returns the import settings chosen but the user. * * @return The import settings selected by the user. */ protected ImportLocationSettings getImportSettings() { GroupData group = getSelectedGroup(); ExperimenterData user = getSelectedUser(); switch (dataType) { case Importer.PROJECT_TYPE: DataNode project = getSelectedItem(projectsBox); DataNode dataset = getSelectedItem(datasetsBox); return new ProjectImportLocationSettings(group, user, project, dataset); case Importer.SCREEN_TYPE: DataNode screen = getSelectedItem(screensBox); return new ScreenImportLocationSettings(group, user, screen); } return new NullImportSettings(group, user); } /** * Returns the selected user in the users combobox * @return see above. */ private ExperimenterData getSelectedUser() { return getUser(usersBox.getSelectedIndex()); } /** * Returns the user corresponding to the specified index. * * @param index The index of the user. * @return see above. */ private ExperimenterData getUser(int index) { Selectable<ExperimenterDisplay> selectedItem = (Selectable<ExperimenterDisplay>) usersBox.getItemAt(index); if (selectedItem != null) return selectedItem.getObject().getData(); return null; } /** * Populates the JComboBox with the items provided adding hover tooltips. * @param comboBox The JComboBox to populate * @param listItems The items to populate the box with */ private void displayItemsWithTooltips(JComboBox comboBox, List<DataNode> listItems) { displayItems(comboBox, listItems, null, null); } /** * Populates the JComboBox with the items provided adding hover tooltips * and selecting the specified item. * * @param comboBox The JComboBox to populate * @param listItems The items to populate the box with * @param selected The item to select in the JComboBox */ private void displayItemsWithTooltips(JComboBox comboBox, List<DataNode> listItems, DataNode selected) { displayItems(comboBox, listItems, selected, null); } /** * Returns <code>true</code> if the specified user is an administrator, * <code>false</code> otherwise. * * @param userID The identifier of the user. * @return See above. */ private boolean isAdmin(long userID) { Iterator<GroupData> i = groups.iterator(); GroupData g; Set<ExperimenterData> experimenters; while (i.hasNext()) { g = i.next(); if (model.isSystemGroup(g.getId(), GroupData.SYSTEM)) { experimenters = g.getExperimenters(); Iterator<ExperimenterData> j = experimenters.iterator(); while (j.hasNext()) { if (j.next().getId() == userID) return true; } } } return false; } /** * Populates the JComboBox with the items provided adding hover tooltips, * selecting the specified item and attaching the listener. * * @param comboBox The JComboBox to populate * @param listItems The items to populate the box with * @param select The item to select in the JComboBox * @param itemListener An item listener to add for the JComboBox */ private void displayItems(JComboBox comboBox, List<DataNode> listItems, DataNode select, ItemListener itemListener) { if (comboBox == null || listItems == null) return; //Only add the item the user can actually select if (itemListener != null) comboBox.removeItemListener(itemListener); comboBox.removeAllItems(); List<String> tooltips = new ArrayList<String>(listItems.size()); List<String> lines; ExperimenterData exp; SelectableComboBoxModel model = new SelectableComboBoxModel(); Selectable<DataNode> selected = null; GroupData group = getSelectedGroup(); ExperimenterData user = getSelectedUser(); long userID = -1; if (user != null) userID = user.getId(); ExperimenterData loggedIn = ImporterAgent.getUserDetails(); boolean isAdmin = ImporterAgent.isAdministrator(); long loggedInID = loggedIn.getId(); boolean userIsAdmin = isAdmin(userID); for (DataNode node : listItems) { exp = getExperimenter(node.getOwner()); lines = new ArrayList<String>(); if (exp != null) { lines.add("<b>Owner: </b>" + EditorUtil.formatExperimenter(exp)); } lines.addAll(UIUtilities.wrapStyleWord(node.getFullName())); tooltips.add(UIUtilities.formatToolTipText(lines)); boolean selectable = true; if (!node.isDefaultNode()) { selectable = canLink(node.getDataObject(), userID, group, loggedInID, isAdmin, userIsAdmin); } Selectable<DataNode> comboBoxItem = new Selectable<DataNode>(node, selectable); if (select != null && node.getDataObject().getId() == select.getDataObject().getId()) selected = comboBoxItem; model.addElement(comboBoxItem); } ComboBoxToolTipRenderer renderer = createComboboxRenderer(); renderer.setTooltips(tooltips); comboBox.setModel(model); comboBox.setRenderer(renderer); if (selected != null) comboBox.setSelectedItem(selected); if (itemListener != null) comboBox.addItemListener(itemListener); } /** * Returns <code>true</code> if the user currently selected * can link data to the selected object, <code>false</code> otherwise. * * @param node The node to handle. * @param userID The id of the selected user. * @param group The selected group. * @param loggedUserID the if of the user currently logged in. * @param isAdmin Returns <code>true</code> if the logged in user is an * administrator, <code>false</code> otherwise. * @param userIsAdmin Returns <code>true</code> if the selected user is an * administrator, <code>false</code> otherwise. * @return See above. */ private boolean canLink(DataObject node, long userID, GroupData group, long loggedUserID, boolean isAdmin, boolean userIsAdmin) { //data owner if (node.getOwner().getId() == userID) return true; if (!node.canLink()) return false; //handle private group case. PermissionData permissions = group.getPermissions(); if (permissions.getPermissionsLevel() == GroupData.PERMISSIONS_PRIVATE) return false; if (permissions.isGroupWrite() || userIsAdmin) return true; //read-only group and higher //is the selected user a group owner. Set leaders = group.getLeaders(); if (leaders != null) { Iterator i = leaders.iterator(); ExperimenterData exp; while (i.hasNext()) { exp = (ExperimenterData) i.next(); if (exp.getId() == userID) return true; } } if (userID != loggedUserID) return false; return isAdmin; } /** * Creates the renderer depending on the selected user. * * @return See above. */ private ComboBoxToolTipRenderer createComboboxRenderer() { ExperimenterData exp = getSelectedUser(); long id = -1; if (exp != null) id = exp.getId(); return new ComboBoxToolTipRenderer(id); } /** * Populates the JComboBox with the user details provided, * selecting the logged in user and attaching the item listener. * * @param comboBox The JComboBox to populate * @param group The group being displayed * @param itemListener An item listener to add for the JComboBox * @param userID The id of the user. */ private void displayUsers(JComboBox comboBox, GroupData group, ItemListener itemListener, long userID) { if (comboBox == null || group == null) return; if (itemListener != null) comboBox.removeItemListener(itemListener); comboBox.removeAllItems(); DefaultComboBoxModel model = new SelectableComboBoxModel(); Selectable<ExperimenterDisplay> selected = null; List<ExperimenterData> members = sort(group.getExperimenters()); boolean canImportAs; Selectable<ExperimenterDisplay> item; List<String> tooltips = new ArrayList<String>(members.size()); List<String> lines; for (ExperimenterData user : members) { canImportAs = canImportForUserInGroup(user, group); item = new Selectable<ExperimenterDisplay>(new ExperimenterDisplay(user), canImportAs); if (user.getId() == userID) selected = item; lines = new ArrayList<String>(); lines.addAll(UIUtilities.wrapStyleWord(EditorUtil.formatExperimenter(user))); tooltips.add(UIUtilities.formatToolTipText(lines)); model.addElement(item); } ComboBoxToolTipRenderer renderer = createComboboxRenderer(); renderer.setTooltips(tooltips); comboBox.setModel(model); comboBox.setRenderer(renderer); if (selected != null) comboBox.setSelectedItem(selected); if (itemListener != null) comboBox.addItemListener(itemListener); } /** * Creates a project. * @param newProject The project to create. */ protected void createProject(DataObject newProject) { if (newProject == null) return; DataNode newProjectNode = new DataNode(newProject); DataNode newDefaultDatasetNode = new DataNode(DataNode.createDefaultDataset(), newProjectNode); newProjectNode.addNode(newDefaultDatasetNode); List<DataNode> newDatasets = new ArrayList<DataNode>(); newDatasets.add(newDefaultDatasetNode); projects.add(newProjectNode); projects = sort(projects); datasets.put(newProjectNode, newDatasets); displayItems(projectsBox, projects, newProjectNode, this); displayItemsWithTooltips(datasetsBox, newDatasets); repaint(); } /** * Creates the dataset. * @param dataset The dataset to create. */ protected void createDataset(DatasetData dataset) { if (dataset == null) return; DataNode selectedProject = getSelectedItem(projectsBox); DataNode newDatasetNode = new DataNode(dataset, selectedProject); List<DataNode> projectDatasets = datasets.get(selectedProject); if (projectDatasets == null) { projectDatasets = new ArrayList<DataNode>(); DataNode newDefaultDatasetNode = new DataNode(DataNode.createDefaultDataset(), selectedProject); selectedProject.addNode(newDefaultDatasetNode); projectDatasets.add(newDefaultDatasetNode); } projectDatasets.add(newDatasetNode); projectDatasets = sort(projectDatasets); datasets.put(selectedProject, projectDatasets); displayItemsWithTooltips(datasetsBox, projectDatasets, newDatasetNode); repaint(); } /** * Creates a screen. * @param newScreenObject The screen to create. */ protected void createScreen(DataObject newScreenObject) { if (newScreenObject == null) return; DataNode newScreenNode = new DataNode(newScreenObject); screens.add(newScreenNode); screens = sort(screens); displayItemsWithTooltips(screensBox, screens, newScreenNode); repaint(); } /** * Populates the datasets box depending on the selected project. */ private void populateDatasetsBox() { DataNode project = getSelectedItem(projectsBox); displayItemsWithTooltips(datasetsBox, datasets.get(project)); } /** * Handles property fired by the Editor Dialog. * @see PropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if (EditorDialog.CREATE_NO_PARENT_PROPERTY.equals(name)) { Object ho = evt.getNewValue(); DataObject child = null, parent = null; if (ho instanceof ProjectData || ho instanceof ScreenData) { child = (DataObject) ho; } else if (ho instanceof DatasetData) { child = (DataObject) ho; DataNode n = getSelectedItem(projectsBox); if (!n.isDefaultNode()) { parent = n.getDataObject(); } } GroupData selectedGroup = getSelectedGroup(); if (child != null) { firePropertyChange(ImportDialog.CREATE_OBJECT_PROPERTY, null, new ObjectToCreate(selectedGroup, child, parent, getSelectedUser())); } } } /** * Returns the currently selected group in the Group selection box. * @return see above. */ private GroupData getSelectedGroup() { JComboBoxImageObject selectedEntry = (JComboBoxImageObject) groupsBox.getSelectedItem(); return (GroupData) selectedEntry.getData(); } /** * Converts the treeNodes in to DataNdoes used to hold display data for the * location combo boxes. * @param treeNodes The nodes to convert for import target options. */ private void convertToDisplayData(Collection<TreeImageDisplay> treeNodes) { projects.clear(); datasets.clear(); screens.clear(); DataNode defaultProject = new DataNode(DataNode.createDefaultProject()); List<DataNode> orphanDatasets = new ArrayList<DataNode>(); List<DataNode> lp = new ArrayList<DataNode>(); List<DataNode> ls = new ArrayList<DataNode>(); if (treeNodes != null) { for (TreeImageDisplay treeNode : treeNodes) { Object userObject = treeNode.getUserObject(); if (userObject instanceof ProjectData) { DataNode project = new DataNode((ProjectData) userObject); lp.add(project); List<DataNode> projectDatasets = new ArrayList<DataNode>(); List children = treeNode.getChildrenDisplay(); TreeImageDisplay n; for (Object child : children) { n = (TreeImageDisplay) child; projectDatasets.add(new DataNode((DatasetData) n.getUserObject())); } List<DataNode> list = new ArrayList<DataNode>(); list.add(new DataNode(DataNode.createDefaultDataset())); list.addAll(sort(projectDatasets)); datasets.put(project, list); } if (userObject instanceof ScreenData) { DataNode screen = new DataNode((ScreenData) userObject); ls.add(screen); } if (userObject instanceof DatasetData) { DataNode dataset = new DataNode((DatasetData) userObject); orphanDatasets.add(dataset); } } } List<DataNode> l = new ArrayList<DataNode>(); l.add(new DataNode(DataNode.createDefaultDataset())); l.addAll(sort(orphanDatasets)); datasets.put(defaultProject, l); projects.add(defaultProject); projects.addAll(sort(lp)); screens.add(new DataNode(DataNode.createDefaultScreen())); screens.addAll(sort(ls)); } /** * Helper method to sort objects and casts as a List<T>. * @param list The list to sort * @return The sorted list */ private <T> List<T> sort(Collection<T> list) { return (List<T>) sorter.sort(list); } /** * Populates the selection boxes with the currently selected data. */ private void populateLocationComboBoxes() { DataNode selectedProject = null; DataNode selectedDataset = null; DataNode selectedScreen = null; /* work out what to select, * NOTE: this defaults back to the selected container * on tab switch / refresh */ if (container != null) { Object hostObject = container.getUserObject(); if (hostObject instanceof ProjectData) { selectedProject = findDataNode(projects, hostObject, ProjectData.class); } if (hostObject instanceof DatasetData) { Object parentNode = getParentUserObject(container); selectedProject = findDataNode(projects, parentNode, ProjectData.class); DatasetData datasetData = (DatasetData) hostObject; long datasetId = datasetData.getId(); selectedDataset = findDataNodeById(datasets.get(selectedProject), datasetId); } if (hostObject instanceof ScreenData) { selectedScreen = findDataNode(screens, hostObject, ScreenData.class); } } else { selectedProject = findDataNode(projects, currentProject); selectedDataset = findDataNode(datasets.get(selectedProject), currentDataset); selectedScreen = findDataNode(screens, currentScreen); } switch (dataType) { case Importer.PROJECT_TYPE: displayItems(projectsBox, sortByUser(projects), selectedProject, this); displayItemsWithTooltips(datasetsBox, sortByUser(datasets.get(selectedProject)), selectedDataset); break; case Importer.SCREEN_TYPE: if (container != null) { Object hostObject = container.getUserObject(); selectedScreen = findDataNode(screens, hostObject, ScreenData.class); } displayItemsWithTooltips(screensBox, sortByUser(screens), selectedScreen); } } /** * Sorts the nodes. * * @param nodes The nodes to sort. * @return See above. */ private List<DataNode> sortByUser(List<DataNode> nodes) { if (CollectionUtils.isEmpty(nodes)) return nodes; List<DataNode> sorted = new ArrayList<DataNode>(); ListMultimap<Long, DataNode> map = ArrayListMultimap.create(); sorted.add(nodes.get(0)); //default node. Iterator<DataNode> i = nodes.iterator(); DataNode node; while (i.hasNext()) { node = i.next(); if (!node.isDefaultNode()) { map.put(node.getDataObject().getOwner().getId(), node); } } ExperimenterData exp = getSelectedUser(); List<DataNode> l = map.get(exp.getId()); if (CollectionUtils.isNotEmpty(l)) sorted.addAll(sort(l)); //items are ordered by users. long id; ExperimenterData user; for (int j = 0; j < usersBox.getItemCount(); j++) { user = getUser(j); if (user != null) { id = user.getId(); if (id != exp.getId()) sorted.addAll(sort(map.get(id))); } } return sorted; } /** * Searches the list of nodes returning the entry with the same Id as * the find parameter, returns <null> if the list is empty, or the first * item in the list if the find parameter is not found or is null. * @param nodes The list of nodes to scan. * @param find The node to match Id against. * @return The item, <null> if no list, first list item if find is <null>. */ private DataNode findDataNode(List<DataNode> nodes, DataNode find) { if (CollectionUtils.isEmpty(nodes)) return null; if (find == null) return nodes.get(0); for (DataNode node : nodes) { if (getIdOf(node) == getIdOf(find)) return node; } return nodes.get(0); } /** * Helper method to return the UserObject of the parent node. * @return see above. */ private Object getParentUserObject(TreeImageDisplay node) { if (node.getParentDisplay() == null) return null; return node.getParentDisplay().getUserObject(); } /** * Searches a list of DataNodes for an entry with a matching Id and type to * that of the DataObject provided * @param list The list of DataNodes to search through. * @param find The object to * @param klass The Class<T> description of the type to match against. * @return */ private <T extends DataObject> DataNode findDataNode(List<DataNode> list, Object find, Class<T> klass) { DataNode selectedItem = null; if (find != null && klass.isInstance(find)) { T dataObject = klass.cast(find); long nodeId = dataObject.getId(); selectedItem = findDataNodeById(list, nodeId); } if (selectedItem == null) selectedItem = list.get(0); return selectedItem; } /** * Resets the display to the selection and group specified. * * @param container The container that is selected * @param type The data type identifier (Project / SCreen) * @param objects The objects to use. * @param currentGroupId The currently active user group. * @param userID The id of the user. */ void reset(TreeImageDisplay container, int type, Collection<TreeImageDisplay> objects, long currentGroupId, long userID) { this.dataType = type; this.objects = objects; this.container = container; populateUIWithDisplayData(findWithId(groups, currentGroupId), userID); setInputsEnabled(true); } /** * Listener for the swapping of Screen / Project tabs * @see ChangeListener */ public void stateChanged(ChangeEvent evt) { Object source = evt.getSource(); if (source == tabbedPane) { JTabbedPane tabbedPane = (JTabbedPane) evt.getSource(); JPanel activePanel = (JPanel) tabbedPane.getSelectedComponent(); // default to projects int newDataType = Importer.PROJECT_TYPE; if (activePanel == screenPanel) newDataType = Importer.SCREEN_TYPE; storeCurrentSelections(); firePropertyChange(ImportDialog.REFRESH_LOCATION_PROPERTY, null, new ImportLocationDetails(newDataType, getSelectedUser().getId())); } } /** * Stores the currently selected combobox items for restoration later. */ private void storeCurrentSelections() { currentProject = getSelectedItem(projectsBox); currentDataset = getSelectedItem(datasetsBox); currentScreen = getSelectedItem(screensBox); } /** * Returns the selected item in the combo box as a DataNode. * @param comboBox see above. * @return see above. */ private DataNode getSelectedItem(JComboBox comboBox) { Object compareItem = comboBox.getSelectedItem(); if (compareItem instanceof Selectable<?>) { Selectable<?> selectable = (Selectable<?>) compareItem; if (!selectable.isSelectable()) return null; Object innerItem = selectable.getObject(); if (innerItem instanceof DataNode) return (DataNode) innerItem; } return null; } /** * Returns the Id of the DataNode. * @param node The node to use. * @return The id of the node. */ private long getIdOf(DataNode node) { if (node == null || node.getDataObject() == null) return -1; return node.getDataObject().getId(); } /** * Listener for Group and Project JComboBox selection events * @see ItemChangeListener */ public void itemStateChanged(ItemEvent ie) { Object source = ie.getSource(); if (ie.getStateChange() == ItemEvent.SELECTED) { if (source == groupsBox) { storeCurrentSelections(); switchToSelectedGroup(); } else if (source == usersBox) { switchToSelectedUser(); } else if (source == projectsBox) { DataNode node = getSelectedItem(projectsBox); datasetsBox.setEnabled(true); newDatasetButton.setEnabled(true); if (node.isDefaultProject()) newDatasetButton.setEnabled(true); populateDatasetsBox(); } } } /** * Sets the currently selected group * @param group The group to set as selected */ void setSelectedGroup(GroupData group) { groupsBox.setSelectedItem(group); } /** * Enables or disables the user input controls * @param isEnabled Whether to enable or disable the controls */ private void setInputsEnabled(boolean isEnabled) { projectsBox.setEnabled(isEnabled); datasetsBox.setEnabled(isEnabled); screensBox.setEnabled(isEnabled); newProjectButton.setEnabled(isEnabled); newDatasetButton.setEnabled(isEnabled); newScreenButton.setEnabled(isEnabled); addButton.setEnabled(isEnabled); groupsBox.setEnabled(isEnabled); usersBox.setEnabled(isEnabled); tabbedPane.setEnabled(isEnabled); refreshButton.setEnabled(isEnabled); } }