Files
archived-ATCS/src/com/gpl/rpg/atcontentstudio/ui/JSONCreationWizard.java
Zukero 940996aa30 Some refactoring. Replaced all "listeners" list by instances of
CopyOnWriteArrayList, to allow listeners to unregister themselves due to
an event while preventing ConcurrentModificationExceptions.
Modified all GameDataElement.elementChanged concrete implementation to
remove the backlink from the oldOne.An element pointed by an altered
element will not show the game source element in its backlink list
anymore.
2017-03-02 13:53:24 +01:00

601 lines
22 KiB
Java

package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
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.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.sprites.SpriteChooser;
import com.jidesoft.swing.JideBoxLayout;
public class JSONCreationWizard extends JDialog {
private static final long serialVersionUID = -5744628699021314026L;
public static enum DataType {
none,
actorCondition,
dialogue,
droplist,
item,
itemCategory,
npc,
quest
}
private JSONElement creation = null;
final JLabel message;
@SuppressWarnings("rawtypes")
final JComboBox dataTypeCombo;
final JTextField idField;
final JTextField nameField;
final JButton ok;
final Project proj;
public JSONCreationWizard(final Project proj, Class<? extends GameDataElement> dataClass) {
this(proj);
if (dataClass == ActorCondition.class) {
dataTypeCombo.setSelectedItem(DataType.actorCondition);
} else if (dataClass == Dialogue.class) {
dataTypeCombo.setSelectedItem(DataType.dialogue);
} else if (dataClass == Droplist.class) {
dataTypeCombo.setSelectedItem(DataType.droplist);
} else if (dataClass == Item.class) {
dataTypeCombo.setSelectedItem(DataType.item);
} else if (dataClass == ItemCategory.class) {
dataTypeCombo.setSelectedItem(DataType.itemCategory);
} else if (dataClass == NPC.class) {
dataTypeCombo.setSelectedItem(DataType.npc);
} else if (dataClass == Quest.class) {
dataTypeCombo.setSelectedItem(DataType.quest);
}
dataTypeCombo.setEnabled(false);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public JSONCreationWizard(final Project proj) {
super(ATContentStudio.frame);
this.proj = proj;
setTitle("Create Game Data Element (JSON)");
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
pane.add(new JLabel("Create a new game data element."), JideBoxLayout.FIX);
message = new JLabel("Select a data type below:");
pane.add(message, JideBoxLayout.FIX);
dataTypeCombo = new JComboBox(new DataTypeComboModel());
dataTypeCombo.setRenderer(new DataTypeComboCellRenderer());
pane.add(dataTypeCombo);
final JPanel idPane = new JPanel();
idPane.setLayout(new BorderLayout());
JLabel idLabel = new JLabel("Internal ID: ");
idPane.add(idLabel, BorderLayout.WEST);
idField = new JTextField("");
idField.setEditable(true);
idPane.add(idField, BorderLayout.CENTER);
pane.add(idPane, JideBoxLayout.FIX);
final JPanel namePane = new JPanel();
namePane.setLayout(new BorderLayout());
JLabel nameLabel = new JLabel("Display name: ");
namePane.add(nameLabel, BorderLayout.WEST);
nameField = new JTextField("");
nameField.setEditable(true);
namePane.add(nameField, BorderLayout.CENTER);
pane.add(namePane, JideBoxLayout.FIX);
final JPanel iconPane = new JPanel();
iconPane.setLayout(new BorderLayout());
final JLabel iconLabel = new JLabel("Icon: ");
iconPane.add(iconLabel, BorderLayout.WEST);
final JButton iconButton = new JButton(new ImageIcon(DefaultIcons.getActorConditionImage()));
iconPane.add(iconButton, BorderLayout.CENTER);
pane.add(iconPane, JideBoxLayout.FIX);
iconPane.setVisible(true);
dataTypeCombo.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
idPane.setVisible(true);
switch ((DataType)e.getItem()) {
case actorCondition:
iconPane.setVisible(true);
namePane.setVisible(true);
iconButton.setIcon(new ImageIcon(DefaultIcons.getActorConditionImage()));
creation = new ActorCondition();
break;
case dialogue:
iconPane.setVisible(false);
namePane.setVisible(false);
creation = new Dialogue();
break;
case droplist:
iconPane.setVisible(false);
namePane.setVisible(false);
creation = new Droplist();
break;
case item:
iconPane.setVisible(true);
namePane.setVisible(true);
creation = new Item();
iconButton.setIcon(new ImageIcon(DefaultIcons.getItemImage()));
break;
case itemCategory:
iconPane.setVisible(false);
namePane.setVisible(true);
creation = new ItemCategory();
break;
case npc:
iconPane.setVisible(true);
namePane.setVisible(true);
creation = new NPC();
iconButton.setIcon(new ImageIcon(DefaultIcons.getNPCImage()));
break;
case quest:
iconPane.setVisible(false);
namePane.setVisible(true);
creation = new Quest();
break;
default:
idPane.setVisible(false);
iconPane.setVisible(false);
namePane.setVisible(false);
creation = null;
break;
}
updateStatus();
idPane.revalidate();
namePane.revalidate();
iconPane.revalidate();
idPane.repaint();
namePane.repaint();
iconPane.repaint();
}
}
});
iconButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Spritesheet.Category cat = null;
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
cat = Spritesheet.Category.actorcondition;
break;
case dialogue:
break;
case droplist:
break;
case item:
cat = Spritesheet.Category.item;
break;
case itemCategory:
break;
case npc:
cat = Spritesheet.Category.monster;
break;
case quest:
break;
default:
break;
}
if (cat == null) return;
SpriteChooser chooser = SpriteChooser.getChooser(proj, cat);
chooser.setSelectionListener(new SpriteChooser.SelectionListener() {
@Override
public void iconSelected(String selected) {
if (selected != null) {
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
((ActorCondition)creation).icon_id = selected;
break;
case item:
((Item)creation).icon_id = selected;
break;
case npc:
((NPC)creation).icon_id = selected;
break;
case dialogue:
case droplist:
case itemCategory:
case quest:
default:
break;
}
iconButton.setIcon(new ImageIcon(proj.getImage(selected)));
iconButton.revalidate();
iconButton.repaint();
updateStatus();
}
}
});
chooser.setVisible(true);
}
});
pane.add(new JPanel(), JideBoxLayout.VARY);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton cancel = new JButton("Cancel");
buttonPane.add(cancel, JideBoxLayout.FIX);
ok = new JButton("Ok");
buttonPane.add(ok, JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
((ActorCondition)creation).display_name = nameField.getText();
break;
case item:
((Item)creation).name = nameField.getText();
break;
case npc:
((NPC)creation).name = nameField.getText();
break;
case dialogue:
case droplist:
break;
case itemCategory:
((ItemCategory)creation).name = nameField.getText();
break;
case quest:
((Quest)creation).name = nameField.getText();
break;
default:
return;
}
creation.id = idField.getText();
JSONCreationWizard.this.setVisible(false);
JSONCreationWizard.this.dispose();
creation.state = State.created;
proj.createElement(creation);
notifyCreated();
ATContentStudio.frame.selectInTree(creation);
ATContentStudio.frame.openEditor(creation);
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
creation = null;
JSONCreationWizard.this.setVisible(false);
JSONCreationWizard.this.dispose();
}
});
DocumentListener statusUpdater = new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void insertUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateStatus();
}
};
idField.getDocument().addDocumentListener(statusUpdater);
nameField.getDocument().addDocumentListener(statusUpdater);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(350,250));
idPane.setVisible(false);
iconPane.setVisible(false);
namePane.setVisible(false);
updateStatus();
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
public void updateStatus() {
boolean trouble = false;
message.setText("<html><font color=\"#00AA00\">Looks OK to me.</font></html>");
if (creation == null) {
message.setText("<html><font color=\"#FF0000\">Select a data type below:</font></html>");
trouble = true;
} else if (idField.getText() == null || idField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">Internal ID must not be empty.</font></html>");
trouble = true;
} else {
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">An actor condition must have a name.</font></html>");
trouble = true;
} else if (((ActorCondition)creation).icon_id == null) {
message.setText("<html><font color=\"#FF0000\">An actor condition must have an icon.</font></html>");
trouble = true;
} else if (proj.getActorCondition(idField.getText()) != null) {
if (proj.getActorCondition(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">An actor condition with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getActorCondition(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">An actor condition with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getActorCondition(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">An actor condition with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case item:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">An item must have a name.</font></html>");
trouble = true;
} else if (((Item)creation).icon_id == null) {
message.setText("<html><font color=\"#FF0000\">An item must have an icon.</font></html>");
trouble = true;
} else if (proj.getItem(idField.getText()) != null) {
if (proj.getItem(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">An item with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getItem(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">An item with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getItem(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">An item with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case npc:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">A NPC must have a name.</font></html>");
trouble = true;
} else if (((NPC)creation).icon_id == null) {
message.setText("<html><font color=\"#FF0000\">A NPC must have an icon.</font></html>");
trouble = true;
} else if (proj.getNPC(idField.getText()) != null) {
if (proj.getNPC(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A NPC with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getNPC(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A NPC with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getNPC(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A NPC with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case dialogue:
if (proj.getDialogue(idField.getText()) != null) {
if (proj.getDialogue(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A dialogue with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getDialogue(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A dialogue with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getDialogue(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A dialogue with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case droplist:
if (proj.getDroplist(idField.getText()) != null) {
if (proj.getDroplist(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A droplist with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getDroplist(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A droplist with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getDroplist(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A droplist with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case itemCategory:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">An item category must have a name.</font></html>");
trouble = true;
} else if (proj.getItemCategory(idField.getText()) != null) {
if (proj.getItemCategory(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">An item category with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getItemCategory(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">An item category with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getItemCategory(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">An item category with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case quest:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">A quest must have a name.</font></html>");
trouble = true;
} else if (proj.getQuest(idField.getText()) != null) {
if (proj.getQuest(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A quest with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getQuest(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A quest with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getQuest(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A quest with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
default:
break;
}
}
ok.setEnabled(!trouble);
message.revalidate();
message.repaint();
}
public static String dataTypeDesc(DataType type) {
switch (type) {
case actorCondition:
return "Actor Condition";
case dialogue:
return "Dialogue";
case droplist:
return "Droplist";
case item:
return "Item";
case itemCategory:
return "Item Category";
case npc:
return "NPC";
case quest:
return "Quest";
default:
return "Select below";
}
}
@SuppressWarnings("rawtypes")
public static class DataTypeComboModel implements ComboBoxModel {
DataType selected = DataType.none;
@Override
public int getSize() {
return DataType.values().length;
}
@Override
public Object getElementAt(int index) {
return DataType.values()[index];
}
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
@Override
public void setSelectedItem(Object anItem) {
selected = (DataType) anItem;
}
@Override
public Object getSelectedItem() {
return selected;
}
}
public static class DataTypeComboCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 5621373849299980998L;
@Override
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
((JLabel)c).setText(JSONCreationWizard.dataTypeDesc((DataType) value));
switch ((DataType)value) {
case actorCondition:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getActorConditionIcon()));
break;
case dialogue:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDialogueIcon()));
break;
case droplist:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDroplistIcon()));
break;
case item:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getItemIcon()));
break;
case itemCategory:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDroplistIcon()));
break;
case npc:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getNPCIcon()));
break;
case quest:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getQuestIcon()));
break;
default:
break;
}
}
return c;
}
}
public static interface CreationCompletedListener {
public void elementCreated(JSONElement created);
}
private List<CreationCompletedListener> listeners = new CopyOnWriteArrayList<JSONCreationWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);
}
public void notifyCreated() {
for (CreationCompletedListener l : listeners) {
l.elementCreated(creation);
}
}
}