/* *------------------------------------------------------------------------------ * Copyright (C) 2006-2015 University of Dundee. 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.util.ui; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; 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.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.JTextComponent; import info.clearthought.layout.TableLayout; import org.openmicroscopy.shoola.util.CommonsLangUtils; import org.openmicroscopy.shoola.agents.util.EditorUtil; import org.openmicroscopy.shoola.util.ui.IconManager; import org.openmicroscopy.shoola.util.ui.MultilineLabel; import org.openmicroscopy.shoola.util.ui.TitlePanel; import org.openmicroscopy.shoola.util.ui.UIUtilities; import org.openmicroscopy.shoola.agents.metadata.MetadataViewerAgent; import omero.gateway.model.BooleanAnnotationData; import omero.gateway.model.DataObject; import omero.gateway.model.DatasetData; import omero.gateway.model.DoubleAnnotationData; import omero.gateway.model.LongAnnotationData; import omero.gateway.model.ProjectData; import omero.gateway.model.ScreenData; import omero.gateway.model.AnnotationData; import omero.gateway.model.TagAnnotationData; import omero.gateway.model.TermAnnotationData; import omero.gateway.model.XMLAnnotationData; /** * Basic modal dialog brought up to create a new container. * * @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> * @version 3.0 * @since OME2.2 */ public class EditorDialog extends JDialog implements ActionListener, DocumentListener { /** Indicates that the dialog is to create object. */ public static final int CREATE_TYPE = 0; /** Indicates that the dialog is to edit the object.*/ public static final int EDIT_TYPE = 1; /** Indicates that the dialog is to view the object.*/ public static final int VIEW_TYPE = 2; /** Bound property indicating to create an object. */ public static final String CREATE_PROPERTY = "create"; /** Bound property indicating to create an object. */ public static final String CREATE_NO_PARENT_PROPERTY = "createNoParent"; /** Bound property indicating to create an object. */ public static final String CLOSE_EDITOR_DIALOG_PROPERTY = "closeEditorDialog"; /** The default size of the dialog. */ private static final Dimension WIN_DIM = new Dimension(600, 300); /** The default title of the window. */ private static final String TITLE = "Create"; /** The default title of the window. */ private static final String TITLE_EDIT = "Edit"; /** The default title of the window. */ private static final String TITLE_VIEW = "View"; /** Action command ID to close the dialog. */ private static final int CANCEL = 0; /** Action command ID to create a new object. */ private static final int SAVE = 1; /** Area where to enter the name of the <code>DataObject</code>. */ private JTextComponent nameArea; /** Area where to enter the description of the <code>DataObject</code>. */ private JTextArea descriptionArea; /** Component for editing boolean values */ private JComboBox checkBox; /** Button to close the dialog. */ private JButton cancelButton; /** Button to create a new item. */ private JButton saveButton; /** The object to create. */ private Object data; /** Box used to indicate that the new object will have public visibility. */ private JRadioButton publicBox; /** Box used to indicate that the new object will have group visibility. */ private JRadioButton groupBox; /** Box used to indicate that the new object will be private. */ private JRadioButton privateBox; /** The type of object to create. */ private String typeName; /** The original text when editing. */ private String originalText; /** The original text when editing. */ private String originalDescription; /** * Sets to <code>true</code> if the object will have a parent, * <code>false</code> otherwise. */ private boolean withParent; /** The type of dialog, either create or edit. */ private int type; /** * Builds and lays out the panel displaying the permissions of the edited * file. * * @return See above. */ private JPanel buildPermissions() { JPanel content = new JPanel(); content.add(privateBox); content.add(groupBox); content.add(publicBox); return content; } /** Initializes the components composing this display. */ private void initComponents() { publicBox = new JRadioButton(EditorUtil.PUBLIC); publicBox.setEnabled(false); groupBox = new JRadioButton(EditorUtil.GROUP_VISIBLE); groupBox.setEnabled(false); privateBox = new JRadioButton(EditorUtil.PRIVATE); privateBox.setSelected(true); privateBox.setEnabled(false); if (data instanceof XMLAnnotationData || data instanceof String) { nameArea = new MultilineLabel(); nameArea.setEditable(true); } else { nameArea = new JTextField(); nameArea.setBorder(BorderFactory.createEtchedBorder()); } nameArea.setName("name field"); descriptionArea = new MultilineLabel(); descriptionArea.setEditable(true); originalText = ""; originalDescription = ""; if (type == EDIT_TYPE || type == VIEW_TYPE) { originalText = getDataName(); originalDescription = getDataDescription(); nameArea.setText(originalText); descriptionArea.setText(originalDescription); if (type == EDIT_TYPE) descriptionArea.getDocument().addDocumentListener(this); } nameArea.getDocument().addDocumentListener(this); if (data instanceof BooleanAnnotationData) { checkBox = new JComboBox(); checkBox.addItem(Boolean.TRUE.toString()); checkBox.addItem(Boolean.FALSE.toString()); checkBox.setSelectedItem(((BooleanAnnotationData)data).getValue().toString()); checkBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { enableSave(); } }); } cancelButton = new JButton("Cancel"); cancelButton.setName("cancel button"); cancelButton.setToolTipText("Close the dialog."); cancelButton.addActionListener(this); cancelButton.setActionCommand(""+CANCEL); saveButton = new JButton("Create"); saveButton.setName("create button"); saveButton.setToolTipText("Create a new object."); switch (type) { case EDIT_TYPE: saveButton.setText("Save"); saveButton.setToolTipText("Edit the object."); break; case VIEW_TYPE: cancelButton.setText("Close"); saveButton.setVisible(false); } saveButton.addActionListener(this); saveButton.setActionCommand(""+SAVE); saveButton.setEnabled(false); getRootPane().setDefaultButton(saveButton); addWindowListener(new WindowAdapter() { public void windowOpened(WindowEvent e) { nameArea.requestFocus(); } }); } /** * Builds the panel hosting the {@link #nameArea} and the * {@link #descriptionArea}. If the <code>DataOject</code> can be annotated * and if we are in the {@link Editor#PROPERTIES_EDITOR} mode, we display * the annotation pane. * * @return See above. */ private JPanel buildContentPanel() { JPanel content = new JPanel(); double[][] tl = {{TableLayout.PREFERRED, TableLayout.FILL}, {TableLayout.PREFERRED, 5, TableLayout.FILL}}; TableLayout layout = new TableLayout(tl); content.setLayout(layout); content.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); String value = ", LEFT, TOP"; if (data instanceof XMLAnnotationData || data instanceof DoubleAnnotationData || data instanceof LongAnnotationData) { content.add(UIUtilities.setTextFont("Content"), "0, 2" + value); content.add(new JScrollPane(nameArea), "1, 2"); } else if (data instanceof BooleanAnnotationData) { content.add(checkBox, "1, 2"); } else if (data instanceof String) { content.add(new JScrollPane(nameArea), "1, 2"); } else { content.add(UIUtilities.setTextFont("Name"), "0, 0" + value); content.add(nameArea, "1, 0"); content.add(UIUtilities.setTextFont("Description"), "0, 2" + value); content.add(new JScrollPane(descriptionArea), "1, 2"); } return content; } /** * Builds and lays out the buttons. * * @return See above. */ public JPanel buildToolBar() { JPanel bar = new JPanel(); bar.setLayout(new BoxLayout(bar, BoxLayout.X_AXIS)); bar.add(cancelButton); bar.add(Box.createHorizontalStrut(5)); bar.add(saveButton); bar.add(Box.createHorizontalStrut(10)); JPanel p = UIUtilities.buildComponentPanelRight(bar); return p; } /** * Builds the panel hosting the title according to the * <code>DataObject</code>. * * @return See above. */ private TitlePanel buildTitlePanel() { IconManager im = IconManager.getInstance(); TitlePanel tp = null; Icon icon = im.getIcon(IconManager.CREATE_48); if (data instanceof ProjectData) { typeName = "Project"; icon = im.getIcon(IconManager.PROJECT_48); } else if (data instanceof DatasetData) { typeName = "Dataset"; icon = im.getIcon(IconManager.DATASET_48); } else if (data instanceof ScreenData) { typeName = "Screen"; icon = im.getIcon(IconManager.SCREEN_48); } else if (data instanceof TagAnnotationData) { typeName = "Tag"; icon = im.getIcon(IconManager.TAG_48); String ns = ((TagAnnotationData) data).getNameSpace(); if (TagAnnotationData.INSIGHT_TAGSET_NS.equals(ns)) { typeName = "Tag Set"; icon = im.getIcon(IconManager.TAG_SET_48); } } else if (data instanceof TermAnnotationData) { typeName = "Term"; } else if (data instanceof XMLAnnotationData) { typeName = "XML"; } else if (data instanceof String) { typeName = "Error"; } switch (type) { case CREATE_TYPE: tp = new TitlePanel("Create "+typeName, "Create a new "+typeName+".", icon); break; case EDIT_TYPE: if (CommonsLangUtils.isEmpty(typeName)) tp = new TitlePanel("Edit value", "", icon); else tp = new TitlePanel("Edit "+typeName, "Edit the "+typeName+".", icon); break; case VIEW_TYPE: tp = new TitlePanel("View "+typeName, "View the "+typeName+".", icon); break; } return tp; } /** * Builds the panel hosting the {@link #nameArea} and the * {@link #descriptionArea}. */ private void buildGUI() { Container c = getContentPane(); c.setLayout(new BorderLayout()); c.add(buildTitlePanel(), BorderLayout.NORTH); c.add(buildContentPanel(), BorderLayout.CENTER); c.add(buildToolBar(), BorderLayout.SOUTH); } /** Closes and disposes. */ private void close() { firePropertyChange(CLOSE_EDITOR_DIALOG_PROPERTY, Boolean.valueOf(false), Boolean.valueOf(true)); setVisible(false); dispose(); } /** Creates a new item. */ private void save() { String name = nameArea.getText(); if (name == null) return; name = name.trim(); if (name.length() == 0 && !(data instanceof BooleanAnnotationData)) return; if (data instanceof ProjectData) { ProjectData p = (ProjectData) data; p.setName(name); p.setDescription(descriptionArea.getText().trim()); data = p; } else if (data instanceof DatasetData) { DatasetData d = (DatasetData) data; d.setName(name); d.setDescription(descriptionArea.getText().trim()); data = d; } else if (data instanceof ScreenData) { ScreenData d = (ScreenData) data; d.setName(name); d.setDescription(descriptionArea.getText().trim()); data = d; } else if (data instanceof TagAnnotationData) { TagAnnotationData d = (TagAnnotationData) data; d.setContent(name); String text = descriptionArea.getText().trim(); if (text.length() > 0) d.setTagDescription(text); data = d; } else if (data instanceof XMLAnnotationData) { XMLAnnotationData d = (XMLAnnotationData) data; d.setContent(name); String text = descriptionArea.getText().trim(); if (text.length() > 0) d.setDescription(text); data = d; } else if (data instanceof TermAnnotationData) { TermAnnotationData d = (TermAnnotationData) data; d.setContent(name); String text = descriptionArea.getText().trim(); if (text.length() > 0) d.setTermDescription(text); data = d; } else if(data instanceof DoubleAnnotationData) { DoubleAnnotationData d = (DoubleAnnotationData) data; try { d.setDataValue(Double.parseDouble(name)); } catch (NumberFormatException e) { MetadataViewerAgent.getRegistry().getUserNotifier().notifyError("Invalid input", "'"+name+"' is not a floating point number."); return; } data = d; } else if(data instanceof LongAnnotationData) { LongAnnotationData d = (LongAnnotationData) data; try { d.setDataValue(Long.parseLong(name)); } catch (NumberFormatException e) { MetadataViewerAgent.getRegistry().getUserNotifier().notifyError("Invalid input", "'"+name+"' is not an integer value."); return; } data = d; } else if(data instanceof BooleanAnnotationData) { BooleanAnnotationData d = (BooleanAnnotationData) data; d.setValue(Boolean.parseBoolean(checkBox.getSelectedItem().toString())); data = d; } if (withParent) firePropertyChange(CREATE_PROPERTY, null, data); else firePropertyChange(CREATE_NO_PARENT_PROPERTY, null, data); close(); } /** * Checks if the object is supported. * * @param object The type of object to create. */ private void checkData(Object object) { if (object == null) throw new IllegalArgumentException("No object to create."); if (object instanceof ProjectData || object instanceof DatasetData || object instanceof ScreenData || object instanceof TagAnnotationData || object instanceof TermAnnotationData || object instanceof XMLAnnotationData || object instanceof String || object instanceof DoubleAnnotationData || object instanceof LongAnnotationData || object instanceof BooleanAnnotationData) return; throw new IllegalArgumentException("Object not supported."); } /** * Returns the name of the data object. * * @return See above. */ private String getDataName() { if (data instanceof ProjectData) return ((ProjectData) data).getName(); if (data instanceof DatasetData) return ((DatasetData) data).getName(); if (data instanceof ScreenData) return ((ScreenData) data).getName(); if (data instanceof TagAnnotationData || data instanceof TermAnnotationData || data instanceof XMLAnnotationData) return ((AnnotationData) data).getContentAsString(); if (data instanceof DoubleAnnotationData) return ""+((DoubleAnnotationData)data).getDataValue(); if (data instanceof LongAnnotationData) return ""+((LongAnnotationData)data).getDataValue(); if (data instanceof String) return data.toString(); return ""; } /** * Returns the description of the data object. * * @return See above. */ private String getDataDescription() { if (data instanceof ProjectData) return ((ProjectData) data).getDescription(); if (data instanceof DatasetData) return ((DatasetData) data).getDescription(); if (data instanceof ScreenData) return ((ScreenData) data).getDescription(); if (data instanceof TagAnnotationData) return ((TagAnnotationData) data).getTagDescription(); if (data instanceof TermAnnotationData) return ((TermAnnotationData) data).getTermDescription(); if (data instanceof XMLAnnotationData) return ((XMLAnnotationData) data).getDescription(); if (data instanceof String) return data.toString(); return ""; } /** Sets the enabled flag of the {@link #saveButton}. */ private void enableSave() { String name = nameArea.getText(); String desc = descriptionArea.getText(); if (type == CREATE_TYPE) { if (name == null) saveButton.setEnabled(false); else { name = name.trim(); int l = name.length(); saveButton.setEnabled(l > 0); } } else if (type == EDIT_TYPE) { if(data instanceof BooleanAnnotationData) { saveButton.setEnabled(!checkBox.getSelectedItem().toString().equals(((BooleanAnnotationData)data).getValue().toString())); } else if (!originalText.equals(name)) { name = name.trim(); int l = name.length(); saveButton.setEnabled(l > 0); } else { desc = desc.trim(); saveButton.setEnabled(!originalDescription.equals(desc)); } } } /** * Initializes. * * @param data The type of object to create. * @param withParent Sets to <code>true</code> if the object will * have a parent, <code>false</code> otherwise. * @param type The type of the dialog. */ private void init(Object data, boolean withParent, int type) { switch (type) { case EDIT_TYPE: this.type = type; setTitle(TITLE_EDIT); break; case VIEW_TYPE: this.type = type; setTitle(TITLE_VIEW); break; case CREATE_TYPE: default: this.type = CREATE_TYPE; setTitle(TITLE); } checkData(data); this.data = data; this.withParent = withParent; initComponents(); buildGUI(); setName("editor dialog"); setSize(WIN_DIM); } /** * Creates a new instance. * * @param owner The owner of the frame. * @param data The type of object to create. * @param withParent Sets to <code>true</code> if the object will * have a parent, <code>false</code> otherwise. * @param type The type of the dialog. */ public EditorDialog(JFrame owner, DataObject data, boolean withParent, int type) { super(owner); init(data, withParent, type); } /** * Creates a new instance. * * @param owner The owner of the frame. * @param data The type of object to create. * @param type The type of the dialog. */ public EditorDialog(JFrame owner, String data, int type) { super(owner); init(data, withParent, type); } /** * Creates a new instance. * * @param owner The owner of the frame. * @param data The type of object to create. * @param withParent Sets to <code>true</code> if the object will * have a parent, <code>false</code> otherwise. */ public EditorDialog(JFrame owner, DataObject data, boolean withParent) { this(owner, data, withParent, CREATE_TYPE); } /** * Creates a new instance. * * @param owner The owner of the frame. * @param data The type of object to create. * @param withParent Sets to <code>true</code> if the object will * have a parent, <code>false</code> otherwise. */ public EditorDialog(JDialog owner, DataObject data, boolean withParent) { super(owner); init(data, withParent, CREATE_TYPE); } /** * Sets the description of the dialog. * * @param description The description of the dialog. */ public void setOriginalDescription(String description) { if (description == null) return; originalDescription = description; descriptionArea.getDocument().removeDocumentListener(this); descriptionArea.setText(description); descriptionArea.getDocument().addDocumentListener(this); } /** * Allows to edit or not the name. * * @param edit Pass <code>true</code> to edit, <code>false</code> * otherwise. */ public void allowEdit(boolean edit) { nameArea.setEditable(edit); } /** * Creates a new item or closes the dialog. * @see ActionListener#actionPerformed(ActionEvent) */ public void actionPerformed(ActionEvent e) { int index = Integer.parseInt(e.getActionCommand()); switch (index) { case CANCEL: close(); break; case SAVE: save(); } } /** * Enables the save button depending on the value entered for the name. * @see DocumentListener#insertUpdate(DocumentEvent) */ public void insertUpdate(DocumentEvent e) { enableSave(); } /** * Enables the save button depending on the value entered for the name. * @see DocumentListener#removeUpdate(DocumentEvent) */ public void removeUpdate(DocumentEvent e) { enableSave(); } /** * Required by the {@link DocumentListener} I/F but no-op implementation * in our case. * @see DocumentListener#changedUpdate(DocumentEvent) */ public void changedUpdate(DocumentEvent e) {} }