package com.gpl.rpg.atcontentstudio.ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import javax.swing.AbstractListModel; import javax.swing.ComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JSpinner.NumberEditor; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListModel; import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.text.DefaultFormatter; import com.gpl.rpg.atcontentstudio.ATContentStudio; import com.gpl.rpg.atcontentstudio.Notification; import com.gpl.rpg.atcontentstudio.model.GameDataElement; import com.gpl.rpg.atcontentstudio.model.Project; import com.gpl.rpg.atcontentstudio.model.ProjectElementListener; import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition; import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue; import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist; import com.gpl.rpg.atcontentstudio.model.gamedata.Item; import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory; import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement; import com.gpl.rpg.atcontentstudio.model.gamedata.NPC; import com.gpl.rpg.atcontentstudio.model.gamedata.Quest; import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; import com.jidesoft.swing.ComboBoxSearchable; import com.jidesoft.swing.JideBoxLayout; public abstract class Editor extends JPanel implements ProjectElementListener { private static final long serialVersionUID = 241750514033596878L; private static final FieldUpdateListener nullListener = new FieldUpdateListener() {@Override public void valueChanged(JComponent source, Object value) {}}; public static final String SAVE = "Save"; public static final String DELETE = "Delete"; public static final String REVERT = "Revert to original"; public static final String ALTER = "Alter"; public static final String GO_TO_ALTERED = "Go to altered"; public static final String READ_ONLY_MESSAGE = "" + "This element is not modifiable.
" + "Click on the \"Alter\" button to create a writable copy." + "
"; public static final String ALTERED_EXISTS_MESSAGE = "" + "This element is not modifiable.
" + "A writable copy exists in this project. Click on \"Go to altered\" to open it." + "
"; public static final String ALTERED_MESSAGE = "" + "This element is a writable copy of an element of the referenced game source.
" + "Take care not to break existing content when modifying it." + "
"; public static final String CREATED_MESSAGE = "" + "This element is a creation of yours.
" + "Do as you please." + "
"; public String name = "Editor"; public Icon icon = null; public GameDataElement target = null; public JLabel message = null; public static JTextField addLabelField(JPanel pane, String label, String value) { return addTextField(pane, label, value, false, nullListener); } public static JTextField addTextField(JPanel pane, String label, String initialValue, boolean editable, final FieldUpdateListener listener) { JPanel tfPane = new JPanel(); tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6)); JLabel tfLabel = new JLabel(label); tfPane.add(tfLabel, JideBoxLayout.FIX); final JTextField tfField = new JTextField(initialValue); tfField.setEditable(editable); tfPane.add(tfField, JideBoxLayout.VARY); JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); tfPane.add(nullify, JideBoxLayout.FIX); nullify.setEnabled(editable); pane.add(tfPane, JideBoxLayout.FIX); nullify.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { tfField.setText(""); listener.valueChanged(tfField, null); } }); tfField.getDocument().addDocumentListener(new DocumentListener() { @Override public void removeUpdate(DocumentEvent e) { listener.valueChanged(tfField, tfField.getText()); } @Override public void insertUpdate(DocumentEvent e) { listener.valueChanged(tfField, tfField.getText()); } @Override public void changedUpdate(DocumentEvent e) { listener.valueChanged(tfField, tfField.getText()); } }); tfField.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { listener.valueChanged(tfField, tfField.getText()); } }); return tfField; } public static JTextArea addTextArea(JPanel pane, String label, String initialValue, boolean editable, final FieldUpdateListener listener) { String text= initialValue == null ? "" : initialValue.replaceAll("\\n", "\n"); JPanel tfPane = new JPanel(); tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6)); JLabel tfLabel = new JLabel(label); tfPane.add(tfLabel, JideBoxLayout.FIX); final JTextArea tfArea = new JTextArea(text); tfArea.setEditable(editable); tfPane.add(new JScrollPane(tfArea), JideBoxLayout.VARY); JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); tfPane.add(nullify, JideBoxLayout.FIX); nullify.setEnabled(editable); pane.add(tfPane, JideBoxLayout.FIX); nullify.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { tfArea.setText(""); listener.valueChanged(tfArea, null); } }); tfArea.getDocument().addDocumentListener(new DocumentListener() { @Override public void removeUpdate(DocumentEvent e) { listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", Matcher.quoteReplacement("\n"))); } @Override public void insertUpdate(DocumentEvent e) { listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", Matcher.quoteReplacement("\n"))); } @Override public void changedUpdate(DocumentEvent e) { listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", Matcher.quoteReplacement("\n"))); } }); // tfArea.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // listener.valueChanged(tfArea, tfArea.getText().replaceAll("\n", "\\n")); // } // }); return tfArea; } // public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, boolean allowNegatives, boolean editable) { // return addIntegerField(pane, label, initialValue, allowNegatives, editable, nullListener); // } public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, boolean allowNegatives, boolean editable, final FieldUpdateListener listener) { JPanel tfPane = new JPanel(); tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6)); JLabel tfLabel = new JLabel(label); tfPane.add(tfLabel, JideBoxLayout.FIX); final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.intValue() : 0, allowNegatives ? Integer.MIN_VALUE : 0, Integer.MAX_VALUE, 1)); ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT); spinner.setEnabled(editable); ((DefaultFormatter)((NumberEditor)spinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true); tfPane.add(spinner, JideBoxLayout.VARY); JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); tfPane.add(nullify, JideBoxLayout.FIX); nullify.setEnabled(editable); pane.add(tfPane, JideBoxLayout.FIX); spinner.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { listener.valueChanged(spinner, spinner.getValue()); } }); nullify.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { spinner.setValue(0); listener.valueChanged(spinner, null); } }); return spinner; } // public static JSpinner addDoubleField(JPanel pane, String label, Double initialValue, boolean editable) { // return addDoubleField(pane, label, initialValue, editable, nullListener); // } public static JSpinner addDoubleField(JPanel pane, String label, Double initialValue, boolean editable, final FieldUpdateListener listener) { JPanel tfPane = new JPanel(); tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6)); JLabel tfLabel = new JLabel(label); tfPane.add(tfLabel, JideBoxLayout.FIX); final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.doubleValue() : 0.0d, 0.0d, new Float(Float.MAX_VALUE).doubleValue(), 1.0d)); ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT); spinner.setEnabled(editable); ((DefaultFormatter)((NumberEditor)spinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true); tfPane.add(spinner, JideBoxLayout.VARY); JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); tfPane.add(nullify, JideBoxLayout.FIX); nullify.setEnabled(editable); pane.add(tfPane, JideBoxLayout.FIX); pane.add(tfPane, JideBoxLayout.FIX); spinner.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { listener.valueChanged(spinner, spinner.getValue()); } }); nullify.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { spinner.setValue(0.0d); listener.valueChanged(spinner, null); } }); return spinner; } public static IntegerBasedCheckBox addIntegerBasedCheckBox(JPanel pane, String label, Integer initialValue, boolean editable) { return addIntegerBasedCheckBox(pane, label, initialValue, editable, nullListener); } public static IntegerBasedCheckBox addIntegerBasedCheckBox(JPanel pane, String label, Integer initialValue, boolean editable, final FieldUpdateListener listener) { JPanel ibcbPane = new JPanel(); ibcbPane.setLayout(new BorderLayout()); final IntegerBasedCheckBox ibcb = new IntegerBasedCheckBox(); ibcb.setText(label); ibcb.setIntegerValue(initialValue); ibcb.setEnabled(editable); ibcbPane.add(ibcb, BorderLayout.WEST); ibcbPane.add(new JPanel(), BorderLayout.CENTER); pane.add(ibcbPane, JideBoxLayout.FIX); ibcb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { listener.valueChanged(ibcb, ibcb.getIntegerValue()); } }); return ibcb; } public static BooleanBasedCheckBox addBooleanBasedCheckBox(JPanel pane, String label, Boolean initialValue, boolean editable, final FieldUpdateListener listener) { JPanel bbcbPane = new JPanel(); bbcbPane.setLayout(new BorderLayout()); final BooleanBasedCheckBox bbcb = new BooleanBasedCheckBox(); bbcb.setText(label); bbcb.setBooleanValue(initialValue); bbcb.setEnabled(editable); bbcbPane.add(bbcb, BorderLayout.WEST); bbcbPane.add(new JPanel(), BorderLayout.CENTER); pane.add(bbcbPane, JideBoxLayout.FIX); bbcb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { listener.valueChanged(bbcb, bbcb.isSelected()); } }); return bbcb; } public static JComboBox addEnumValueBox(JPanel pane, String label, @SuppressWarnings("rawtypes") Enum[] values, @SuppressWarnings("rawtypes") Enum initialValue, boolean writable) { return addEnumValueBox(pane, label, values, initialValue, writable, new FieldUpdateListener() {@Override public void valueChanged(JComponent source, Object value) {}}); } public static JComboBox addEnumValueBox(JPanel pane, String label, @SuppressWarnings("rawtypes") Enum[] values, @SuppressWarnings("rawtypes") Enum initialValue, boolean writable, final FieldUpdateListener listener) { JPanel comboPane = new JPanel(); comboPane.setLayout(new JideBoxLayout(comboPane, JideBoxLayout.LINE_AXIS, 6)); JLabel comboLabel = new JLabel(label); comboPane.add(comboLabel, JideBoxLayout.FIX); final JComboBox enumValuesCombo = new JComboBox(values); enumValuesCombo.setEnabled(writable); enumValuesCombo.setSelectedItem(initialValue); comboPane.add(enumValuesCombo, JideBoxLayout.VARY); enumValuesCombo.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { listener.valueChanged(enumValuesCombo, e.getItem()); } } }); JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); comboPane.add(nullify, JideBoxLayout.FIX); nullify.setEnabled(writable); nullify.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { enumValuesCombo.setSelectedItem(null); listener.valueChanged(enumValuesCombo, null); } }); pane.add(comboPane, JideBoxLayout.FIX); return enumValuesCombo; } public MyComboBox addNPCBox(JPanel pane, Project proj, String label, NPC npc, boolean writable, FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, npc){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getNPC(index); } @Override public int getSize() { return project.getNPCCount()+1; } }; return addGDEBox(pane, label, npc, NPC.class, comboModel, writable, listener); } public MyComboBox addActorConditionBox(JPanel pane, Project proj, String label, ActorCondition acond, boolean writable, FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, acond){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getActorCondition(index); } @Override public int getSize() { return project.getActorConditionCount()+1; } }; return addGDEBox(pane, label, acond, ActorCondition.class, comboModel, writable, listener); } public MyComboBox addItemBox(JPanel pane, Project proj, String label, Item item, boolean writable, FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, item){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getItem(index); } @Override public int getSize() { return project.getItemCount()+1; } }; return addGDEBox(pane, label, item, Item.class, comboModel, writable, listener); } public MyComboBox addItemCategoryBox(JPanel pane, Project proj, String label, ItemCategory ic, boolean writable, FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, ic){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getItemCategory(index); } @Override public int getSize() { return project.getItemCategoryCount()+1; } }; return addGDEBox(pane, label, ic, ItemCategory.class, comboModel, writable, listener); } public MyComboBox addQuestBox(JPanel pane, Project proj, String label, Quest quest, boolean writable, FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, quest){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getQuest(index); } @Override public int getSize() { return project.getQuestCount()+1; } }; return addGDEBox(pane, label, quest, Quest.class, comboModel, writable, listener); } public MyComboBox addDroplistBox(JPanel pane, Project proj, String label, Droplist droplist, boolean writable, FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, droplist){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getDroplist(index); } @Override public int getSize() { return project.getDroplistCount()+1; } }; return addGDEBox(pane, label, droplist, Droplist.class, comboModel, writable, listener); } public MyComboBox addDialogueBox(JPanel pane, Project proj, String label, Dialogue dialogue, boolean writable, final FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, dialogue){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getDialogue(index); } @Override public int getSize() { return project.getDialogueCount()+1; } }; return addGDEBox(pane, label, dialogue, Dialogue.class, comboModel, writable, listener); } public MyComboBox addMapBox(JPanel pane, Project proj, String label, TMXMap map, boolean writable, final FieldUpdateListener listener) { final GDEComboModel comboModel = new GDEComboModel(proj, map){ private static final long serialVersionUID = 2638082961277241764L; @Override public Object getTypedElementAt(int index) { return project.getMap(index); } @Override public int getSize() { return project.getMapCount()+1; } }; return addGDEBox(pane, label, map, TMXMap.class, comboModel, writable, listener); } public MyComboBox addGDEBox(JPanel pane, String label, GameDataElement gde, final Class dataClass, final GDEComboModel comboModel, final boolean writable, final FieldUpdateListener listener) { JPanel gdePane = new JPanel(); gdePane.setLayout(new JideBoxLayout(gdePane, JideBoxLayout.LINE_AXIS, 6)); JLabel gdeLabel = new JLabel(label); gdePane.add(gdeLabel, JideBoxLayout.FIX); final MyComboBox gdeBox = new MyComboBox(dataClass, comboModel); gdeBox.setRenderer(new GDERenderer(false, writable)); new ComboBoxSearchable(gdeBox){ @Override protected String convertElementToString(Object object) { if (object == null) return "none"; else return ((GameDataElement)object).getDesc(); } }; gdeBox.setEnabled(writable); gdePane.add(gdeBox, JideBoxLayout.VARY); final JButton goToGde = new JButton((Icon) ((gde != null) ? new ImageIcon(gde.getIcon()) : (writable ? new ImageIcon(DefaultIcons.getCreateIcon()) : null))); goToGde.setEnabled(gde != null || writable); goToGde.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { GameDataElement selected = ((GameDataElement)comboModel.getSelectedItem()); if (selected != null) { ATContentStudio.frame.openEditor(((GameDataElement)comboModel.getSelectedItem())); ATContentStudio.frame.selectInTree((GameDataElement)comboModel.getSelectedItem()); } else if (writable) { JSONCreationWizard wizard = new JSONCreationWizard(((GameDataElement)target).getProject(), dataClass); wizard.addCreationListener(new JSONCreationWizard.CreationCompletedListener() { @Override public void elementCreated(JSONElement created) { gdeBox.setSelectedItem(created); } }); wizard.setVisible(true); } } }); gdePane.add(goToGde, JideBoxLayout.FIX); gdeBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (gdeBox.getModel().getSelectedItem() == null) { goToGde.setIcon((writable ? new ImageIcon(DefaultIcons.getCreateIcon()) : null)); goToGde.setEnabled(writable); } else { goToGde.setIcon(new ImageIcon(((GameDataElement)comboModel.getSelectedItem()).getIcon())); goToGde.setEnabled(true); } listener.valueChanged(gdeBox, gdeBox.getModel().getSelectedItem()); } }); JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon())); gdePane.add(nullify, JideBoxLayout.FIX); nullify.setEnabled(writable); nullify.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { gdeBox.setSelectedItem(null); } }); pane.add(gdePane, JideBoxLayout.FIX); return gdeBox; } public JList addBacklinksList(JPanel pane, GameDataElement gde) { final JList list = new JList(new GDEBacklinksListModel(gde)); list.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { ATContentStudio.frame.openEditor((GameDataElement)list.getSelectedValue()); ATContentStudio.frame.selectInTree((GameDataElement)list.getSelectedValue()); } } }); list.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { ATContentStudio.frame.openEditor((GameDataElement)list.getSelectedValue()); ATContentStudio.frame.selectInTree((GameDataElement)list.getSelectedValue()); } } }); list.setCellRenderer(new GDERenderer(true, false)); CollapsiblePanel colPane = new CollapsiblePanel("Elements linking to this one"); colPane.setLayout(new JideBoxLayout(colPane, JideBoxLayout.PAGE_AXIS)); colPane.add(new JScrollPane(list), JideBoxLayout.FIX); colPane.add(new JPanel(), JideBoxLayout.FIX); if (gde.getBacklinks() == null || gde.getBacklinks().isEmpty()) { colPane.collapse(); } pane.add(colPane, JideBoxLayout.FIX); return list; } public static abstract class GDEComboModel extends AbstractListModel implements ComboBoxModel { private static final long serialVersionUID = -5854574666510314715L; public Project project; public E selected; public GDEComboModel(Project proj, E initial) { this.project = proj; this.selected = initial; } @Override public abstract int getSize(); @Override public Object getElementAt(int index) { if (index == 0) { return null; } return getTypedElementAt(index - 1); } public abstract Object getTypedElementAt(int index); @SuppressWarnings("unchecked") @Override public void setSelectedItem(Object anItem) { selected = (E) anItem; } @Override public Object getSelectedItem() { return selected; } public void itemAdded(E item, int index) { fireIntervalAdded(this, index, index); } public void itemRemoved(E item, int index) { fireIntervalRemoved(this, index, index); } } public static class GDERenderer extends DefaultListCellRenderer { private static final long serialVersionUID = 6819681566800482793L; private boolean includeType = false; private boolean writable = false; public GDERenderer(boolean includeType, boolean writable) { super(); this.includeType = includeType; this.writable = writable; } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value == null) { label.setText("None"+(writable ? ". Click on the button to create one." : "")); } else { if (includeType && ((GameDataElement)value).getDataType() != null) { label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc()); } else { label.setText(((GameDataElement)value).getDesc()); } if (((GameDataElement)value).getIcon() == null) { Notification.addError("Unable to find icon for "+((GameDataElement)value).getDesc()); } else { label.setIcon(new ImageIcon(((GameDataElement)value).getIcon())); } } return label; } } public static class GDEBacklinksListModel implements ListModel { GameDataElement source; public GDEBacklinksListModel(GameDataElement source) { super(); this.source = source; source.addBacklinkListener(new GameDataElement.BacklinksListener() { @Override public void backlinkRemoved(GameDataElement gde) { fireListChanged(); } @Override public void backlinkAdded(GameDataElement gde) { fireListChanged(); } }); } @Override public int getSize() { return source.getBacklinks().size(); } @Override public Object getElementAt(int index) { for (GameDataElement gde : source.getBacklinks()) { if (index == 0) return gde; index --; } return null; } List listeners = new ArrayList(); @Override public void addListDataListener(ListDataListener l) { listeners.add(l); } @Override public void removeListDataListener(ListDataListener l) { listeners.remove(l); } public void fireListChanged() { for (ListDataListener l : listeners) { l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, this.getSize())); } } } public class MyComboBox extends JComboBox implements ProjectElementListener { private static final long serialVersionUID = -4184228604170642567L; Class dataType; public MyComboBox(Class dataType, ComboBoxModel model) { super(model); this.dataType = dataType; Editor.this.addElementListener(dataType, this); } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void elementAdded(GameDataElement added, int index) { ((GDEComboModel)getModel()).itemAdded(added, index); } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void elementRemoved(GameDataElement removed, int index) { ((GDEComboModel)getModel()).itemRemoved(removed, index); } @Override public Class getDataType() { return dataType; } } public abstract void targetUpdated(); transient Map, List> projectElementListeners = new HashMap, List>(); public void addElementListener(Class interestingType, ProjectElementListener listener) { if (projectElementListeners.get(interestingType) == null) { projectElementListeners.put(interestingType, new ArrayList()); target.getProject().addElementListener(interestingType, this); } projectElementListeners.get(interestingType).add(listener); } public void removeElementListener(ProjectElementListener listener) { if (listener == null) return; if (projectElementListeners.get(listener.getDataType()) != null) { projectElementListeners.get(listener.getDataType()).remove(listener); if (projectElementListeners.get(listener.getDataType()).isEmpty()) { target.getProject().removeElementListener(listener.getDataType(), this); projectElementListeners.remove(listener.getDataType()); } } } public void elementAdded(GameDataElement element, int index) { if (projectElementListeners.get(element.getClass()) != null) { for (ProjectElementListener l : projectElementListeners.get(element.getClass())) { l.elementAdded(element, index); } } } public void elementRemoved(GameDataElement element, int index) { if (projectElementListeners.get(element.getClass()) != null) { for (ProjectElementListener l : projectElementListeners.get(element.getClass())) { l.elementRemoved(element, index); } } } public void clearElementListeners() { for (Class type : projectElementListeners.keySet()) { target.getProject().removeElementListener(type, this); } } public Class getDataType() { return null; } }