From 47a081440e1de8364d9645f1570e248f6e3ad813 Mon Sep 17 00:00:00 2001 From: "piotr.gawron" <piotr.gawron@uni-new> Date: Fri, 30 Sep 2016 14:15:24 +0200 Subject: [PATCH] editor refactoring to match merge species and alias --- .../gui/detailstab/ElementDetailsPanel.java | 1594 ++++++++--------- 1 file changed, 797 insertions(+), 797 deletions(-) diff --git a/editor/src/main/java/lcsb/mapviewer/editor/gui/detailstab/ElementDetailsPanel.java b/editor/src/main/java/lcsb/mapviewer/editor/gui/detailstab/ElementDetailsPanel.java index 092ca4092b..e544119e74 100644 --- a/editor/src/main/java/lcsb/mapviewer/editor/gui/detailstab/ElementDetailsPanel.java +++ b/editor/src/main/java/lcsb/mapviewer/editor/gui/detailstab/ElementDetailsPanel.java @@ -1,797 +1,797 @@ -package lcsb.mapviewer.editor.gui.detailstab; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JColorChooser; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.text.JTextComponent; - -import lcsb.mapviewer.commands.CommandExecutionException; -import lcsb.mapviewer.commands.ModelCommand; -import lcsb.mapviewer.common.exception.InvalidArgumentException; -import lcsb.mapviewer.common.exception.InvalidStateException; -import lcsb.mapviewer.common.exception.NotImplementedException; -import lcsb.mapviewer.editor.gui.ElementModifiedEvent; -import lcsb.mapviewer.editor.gui.ElementModifiedEventListener; -import lcsb.mapviewer.editor.gui.GuiStyle; -import lcsb.mapviewer.editor.gui.MiriamDataCellRender; -import lcsb.mapviewer.editor.gui.objectedit.MiriamDataDialog; -import lcsb.mapviewer.editor.gui.objectedit.ObjectEditDialog; -import lcsb.mapviewer.editor.gui.objectedit.StringEditDialog; -import lcsb.mapviewer.model.map.MiriamData; -import lcsb.mapviewer.model.map.layout.alias.Alias; -import lcsb.mapviewer.model.map.layout.alias.CompartmentAlias; -import lcsb.mapviewer.model.map.layout.alias.ComplexAlias; -import lcsb.mapviewer.model.map.model.Model; -import lcsb.mapviewer.model.map.reaction.Reaction; - -import org.apache.log4j.Logger; - -/** - * {@link JPanel} with detail information about selected {@link Alias} or - * {@link Reaction}. - * - * @author Piotr Gawron - * - */ -public class ElementDetailsPanel extends JPanel { - - /** - * X ratio between label and field that contains data in a single row. (take a - * look at {@link GridBagConstraints#weightx}). - */ - private static final double GRID_RATIO = 0.5; - - /** - * - */ - private static final long serialVersionUID = 1L; - - /** - * Default class logger. - */ - private final Logger logger = Logger.getLogger(ElementDetailsPanel.class); - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#name} parameter. - */ - private JLabel nameLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#getElementId()} - * parameter. - */ - private JLabel idLabel; - - /** - * Label for complex parameter. - */ - private JLabel complexLabel; - - /** - * Label for {@link Alias#compartmentAlias} parameter. - */ - private JLabel compartmentLabel; - - /** - * Label for {@link Alias#fontSize} parameter. - */ - private JLabel fontSizeLabel; - - /** - * Label for {@link Alias#color} parameter. - */ - private JLabel colorLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#notes} parameter. - */ - private JLabel notesLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#symbol} parameter. - */ - private JLabel symbolLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#fullName} parameter. - */ - private JLabel fullNameLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#abbreviation} parameter. - */ - private JLabel abbreviationLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#formula} parameter. - */ - private JLabel formulaLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#synonyms} parameter. - */ - private JLabel synonymsLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#formerSymbols} parameter. - */ - private JLabel formerSymbolsLabel; - - /** - * Label for {@link lcsb.mapviewer.model.map.Element#symbol} parameter. - */ - private JLabel miriamDataLabel; - - /** - * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#name} - * parameter. - */ - private JTextField nameText; - - /** - * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#name} - * parameter. - */ - private JTextField idText; - - /** - * {@link JTextField} for complex parameter. - */ - private JTextField complexText; - - /** - * {@link JTextField} for {@link Alias#compartmentAlias} parameter. - */ - private JTextField compartmentText; - - /** - * {@link JTextField} for {@link Alias#fontSize} parameter. - */ - private JTextField fontSizeText; - - /** - * {@link JTextField} for {@link Alias#color} parameter. - */ - private JButton colorButton; - - /** - * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#notes} - * parameter. - */ - private JTextArea notesText; - - /** - * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#symbol} - * parameter. - */ - private JTextField symbolText; - - /** - * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#fullName} - * parameter. - */ - private JTextField fullNameText; - - /** - * {@link JTextField} for - * {@link lcsb.mapviewer.model.map.Element#abbreviation} parameter. - */ - private JTextField abbreviationText; - - /** - * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#formula} - * parameter. - */ - private JTextField formulaText; - - /** - * {@link JList} for {@link lcsb.mapviewer.model.map.Element#synonyms} - * parameter. - */ - private JList<String> synonymsList; - - /** - * {@link JList} for - * {@link lcsb.mapviewer.model.map.Element#formerSymbols} parameter. - */ - private JList<String> formerSymbolsList; - - /** - * {@link JList} for {@link lcsb.mapviewer.model.map.Element#miriamData} - * parameter. - */ - private JList<MiriamData> miriamDataList; - - /** - * List of synonyms in {@link lcsb.mapviewer.model.map.Element#synonyms}. - * - * @see {@link #synonymsList} - */ - private DefaultListModel<String> synonymsListModel = new DefaultListModel<>(); - - /** - * List of synonyms in {@link lcsb.mapviewer.model.map.Element#formerSymbols}. - * - * @see {@link #formerSymbolsList} - */ - private DefaultListModel<String> formerSymbolsListModel = new DefaultListModel<>(); - - /** - * List of synonyms in {@link lcsb.mapviewer.model.map.Element#miriamData}. - * - * @see {@link #miriamDataList} - */ - private DefaultListModel<MiriamData> miriamDataListModel = new DefaultListModel<>(); - - /** - * {@link Alias} or {@link Reaction} that is currently selected. - */ - private Object element; - - /** - * List of listeners that should be thrown when some properties of selected - * {@link Alias} is changed. - */ - private List<ElementModifiedEventListener<Alias>> aliasListeners = new ArrayList<>(); - - /** - * List of listeners that should be thrown when some properties of selected - * {@link Reaction} is changed. - */ - private List<ElementModifiedEventListener<Reaction>> reactionListeners = new ArrayList<>(); - - /** - * This flag value is set when data in the panel is updated from newly - * selected element. - */ - private boolean updatingData = false; - - /** - * Default constructor. - */ - public ElementDetailsPanel() { - GridBagLayout gridLayout = new GridBagLayout(); - setLayout(gridLayout); - setPreferredSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH, GuiStyle.DETAIL_PANEL_HEIGHT)); - - nameLabel = new JLabel("Name: "); - idLabel = new JLabel("ID: "); - complexLabel = new JLabel("Parent complex: "); - compartmentLabel = new JLabel("Parent compartment: "); - fontSizeLabel = new JLabel("Font size: "); - colorLabel = new JLabel("Color: "); - notesLabel = new JLabel("Notes: "); - symbolLabel = new JLabel("Symbol: "); - fullNameLabel = new JLabel("Full name: "); - abbreviationLabel = new JLabel("Abbreviation: "); - formulaLabel = new JLabel("Formula: "); - synonymsLabel = new JLabel("Synonyms: "); - formerSymbolsLabel = new JLabel("Former symbols: "); - miriamDataLabel = new JLabel("Annotations: "); - - nameText = new JTextField(); - idText = new JTextField(); - idText.setEditable(false); - idText.setEnabled(false); - complexText = new JTextField(); - complexText.setEditable(false); - complexText.setEnabled(false); - compartmentText = new JTextField(); - compartmentText.setEditable(false); - compartmentText.setEnabled(false); - fontSizeText = new JTextField(); - colorButton = new JButton("Change"); - notesText = new JTextArea(); - notesText.setLineWrap(true); - notesText.setWrapStyleWord(true); - symbolText = new JTextField(); - fullNameText = new JTextField(); - abbreviationText = new JTextField(); - formulaText = new JTextField(); - synonymsList = new JList<>(synonymsListModel); - formerSymbolsList = new JList<>(formerSymbolsListModel); - miriamDataList = new JList<>(miriamDataListModel); - miriamDataList.setCellRenderer(new MiriamDataCellRender()); - - assignCommandToField(nameText, new CreateChangeNameCommand(nameText)); - assignCommandToField(fontSizeText, new CreateChangeFontSizeCommand(fontSizeText)); - assignCommandToField(notesText, new CreateChangeNotesCommand(notesText)); - assignCommandToField(symbolText, new CreateChangeSymbolCommand(symbolText)); - assignCommandToField(fullNameText, new CreateChangeFullNameCommand(fullNameText)); - assignCommandToField(abbreviationText, new CreateChangeAbbreviationCommand(abbreviationText)); - assignCommandToField(formulaText, new CreateChangeFormulaCommand(formulaText)); - assignColorCommandToField(colorButton, new CreateChangeColorCommand(colorButton)); - assignCommandToList(synonymsList, new CreateChangeSynonymCommand(synonymsList), "Synonym", String.class); - assignCommandToList(formerSymbolsList, new CreateChangeFormerSymbolCommand(formerSymbolsList), "Former symbol", String.class); - assignCommandToList(miriamDataList, new CreateChangeMiriamDataCommand(miriamDataList), "Miriam data", MiriamData.class); - } - - /** - * Creates listener that will handle changes on list parameter. It assigns - * {@link CreateListPropertyChangeCommand<T>} object that will create a proper - * {@link ModelCommand} when changes are made to the parameter field. - * - * @param list - * component where changes can be made - * @param dialogTitle - * title of the dialog used for editing property - * @param clazz - * class type of the property - * @param createCommandObject - * object that will create apropriate {@link ModelCommand} - * @param <T> - * type of the objects included in the parameter list - */ - private <T> void assignCommandToList(JList<T> list, CreateListPropertyChangeCommand<T> createCommandObject, String dialogTitle, Class<T> clazz) { - list.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - logger.debug("Mouse pressed"); - if (e.isPopupTrigger()) { - doPop(e); - } - } - - @Override - public void mouseReleased(MouseEvent e) { - if (e.isPopupTrigger()) { - doPop(e); - } - } - - private void doPop(MouseEvent e) { - JPopupMenu menu = new JPopupMenu(); - JMenuItem addItem = new JMenuItem("Add"); - menu.add(addItem); - addItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ObjectEditDialog<T> editDialog = createEditDialog(dialogTitle, clazz); - editDialog.addOkListener(new ElementModifiedEventListener<T>() { - - @Override - public void actionPerformed(ElementModifiedEvent<T> e) throws CommandExecutionException { - T s = e.getElement(); - List<T> values = new ArrayList<>(); - values.add(s); - ModelCommand modelCommand = createCommandObject.createAddCommand(getModel(), (Alias) element, values); - processCommand(modelCommand); - ((DefaultListModel<T>) list.getModel()).addElement(s); - } - }); - editDialog.editObject(null); - } - - }); - if (list.getSelectedIndices().length == 1) { - JMenuItem editItem = new JMenuItem("Edit"); - menu.add(editItem); - editItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ObjectEditDialog<T> editDialog = createEditDialog(dialogTitle, clazz); - editDialog.addOkListener(new ElementModifiedEventListener<T>() { - @Override - public void actionPerformed(ElementModifiedEvent<T> e) throws CommandExecutionException { - T s = e.getElement(); - ModelCommand modelCommand = createCommandObject.createChangeCommand(getModel(), (Alias) element, s, list.getSelectedValue()); - processCommand(modelCommand); - ((DefaultListModel<T>) list.getModel()).set(list.getSelectedIndices()[0], s); - } - }); - editDialog.editObject(list.getSelectedValue()); - } - }); - } - if (list.getSelectedIndices().length > 0) { - JMenuItem removeItem = new JMenuItem("Remove"); - menu.add(removeItem); - removeItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - List<T> elements = new ArrayList<>(); - for (T string : list.getSelectedValuesList()) { - elements.add(string); - } - ModelCommand modelCommand = createCommandObject.createRemoveCommand(getModel(), (Alias) element, elements); - try { - processCommand(modelCommand); - for (T string : elements) { - ((DefaultListModel<T>) list.getModel()).removeElement(string); - } - } catch (CommandExecutionException exception) { - JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); - } - } - }); - } - menu.show(e.getComponent(), e.getX(), e.getY()); - } - }); - } - - /** - * Creates listener that will handle changes on color button parameter. It - * assigns {@link CreateListPropertyChangeCommand<T>} object that will create - * a proper {@link ModelCommand} when changes are made to the parameter field. - * - * @param colorButton - * component where changes can be made - * @param createCommandObject - * object that will create apropriate {@link ModelCommand} - */ - private void assignColorCommandToField(JButton colorButton, CreatePropertyChangeCommand createCommandObject) { - colorButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!updatingData && element != null) { - Color newColor = JColorChooser.showDialog(ElementDetailsPanel.this, "Choose Color", colorButton.getBackground()); - if (newColor != null) { - colorButton.setBackground(newColor); - ModelCommand modelCommand = createCommandObject.createCommand(getModel(), (Alias) element); - try { - processCommand(modelCommand); - } catch (CommandExecutionException exception) { - JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); - } - } - } - } - - }); - } - - /** - * Executes parameter {@link ModelCommand} and fires appropraite listeners. - * - * @param modelCommand - * command to be executed - * @throws CommandExecutionException - * thrown when modelCommand cannot be executed due to some - * problematic input data - */ - public void processCommand(ModelCommand modelCommand) throws CommandExecutionException { - modelCommand.execute(); - if (modelCommand != null) { - if (element instanceof Alias) { - ElementModifiedEvent<Alias> event = new ElementModifiedEvent<Alias>(this, (Alias) element, modelCommand); - for (ElementModifiedEventListener<Alias> listener : aliasListeners) { - listener.actionPerformed(event); - } - } else if (element instanceof Reaction) { - ElementModifiedEvent<Reaction> event = new ElementModifiedEvent<Reaction>(this, (Reaction) element, modelCommand); - for (ElementModifiedEventListener<Reaction> listener : reactionListeners) { - listener.actionPerformed(event); - } - } else { - throw new NotImplementedException("Don't know how to handle: " + element.getClass()); - } - } - } - - /** - * Creates listener that will handle changes on {@link JTextComponent} - * parameter. It assigns {@link CreateListPropertyChangeCommand<T>} object - * that will create a proper {@link ModelCommand} when changes are made to the - * parameter field. - * - * @param field - * component where changes can be made - * @param createCommandObject - * object that will create apropriate {@link ModelCommand} - */ - private void assignCommandToField(JTextComponent field, CreatePropertyChangeCommand createCommandObject) { - field.addFocusListener(new FocusListener() { - public void focusGained(FocusEvent e) { - } - - public void focusLost(FocusEvent e) { - if (!updatingData && element != null) { - ModelCommand modelCommand = createCommandObject.createCommand(getModel(), (Alias) element); - try { - processCommand(modelCommand); - } catch (CommandExecutionException exception) { - JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); - } - } - } - }); - if (field instanceof JTextField) { - ((JTextField) field).addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!updatingData && element != null) { - ModelCommand modelCommand = createCommandObject.createCommand(getModel(), (Alias) element); - try { - processCommand(modelCommand); - } catch (CommandExecutionException exception) { - JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); - } - } - } - }); - } - - } - - /** - * Sets {@link #element}. - * - * @param object - * new {@link #element} value - */ - public void setElement(Object object) { - this.element = object; - - updateData(object); - } - - /** - * Updates data in the panel using parameter object as a data source. - * - * @param object - * object for which data details should be available - */ - private void updateData(Object object) { - updatingData = true; - removeAll(); - try { - if (object instanceof Alias) { - createAliasPanel((Alias) object); - } else if (object instanceof Reaction) { - createReactionPanel((Reaction) object); - } else if (object != null) { - throw new InvalidArgumentException("Cannot provide details for object: " + object); - } - validate(); - repaint(); - } finally { - updatingData = false; - } - - } - - /** - * Creates property details panel for reaction. - * - * @param object - * reaction for which panel will be created - */ - private void createReactionPanel(Reaction object) { - throw new NotImplementedException(); - - } - - /** - * Creates property details panel for alias. - * - * @param alias - * {@link Alias} for which panel will be created - */ - private void createAliasPanel(Alias alias) { - int row = 0; - add(nameLabel, createLayoutConstraints(0, row)); - add(nameText, createLayoutConstraints(1, row)); - nameText.setText(alias.getElement().getName()); - row++; - - add(idLabel, createLayoutConstraints(0, row)); - add(idText, createLayoutConstraints(1, row)); - idText.setText(alias.getAliasId()); - row++; - - add(complexLabel, createLayoutConstraints(0, row)); - add(complexText, createLayoutConstraints(1, row)); - if (alias.getParent() instanceof ComplexAlias) { - complexText.setText(alias.getParent().getAliasId()); - } else { - complexText.setText("N/A"); - } - row++; - - add(compartmentLabel, createLayoutConstraints(0, row)); - add(compartmentText, createLayoutConstraints(1, row)); - if (alias.getCompartmentAlias() instanceof CompartmentAlias) { - compartmentText.setText(alias.getCompartmentAlias().getAliasId()); - } else { - compartmentText.setText("N/A"); - } - row++; - - add(fontSizeLabel, createLayoutConstraints(0, row)); - add(fontSizeText, createLayoutConstraints(1, row)); - fontSizeText.setText(alias.getFontSize() + ""); - row++; - - add(colorLabel, createLayoutConstraints(0, row)); - add(colorButton, createLayoutConstraints(1, row)); - colorButton.setBackground(alias.getColor()); - row++; - - add(notesLabel, createLayoutConstraints(0, row)); - JScrollPane notesScrollContainer = new JScrollPane(); - notesScrollContainer.setViewportView(notesText); - notesScrollContainer.setWheelScrollingEnabled(true); - notesScrollContainer.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); - - add(notesScrollContainer, createLayoutConstraints(1, row)); - notesText.setText(alias.getElement().getNotes()); - row++; - - add(symbolLabel, createLayoutConstraints(0, row)); - add(symbolText, createLayoutConstraints(1, row)); - symbolText.setText(alias.getElement().getSymbol()); - row++; - - add(fullNameLabel, createLayoutConstraints(0, row)); - add(fullNameText, createLayoutConstraints(1, row)); - fullNameText.setText(alias.getElement().getFullName()); - row++; - - add(abbreviationLabel, createLayoutConstraints(0, row)); - add(abbreviationText, createLayoutConstraints(1, row)); - abbreviationText.setText(alias.getElement().getAbbreviation()); - row++; - - add(formulaLabel, createLayoutConstraints(0, row)); - add(formulaText, createLayoutConstraints(1, row)); - formulaText.setText(alias.getElement().getFormula()); - row++; - - add(synonymsLabel, createLayoutConstraints(0, row)); - JScrollPane synonymsScrollPane = new JScrollPane(synonymsList); - synonymsScrollPane.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); - add(synonymsScrollPane, createLayoutConstraints(1, row)); - synonymsListModel.removeAllElements(); - for (String string : alias.getElement().getSynonyms()) { - synonymsListModel.addElement(string); - } - row++; - - add(formerSymbolsLabel, createLayoutConstraints(0, row)); - JScrollPane formerSymbolsPane = new JScrollPane(formerSymbolsList); - formerSymbolsPane.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); - add(formerSymbolsPane, createLayoutConstraints(1, row)); - formerSymbolsListModel.removeAllElements(); - for (String string : alias.getElement().getFormerSymbols()) { - formerSymbolsListModel.addElement(string); - } - row++; - - add(miriamDataLabel, createLayoutConstraints(0, row)); - JScrollPane miriamDataPane = new JScrollPane(miriamDataList); - miriamDataPane.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); - add(miriamDataPane, createLayoutConstraints(1, row)); - miriamDataListModel.removeAllElements(); - for (MiriamData md : alias.getElement().getMiriamData()) { - miriamDataListModel.addElement(md); - } - row++; - - addFooterForAlignment(row++); - } - - /** - * Adds footer on bottom of the panel to make proper alignments. - * - * @param row - * row in which the last element should appear - */ - private void addFooterForAlignment(int row) { - JLabel button = new JLabel(""); - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.HORIZONTAL; - c.ipady = 0; // reset to default - c.weighty = 1.0; // request any extra vertical space - c.anchor = GridBagConstraints.PAGE_END; // bottom of space - c.gridx = 1; // aligned with button 2 - c.gridwidth = 2; // 2 columns wide - c.gridy = row; // third row - add(button, c); - } - - /** - * Create constraints for element located on x,y positions in - * {@link GridBagLayout}. - * - * @param x - * column - * @param y - * row - * @return {@link GridBagConstraints} for object at specified coordinates - */ - public GridBagConstraints createLayoutConstraints(int x, int y) { - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.HORIZONTAL; - c.anchor = GridBagConstraints.NORTH; - c.weightx = GRID_RATIO; - c.gridx = x; - c.gridy = y; - return c; - } - - /** - * Adds listener to be thrown when properties of the {@link #element edited - * Alias} is changing. - * - * @param e - * {@link ElementModifiedEventListener listener} to add - */ - public void addAliasModifiedEventListener(ElementModifiedEventListener<Alias> e) { - aliasListeners.add(e); - } - - /** - * Adds listener to be thrown when properties of the {@link #element edited - * Reaction} is changing. - * - * @param e - * {@link ElementModifiedEventListener listener} to add - */ - public void addReactionModifiedEventListener(ElementModifiedEventListener<Reaction> e) { - reactionListeners.add(e); - } - - /** - * Returns {@link Model} where edited element is located. - * - * @return {@link Model} where edited element is located - */ - private Model getModel() { - if (element instanceof Alias) { - return ((Alias) element).getModel(); - } else if (element instanceof Reaction) { - return ((Reaction) element).getModel(); - } else if (element != null) { - throw new InvalidStateException("Don't know how to handle object of class: " + element.getClass()); - } else { - return null; - } - } - - /** - * Created {@link ObjectEditDialog} that can edit objects of type specified in - * parameter. - * - * @param dialogTitle - * title that should be used in a dialog - * @param clazz - * class of a type of the object to edit - * @return {@link ObjectEditDialog} that can edit objects of type specified in - * parameter - * @param <T> - * type of the object to edit - */ - @SuppressWarnings("unchecked") - private <T> ObjectEditDialog<T> createEditDialog(String dialogTitle, Class<T> clazz) { - if (String.class.equals(clazz)) { - return (ObjectEditDialog<T>) new StringEditDialog(null, dialogTitle, dialogTitle); - } else if (MiriamData.class.equals(clazz)) { - return (ObjectEditDialog<T>) new MiriamDataDialog(null, dialogTitle, dialogTitle); - } else { - throw new NotImplementedException("Don't know how to handle: " + clazz); - } - } -} +package lcsb.mapviewer.editor.gui.detailstab; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JColorChooser; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.text.JTextComponent; + +import lcsb.mapviewer.commands.CommandExecutionException; +import lcsb.mapviewer.commands.ModelCommand; +import lcsb.mapviewer.common.exception.InvalidArgumentException; +import lcsb.mapviewer.common.exception.InvalidStateException; +import lcsb.mapviewer.common.exception.NotImplementedException; +import lcsb.mapviewer.editor.gui.ElementModifiedEvent; +import lcsb.mapviewer.editor.gui.ElementModifiedEventListener; +import lcsb.mapviewer.editor.gui.GuiStyle; +import lcsb.mapviewer.editor.gui.MiriamDataCellRender; +import lcsb.mapviewer.editor.gui.objectedit.MiriamDataDialog; +import lcsb.mapviewer.editor.gui.objectedit.ObjectEditDialog; +import lcsb.mapviewer.editor.gui.objectedit.StringEditDialog; +import lcsb.mapviewer.model.map.MiriamData; +import lcsb.mapviewer.model.map.layout.alias.Alias; +import lcsb.mapviewer.model.map.layout.alias.CompartmentAlias; +import lcsb.mapviewer.model.map.layout.alias.ComplexAlias; +import lcsb.mapviewer.model.map.model.Model; +import lcsb.mapviewer.model.map.reaction.Reaction; + +import org.apache.log4j.Logger; + +/** + * {@link JPanel} with detail information about selected {@link Alias} or + * {@link Reaction}. + * + * @author Piotr Gawron + * + */ +public class ElementDetailsPanel extends JPanel { + + /** + * X ratio between label and field that contains data in a single row. (take a + * look at {@link GridBagConstraints#weightx}). + */ + private static final double GRID_RATIO = 0.5; + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Default class logger. + */ + private final Logger logger = Logger.getLogger(ElementDetailsPanel.class); + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#name} parameter. + */ + private JLabel nameLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#getElementId()} + * parameter. + */ + private JLabel idLabel; + + /** + * Label for complex parameter. + */ + private JLabel complexLabel; + + /** + * Label for {@link Alias#compartmentAlias} parameter. + */ + private JLabel compartmentLabel; + + /** + * Label for {@link Alias#fontSize} parameter. + */ + private JLabel fontSizeLabel; + + /** + * Label for {@link Alias#color} parameter. + */ + private JLabel colorLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#notes} parameter. + */ + private JLabel notesLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#symbol} parameter. + */ + private JLabel symbolLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#fullName} parameter. + */ + private JLabel fullNameLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#abbreviation} parameter. + */ + private JLabel abbreviationLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#formula} parameter. + */ + private JLabel formulaLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#synonyms} parameter. + */ + private JLabel synonymsLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#formerSymbols} parameter. + */ + private JLabel formerSymbolsLabel; + + /** + * Label for {@link lcsb.mapviewer.model.map.Element#symbol} parameter. + */ + private JLabel miriamDataLabel; + + /** + * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#name} + * parameter. + */ + private JTextField nameText; + + /** + * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#name} + * parameter. + */ + private JTextField idText; + + /** + * {@link JTextField} for complex parameter. + */ + private JTextField complexText; + + /** + * {@link JTextField} for {@link Alias#compartmentAlias} parameter. + */ + private JTextField compartmentText; + + /** + * {@link JTextField} for {@link Alias#fontSize} parameter. + */ + private JTextField fontSizeText; + + /** + * {@link JTextField} for {@link Alias#color} parameter. + */ + private JButton colorButton; + + /** + * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#notes} + * parameter. + */ + private JTextArea notesText; + + /** + * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#symbol} + * parameter. + */ + private JTextField symbolText; + + /** + * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#fullName} + * parameter. + */ + private JTextField fullNameText; + + /** + * {@link JTextField} for + * {@link lcsb.mapviewer.model.map.Element#abbreviation} parameter. + */ + private JTextField abbreviationText; + + /** + * {@link JTextField} for {@link lcsb.mapviewer.model.map.Element#formula} + * parameter. + */ + private JTextField formulaText; + + /** + * {@link JList} for {@link lcsb.mapviewer.model.map.Element#synonyms} + * parameter. + */ + private JList<String> synonymsList; + + /** + * {@link JList} for + * {@link lcsb.mapviewer.model.map.Element#formerSymbols} parameter. + */ + private JList<String> formerSymbolsList; + + /** + * {@link JList} for {@link lcsb.mapviewer.model.map.Element#miriamData} + * parameter. + */ + private JList<MiriamData> miriamDataList; + + /** + * List of synonyms in {@link lcsb.mapviewer.model.map.Element#synonyms}. + * + * @see {@link #synonymsList} + */ + private DefaultListModel<String> synonymsListModel = new DefaultListModel<>(); + + /** + * List of synonyms in {@link lcsb.mapviewer.model.map.Element#formerSymbols}. + * + * @see {@link #formerSymbolsList} + */ + private DefaultListModel<String> formerSymbolsListModel = new DefaultListModel<>(); + + /** + * List of synonyms in {@link lcsb.mapviewer.model.map.Element#miriamData}. + * + * @see {@link #miriamDataList} + */ + private DefaultListModel<MiriamData> miriamDataListModel = new DefaultListModel<>(); + + /** + * {@link Alias} or {@link Reaction} that is currently selected. + */ + private Object element; + + /** + * List of listeners that should be thrown when some properties of selected + * {@link Alias} is changed. + */ + private List<ElementModifiedEventListener<Alias>> aliasListeners = new ArrayList<>(); + + /** + * List of listeners that should be thrown when some properties of selected + * {@link Reaction} is changed. + */ + private List<ElementModifiedEventListener<Reaction>> reactionListeners = new ArrayList<>(); + + /** + * This flag value is set when data in the panel is updated from newly + * selected element. + */ + private boolean updatingData = false; + + /** + * Default constructor. + */ + public ElementDetailsPanel() { + GridBagLayout gridLayout = new GridBagLayout(); + setLayout(gridLayout); + setPreferredSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH, GuiStyle.DETAIL_PANEL_HEIGHT)); + + nameLabel = new JLabel("Name: "); + idLabel = new JLabel("ID: "); + complexLabel = new JLabel("Parent complex: "); + compartmentLabel = new JLabel("Parent compartment: "); + fontSizeLabel = new JLabel("Font size: "); + colorLabel = new JLabel("Color: "); + notesLabel = new JLabel("Notes: "); + symbolLabel = new JLabel("Symbol: "); + fullNameLabel = new JLabel("Full name: "); + abbreviationLabel = new JLabel("Abbreviation: "); + formulaLabel = new JLabel("Formula: "); + synonymsLabel = new JLabel("Synonyms: "); + formerSymbolsLabel = new JLabel("Former symbols: "); + miriamDataLabel = new JLabel("Annotations: "); + + nameText = new JTextField(); + idText = new JTextField(); + idText.setEditable(false); + idText.setEnabled(false); + complexText = new JTextField(); + complexText.setEditable(false); + complexText.setEnabled(false); + compartmentText = new JTextField(); + compartmentText.setEditable(false); + compartmentText.setEnabled(false); + fontSizeText = new JTextField(); + colorButton = new JButton("Change"); + notesText = new JTextArea(); + notesText.setLineWrap(true); + notesText.setWrapStyleWord(true); + symbolText = new JTextField(); + fullNameText = new JTextField(); + abbreviationText = new JTextField(); + formulaText = new JTextField(); + synonymsList = new JList<>(synonymsListModel); + formerSymbolsList = new JList<>(formerSymbolsListModel); + miriamDataList = new JList<>(miriamDataListModel); + miriamDataList.setCellRenderer(new MiriamDataCellRender()); + + assignCommandToField(nameText, new CreateChangeNameCommand(nameText)); + assignCommandToField(fontSizeText, new CreateChangeFontSizeCommand(fontSizeText)); + assignCommandToField(notesText, new CreateChangeNotesCommand(notesText)); + assignCommandToField(symbolText, new CreateChangeSymbolCommand(symbolText)); + assignCommandToField(fullNameText, new CreateChangeFullNameCommand(fullNameText)); + assignCommandToField(abbreviationText, new CreateChangeAbbreviationCommand(abbreviationText)); + assignCommandToField(formulaText, new CreateChangeFormulaCommand(formulaText)); + assignColorCommandToField(colorButton, new CreateChangeColorCommand(colorButton)); + assignCommandToList(synonymsList, new CreateChangeSynonymCommand(synonymsList), "Synonym", String.class); + assignCommandToList(formerSymbolsList, new CreateChangeFormerSymbolCommand(formerSymbolsList), "Former symbol", String.class); + assignCommandToList(miriamDataList, new CreateChangeMiriamDataCommand(miriamDataList), "Miriam data", MiriamData.class); + } + + /** + * Creates listener that will handle changes on list parameter. It assigns + * {@link CreateListPropertyChangeCommand<T>} object that will create a proper + * {@link ModelCommand} when changes are made to the parameter field. + * + * @param list + * component where changes can be made + * @param dialogTitle + * title of the dialog used for editing property + * @param clazz + * class type of the property + * @param createCommandObject + * object that will create apropriate {@link ModelCommand} + * @param <T> + * type of the objects included in the parameter list + */ + private <T> void assignCommandToList(JList<T> list, CreateListPropertyChangeCommand<T> createCommandObject, String dialogTitle, Class<T> clazz) { + list.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + logger.debug("Mouse pressed"); + if (e.isPopupTrigger()) { + doPop(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + doPop(e); + } + } + + private void doPop(MouseEvent e) { + JPopupMenu menu = new JPopupMenu(); + JMenuItem addItem = new JMenuItem("Add"); + menu.add(addItem); + addItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ObjectEditDialog<T> editDialog = createEditDialog(dialogTitle, clazz); + editDialog.addOkListener(new ElementModifiedEventListener<T>() { + + @Override + public void actionPerformed(ElementModifiedEvent<T> e) throws CommandExecutionException { + T s = e.getElement(); + List<T> values = new ArrayList<>(); + values.add(s); + ModelCommand modelCommand = createCommandObject.createAddCommand(getModel(), (Alias) element, values); + processCommand(modelCommand); + ((DefaultListModel<T>) list.getModel()).addElement(s); + } + }); + editDialog.editObject(null); + } + + }); + if (list.getSelectedIndices().length == 1) { + JMenuItem editItem = new JMenuItem("Edit"); + menu.add(editItem); + editItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ObjectEditDialog<T> editDialog = createEditDialog(dialogTitle, clazz); + editDialog.addOkListener(new ElementModifiedEventListener<T>() { + @Override + public void actionPerformed(ElementModifiedEvent<T> e) throws CommandExecutionException { + T s = e.getElement(); + ModelCommand modelCommand = createCommandObject.createChangeCommand(getModel(), (Alias) element, s, list.getSelectedValue()); + processCommand(modelCommand); + ((DefaultListModel<T>) list.getModel()).set(list.getSelectedIndices()[0], s); + } + }); + editDialog.editObject(list.getSelectedValue()); + } + }); + } + if (list.getSelectedIndices().length > 0) { + JMenuItem removeItem = new JMenuItem("Remove"); + menu.add(removeItem); + removeItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + List<T> elements = new ArrayList<>(); + for (T string : list.getSelectedValuesList()) { + elements.add(string); + } + ModelCommand modelCommand = createCommandObject.createRemoveCommand(getModel(), (Alias) element, elements); + try { + processCommand(modelCommand); + for (T string : elements) { + ((DefaultListModel<T>) list.getModel()).removeElement(string); + } + } catch (CommandExecutionException exception) { + JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } + }); + } + menu.show(e.getComponent(), e.getX(), e.getY()); + } + }); + } + + /** + * Creates listener that will handle changes on color button parameter. It + * assigns {@link CreateListPropertyChangeCommand<T>} object that will create + * a proper {@link ModelCommand} when changes are made to the parameter field. + * + * @param colorButton + * component where changes can be made + * @param createCommandObject + * object that will create apropriate {@link ModelCommand} + */ + private void assignColorCommandToField(JButton colorButton, CreatePropertyChangeCommand createCommandObject) { + colorButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (!updatingData && element != null) { + Color newColor = JColorChooser.showDialog(ElementDetailsPanel.this, "Choose Color", colorButton.getBackground()); + if (newColor != null) { + colorButton.setBackground(newColor); + ModelCommand modelCommand = createCommandObject.createCommand(getModel(), (Alias) element); + try { + processCommand(modelCommand); + } catch (CommandExecutionException exception) { + JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } + } + } + + }); + } + + /** + * Executes parameter {@link ModelCommand} and fires appropraite listeners. + * + * @param modelCommand + * command to be executed + * @throws CommandExecutionException + * thrown when modelCommand cannot be executed due to some + * problematic input data + */ + public void processCommand(ModelCommand modelCommand) throws CommandExecutionException { + modelCommand.execute(); + if (modelCommand != null) { + if (element instanceof Alias) { + ElementModifiedEvent<Alias> event = new ElementModifiedEvent<Alias>(this, (Alias) element, modelCommand); + for (ElementModifiedEventListener<Alias> listener : aliasListeners) { + listener.actionPerformed(event); + } + } else if (element instanceof Reaction) { + ElementModifiedEvent<Reaction> event = new ElementModifiedEvent<Reaction>(this, (Reaction) element, modelCommand); + for (ElementModifiedEventListener<Reaction> listener : reactionListeners) { + listener.actionPerformed(event); + } + } else { + throw new NotImplementedException("Don't know how to handle: " + element.getClass()); + } + } + } + + /** + * Creates listener that will handle changes on {@link JTextComponent} + * parameter. It assigns {@link CreateListPropertyChangeCommand<T>} object + * that will create a proper {@link ModelCommand} when changes are made to the + * parameter field. + * + * @param field + * component where changes can be made + * @param createCommandObject + * object that will create apropriate {@link ModelCommand} + */ + private void assignCommandToField(JTextComponent field, CreatePropertyChangeCommand createCommandObject) { + field.addFocusListener(new FocusListener() { + public void focusGained(FocusEvent e) { + } + + public void focusLost(FocusEvent e) { + if (!updatingData && element != null) { + ModelCommand modelCommand = createCommandObject.createCommand(getModel(), (Alias) element); + try { + processCommand(modelCommand); + } catch (CommandExecutionException exception) { + JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } + } + }); + if (field instanceof JTextField) { + ((JTextField) field).addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (!updatingData && element != null) { + ModelCommand modelCommand = createCommandObject.createCommand(getModel(), (Alias) element); + try { + processCommand(modelCommand); + } catch (CommandExecutionException exception) { + JOptionPane.showMessageDialog(null, exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } + } + }); + } + + } + + /** + * Sets {@link #element}. + * + * @param object + * new {@link #element} value + */ + public void setElement(Object object) { + this.element = object; + + updateData(object); + } + + /** + * Updates data in the panel using parameter object as a data source. + * + * @param object + * object for which data details should be available + */ + private void updateData(Object object) { + updatingData = true; + removeAll(); + try { + if (object instanceof Alias) { + createAliasPanel((Alias) object); + } else if (object instanceof Reaction) { + createReactionPanel((Reaction) object); + } else if (object != null) { + throw new InvalidArgumentException("Cannot provide details for object: " + object); + } + validate(); + repaint(); + } finally { + updatingData = false; + } + + } + + /** + * Creates property details panel for reaction. + * + * @param object + * reaction for which panel will be created + */ + private void createReactionPanel(Reaction object) { + throw new NotImplementedException(); + + } + + /** + * Creates property details panel for alias. + * + * @param alias + * {@link Alias} for which panel will be created + */ + private void createAliasPanel(Alias alias) { + int row = 0; + add(nameLabel, createLayoutConstraints(0, row)); + add(nameText, createLayoutConstraints(1, row)); + nameText.setText(alias.getName()); + row++; + + add(idLabel, createLayoutConstraints(0, row)); + add(idText, createLayoutConstraints(1, row)); + idText.setText(alias.getAliasId()); + row++; + + add(complexLabel, createLayoutConstraints(0, row)); + add(complexText, createLayoutConstraints(1, row)); + if (alias.getParent() instanceof ComplexAlias) { + complexText.setText(alias.getParent().getAliasId()); + } else { + complexText.setText("N/A"); + } + row++; + + add(compartmentLabel, createLayoutConstraints(0, row)); + add(compartmentText, createLayoutConstraints(1, row)); + if (alias.getCompartmentAlias() instanceof CompartmentAlias) { + compartmentText.setText(alias.getCompartmentAlias().getAliasId()); + } else { + compartmentText.setText("N/A"); + } + row++; + + add(fontSizeLabel, createLayoutConstraints(0, row)); + add(fontSizeText, createLayoutConstraints(1, row)); + fontSizeText.setText(alias.getFontSize() + ""); + row++; + + add(colorLabel, createLayoutConstraints(0, row)); + add(colorButton, createLayoutConstraints(1, row)); + colorButton.setBackground(alias.getColor()); + row++; + + add(notesLabel, createLayoutConstraints(0, row)); + JScrollPane notesScrollContainer = new JScrollPane(); + notesScrollContainer.setViewportView(notesText); + notesScrollContainer.setWheelScrollingEnabled(true); + notesScrollContainer.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); + + add(notesScrollContainer, createLayoutConstraints(1, row)); + notesText.setText(alias.getNotes()); + row++; + + add(symbolLabel, createLayoutConstraints(0, row)); + add(symbolText, createLayoutConstraints(1, row)); + symbolText.setText(alias.getSymbol()); + row++; + + add(fullNameLabel, createLayoutConstraints(0, row)); + add(fullNameText, createLayoutConstraints(1, row)); + fullNameText.setText(alias.getFullName()); + row++; + + add(abbreviationLabel, createLayoutConstraints(0, row)); + add(abbreviationText, createLayoutConstraints(1, row)); + abbreviationText.setText(alias.getAbbreviation()); + row++; + + add(formulaLabel, createLayoutConstraints(0, row)); + add(formulaText, createLayoutConstraints(1, row)); + formulaText.setText(alias.getFormula()); + row++; + + add(synonymsLabel, createLayoutConstraints(0, row)); + JScrollPane synonymsScrollPane = new JScrollPane(synonymsList); + synonymsScrollPane.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); + add(synonymsScrollPane, createLayoutConstraints(1, row)); + synonymsListModel.removeAllElements(); + for (String string : alias.getSynonyms()) { + synonymsListModel.addElement(string); + } + row++; + + add(formerSymbolsLabel, createLayoutConstraints(0, row)); + JScrollPane formerSymbolsPane = new JScrollPane(formerSymbolsList); + formerSymbolsPane.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); + add(formerSymbolsPane, createLayoutConstraints(1, row)); + formerSymbolsListModel.removeAllElements(); + for (String string : alias.getFormerSymbols()) { + formerSymbolsListModel.addElement(string); + } + row++; + + add(miriamDataLabel, createLayoutConstraints(0, row)); + JScrollPane miriamDataPane = new JScrollPane(miriamDataList); + miriamDataPane.setMinimumSize(new Dimension(GuiStyle.DETAIL_PANEL_WIDTH / 2, GuiStyle.SCROLL_LIST_HEIGHT)); + add(miriamDataPane, createLayoutConstraints(1, row)); + miriamDataListModel.removeAllElements(); + for (MiriamData md : alias.getMiriamData()) { + miriamDataListModel.addElement(md); + } + row++; + + addFooterForAlignment(row++); + } + + /** + * Adds footer on bottom of the panel to make proper alignments. + * + * @param row + * row in which the last element should appear + */ + private void addFooterForAlignment(int row) { + JLabel button = new JLabel(""); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.ipady = 0; // reset to default + c.weighty = 1.0; // request any extra vertical space + c.anchor = GridBagConstraints.PAGE_END; // bottom of space + c.gridx = 1; // aligned with button 2 + c.gridwidth = 2; // 2 columns wide + c.gridy = row; // third row + add(button, c); + } + + /** + * Create constraints for element located on x,y positions in + * {@link GridBagLayout}. + * + * @param x + * column + * @param y + * row + * @return {@link GridBagConstraints} for object at specified coordinates + */ + public GridBagConstraints createLayoutConstraints(int x, int y) { + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.NORTH; + c.weightx = GRID_RATIO; + c.gridx = x; + c.gridy = y; + return c; + } + + /** + * Adds listener to be thrown when properties of the {@link #element edited + * Alias} is changing. + * + * @param e + * {@link ElementModifiedEventListener listener} to add + */ + public void addAliasModifiedEventListener(ElementModifiedEventListener<Alias> e) { + aliasListeners.add(e); + } + + /** + * Adds listener to be thrown when properties of the {@link #element edited + * Reaction} is changing. + * + * @param e + * {@link ElementModifiedEventListener listener} to add + */ + public void addReactionModifiedEventListener(ElementModifiedEventListener<Reaction> e) { + reactionListeners.add(e); + } + + /** + * Returns {@link Model} where edited element is located. + * + * @return {@link Model} where edited element is located + */ + private Model getModel() { + if (element instanceof Alias) { + return ((Alias) element).getModel(); + } else if (element instanceof Reaction) { + return ((Reaction) element).getModel(); + } else if (element != null) { + throw new InvalidStateException("Don't know how to handle object of class: " + element.getClass()); + } else { + return null; + } + } + + /** + * Created {@link ObjectEditDialog} that can edit objects of type specified in + * parameter. + * + * @param dialogTitle + * title that should be used in a dialog + * @param clazz + * class of a type of the object to edit + * @return {@link ObjectEditDialog} that can edit objects of type specified in + * parameter + * @param <T> + * type of the object to edit + */ + @SuppressWarnings("unchecked") + private <T> ObjectEditDialog<T> createEditDialog(String dialogTitle, Class<T> clazz) { + if (String.class.equals(clazz)) { + return (ObjectEditDialog<T>) new StringEditDialog(null, dialogTitle, dialogTitle); + } else if (MiriamData.class.equals(clazz)) { + return (ObjectEditDialog<T>) new MiriamDataDialog(null, dialogTitle, dialogTitle); + } else { + throw new NotImplementedException("Don't know how to handle: " + clazz); + } + } +} -- GitLab