Added open option, Added delete option for nodes, General functionality changes

This commit is contained in:
Waverunner
2014-09-09 19:35:15 -04:00
parent 54a0fd6699
commit 06c2447970
17 changed files with 496 additions and 118 deletions

4
.gitignore vendored
View File

@@ -15,4 +15,6 @@ hs_err_pid*
/build/
/ConversationEditor/build/
/dist/
/nbproject/private/
/nbproject/private/
/ConversationEditor/nbproject/private/
/ConversationCompiler/nbproject/private/

View File

@@ -45,14 +45,51 @@ public class ConversationConnectProvider implements ConnectProvider {
JOptionPane.showMessageDialog(null, "Cannot attach end conversation node to responses/options!", "Conversation Script Creator", JOptionPane.INFORMATION_MESSAGE);
return;
}
ConversationNode cSource = ((ConversationWidget) source).getAttachedNode();
ConversationNode cTarget = ((ConversationWidget) target).getAttachedNode();
if (cSource.isOption()) {
if (cTarget.isOption())
return;
else if (cTarget.isStartNode())
return;
} else if (cSource.isStartNode()) {
if (cTarget.isEndNode())
return;
} else if (cSource.isEndNode()) {
return;
} else { // Response nodes
if (cTarget.isEndNode())
return;
else if (cTarget.isStartNode())
return;
}
/* This won't work for preventing linking to same node 2x's. Need to find another way :(
if (scene.getConnectionLayer().getChildren().size() > 0) {
for (Widget widget : scene.getConnectionLayer().getChildren()) {
System.out.println("CHILD: " + widget.toString());
if (!(widget instanceof ConnectionWidget)) {
continue;
}
ConnectionWidget existingConn = (ConnectionWidget) widget;
if (existingConn.getTargetAnchor().getRelatedWidget() == target) {
System.out.println("SAME");
return;
}
}
}*/
ConnectionWidget conn = new ConnectionWidget(scene);
conn.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED);
conn.setTargetAnchor(AnchorFactory.createRectangularAnchor(target));
conn.setSourceAnchor(AnchorFactory.createRectangularAnchor(source));
scene.getConnectionLayer().addChild(conn);
((ConversationWidget)source).getAttachedNode().setCompiled(false);
((ConversationWidget)target).getAttachedNode().setCompiled(false);
}
}
}

View File

@@ -8,7 +8,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
public class ConversationNode extends AbstractNode implements Lookup.Provider {
private final int id;
private int id;
private int optionId;
private String displayText;
private String stf;
@@ -24,10 +24,10 @@ public class ConversationNode extends AbstractNode implements Lookup.Provider {
this.stf = stf;
this.option = isOption;
this.displayText = "";
this.id = id;
this.endNode = isEndNode;
this.startNode = isStartNode;
this.optionId = optionId;
this.id = id;
// Properties Window
if (!isStartNode)
@@ -76,6 +76,10 @@ public class ConversationNode extends AbstractNode implements Lookup.Provider {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isCompiled() {
return compiled;
}

View File

@@ -18,13 +18,14 @@ import org.openide.util.LookupListener;
public class ConversationWidget extends IconNodeWidget implements LookupListener {
private final ConversationNode attachedNode;
private final ExplorerManager mgr;
private boolean selected;
public ConversationWidget(SceneView scene, final ExplorerManager mgr, final ConversationNode node, boolean endConversation) {
super(scene.getScene());
this.attachedNode = node;
this.mgr = mgr;
if (node.isEndNode()) {
setLabel(node.getStf());
setImage(ImageUtilities.loadImage("com/projectswg/tools/csc/conversationeditor/conversation_end.png"));
@@ -50,10 +51,24 @@ public class ConversationWidget extends IconNodeWidget implements LookupListener
public Point locationSuggested(Widget widget, Point originalLocation, Point suggestedLocation) {
if (!(widget instanceof ConversationWidget))
return suggestedLocation;
ConversationWidget cWidget = (ConversationWidget) widget;
ConversationNode node = cWidget.getAttachedNode();
if (((ConversationWidget) widget).getAttachedNode().isLocked())
if (node.isLocked())
return originalLocation;
if (cWidget.getExpManager().getRootContext() != node) {
cWidget.getExpManager().setRootContext(node);
ConversationNode[] nodes = new ConversationNode[1];
nodes[0] = node;
try {
cWidget.getExpManager().setSelectedNodes(nodes);
} catch (PropertyVetoException ex) {
Exceptions.printStackTrace(ex);
}
}
return suggestedLocation;
}
}, ActionFactory.createDefaultMoveProvider()));
@@ -98,6 +113,14 @@ public class ConversationWidget extends IconNodeWidget implements LookupListener
return mgr;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
@Override
public void resultChanged(LookupEvent ev) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.

View File

@@ -1,30 +1,26 @@
package com.projectswg.tools.csc.conversationeditor;
import com.projectswg.tools.csc.conversationeditor.actions.SaveConversation;
import java.awt.Point;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import com.projectswg.tools.csc.conversationeditor.actions.OpenConversation;
import java.io.File;
import javax.swing.JOptionPane;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
import org.xml.sax.SAXException;
@ConvertAsProperties(
dtd = "-//com.projectswg.tools.csc.conversationeditor//Editor//EN",
autostore = false
autostore = true
)
@TopComponent.Description(
preferredID = "EditorTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE",
persistenceType = TopComponent.PERSISTENCE_ALWAYS
)
@TopComponent.Registration(mode = "editor", openAtStartup = true)
@TopComponent.Registration(mode = "editor", openAtStartup = false)
@ActionID(category = "Window", id = "com.projectswg.tools.csc.conversationeditor.EditorTopComponent")
@ActionReference(path = "Menu/Window" /*, position = 333 */)
@TopComponent.OpenActionRegistration(
@@ -40,41 +36,21 @@ public final class EditorTopComponent extends TopComponent implements ExplorerMa
private final ExplorerManager mgr = new ExplorerManager();
private final SceneView scene;
private String activePath = "";
// New Conversation
public EditorTopComponent() {
initComponents();
setToolTipText(Bundle.HINT_EditorTopComponent());
SceneView scene = new SceneView(mgr);
scrollPane.setViewportView(scene.createView());
setName(Bundle.CTL_EditorTopComponent() + " - *New Conversation*");
setName("*New Conversation*");
scene.addNode(new ConversationNode("Begin Conversation", false, 0, false, true, 0));
scene.addNode(new ConversationNode("End Conversation", false, 1, true, false, 0));
this.scene = new SceneView(mgr);
scrollPane.setViewportView(scene.createView());
associateLookup(ExplorerUtils.createLookup(mgr, getActionMap()));
this.scene = scene;
}
// Open Conversation
public EditorTopComponent(String convName) {
initComponents();
setToolTipText(Bundle.HINT_EditorTopComponent());
SceneView scene = new SceneView(mgr);
scene.setSceneName(convName);
scrollPane.setViewportView(scene.createView());
setName(Bundle.CTL_EditorTopComponent() + " - " + (scene.getSceneName().equals("") ? "*New Conversation*" : scene.getSceneName()));
associateLookup(ExplorerUtils.createLookup(mgr, getActionMap()));
this.scene = scene;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@@ -100,30 +76,40 @@ public final class EditorTopComponent extends TopComponent implements ExplorerMa
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane scrollPane;
// End of variables declaration//GEN-END:variables
@Override
public void componentOpened() {
// TODO add custom code on component opening
if (activePath.equals("")) {
// blankSlate();
// scene.validate();
return;
}
File file = new File(activePath);
if (!file.exists()) {
JOptionPane.showMessageDialog(null, "Couldn't open conversation file " + file.getAbsolutePath()
+ " because it no longer exists.", "Conversation Script Editor", JOptionPane.INFORMATION_MESSAGE);
blankSlate();
scene.validate();
} else {
OpenConversation.open(file, this);
}
}
@Override
public void componentClosed() {
/*try {
SaveConversation.save(scene);
} catch (ParserConfigurationException | IOException | SAXException | TransformerException ex) {
Exceptions.printStackTrace(ex);
}*/
// TODO: save msg
}
void writeProperties(java.util.Properties p) {
// better to version settings since initial version as advocated at
// http://wiki.apidesign.org/wiki/PropertyFiles
p.setProperty("version", "1.0");
// TODO store your settings
//p.setProperty("version", "1.0");
p.setProperty("activePath", scene.getScenePath());
}
void readProperties(java.util.Properties p) {
String version = p.getProperty("version");
// TODO read your settings according to their version
//String version = p.getProperty("version");
this.activePath = p.getProperty("activePath");
}
@Override
@@ -134,4 +120,9 @@ public final class EditorTopComponent extends TopComponent implements ExplorerMa
public SceneView getScene() {
return scene;
}
public void blankSlate() {
scene.addNode(new ConversationNode("Begin Conversation", false, 0, false, true, 0));
scene.addNode(new ConversationNode("End Conversation", false, 1, true, false, 0));
}
}

View File

@@ -3,10 +3,11 @@ package com.projectswg.tools.csc.conversationeditor;
import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.swing.SwingUtilities;
import org.netbeans.api.visual.graph.GraphScene;
import org.netbeans.api.visual.anchor.AnchorFactory;
import org.netbeans.api.visual.anchor.AnchorShape;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.Widget;
import org.w3c.dom.Attr;
@@ -27,7 +28,7 @@ public class SceneSaver {
private static final String NODEID_ATTR = "nodeID"; // NOI18N
private static final String X_NODE = "posX"; // NOI18N
private static final String Y_NODE = "posY"; // NOI18N
private static final String SOURCE = "source";
private static final String TARGETS = "targets";
private static final String LOCKED = "locked";
private static final String STF = "stf";
private static final String OPTION_ID = "optionId";
@@ -41,7 +42,8 @@ public class SceneSaver {
Node properties = file.createElement("Properties");
root.appendChild(properties);
setTextProperty(properties, file, "name", scene.getSceneName());
setTextProperty(properties, file, "zoom", Double.toString(scene.getZoomFactor()));
setTextProperty(properties, file, "highestId", String.valueOf(scene.getNextId()));
Node sceneXMLNode = file.createElement(NODE_ELEMENT);
root.appendChild(sceneXMLNode);
@@ -49,7 +51,7 @@ public class SceneSaver {
setAttribute(file, sceneXMLNode, VERSION_ATTR, VERSION_VALUE_1); // NOI18N
LinkedHashMap<ConversationNode, ArrayList<ConversationNode>> conversationLinks = scene.getConversationLinks();
for (ConversationNode node : scene.getNodes ()) {
Widget widget = scene.findWidget(node);
if (widget != null) {
@@ -66,8 +68,7 @@ public class SceneSaver {
else
setAttribute(file, dataXMLNode, TYPE, "begin");
if (!node.isStartNode())
setAttribute(file, dataXMLNode, SOURCE, String.valueOf(getSourceNode(conversationLinks, node).getId()));
setAttribute(file, dataXMLNode, TARGETS, getTargets(conversationLinks, node));
setAttribute(file, dataXMLNode, NODEID_ATTR, String.valueOf(node.getId()));
setAttribute(file, dataXMLNode, X_NODE, Integer.toString(location.x));
@@ -83,24 +84,19 @@ public class SceneSaver {
return root;
}
private ConversationNode getSourceNode(LinkedHashMap<ConversationNode, ArrayList<ConversationNode>> conversationLinks, ConversationNode lookNode) {
for (Map.Entry<ConversationNode, ArrayList<ConversationNode>> entry : conversationLinks.entrySet()) {
if (entry.getValue().contains(lookNode))
return entry.getKey();
private String getTargets(LinkedHashMap<ConversationNode, ArrayList<ConversationNode>> conversationLinks, ConversationNode source) {
String targets = "";
if (!conversationLinks.containsKey(source)) {
return targets;
}
return null;
for (ConversationNode nodes : conversationLinks.get(source)) {
targets += (targets.equals("") ? String.valueOf(nodes.getId()) : "," + String.valueOf(nodes.getId()));
}
return targets;
}
private ConversationNode getTargetNode(LinkedHashMap<ConversationNode, ArrayList<ConversationNode>> conversationLinks, ConversationNode lookNode) {
for (Map.Entry<ConversationNode, ArrayList<ConversationNode>> entry : conversationLinks.entrySet()) {
if (entry.getValue().contains(lookNode))
return entry.getValue().get(entry.getValue().indexOf(lookNode));
}
return null;
}
// Returns true if deserialization is successfull
// sceneXMLNode has to be found in the XML file first
public boolean deserializeData(final SceneView scene, final Node sceneXMLNode) {
if (!VERSION_VALUE_1.equals(getAttributeValue(sceneXMLNode, VERSION_ATTR)))
return false;
@@ -108,7 +104,7 @@ public class SceneSaver {
SwingUtilities.invokeLater (new Runnable() {
@Override
public void run() {
deserializeDataVersion1(scene, sceneXMLNode);
deserializeNodeDataVersion1(scene, sceneXMLNode);
scene.validate ();
}
});
@@ -116,19 +112,86 @@ public class SceneSaver {
return true;
}
private void deserializeDataVersion1(SceneView scene, Node data) {
public void deserializeProperties(SceneView scene, Node node) {
System.out.println("Got a node!" + node.getNodeType());
Element properties = (Element) node;
scene.setId(Integer.valueOf(properties.getElementsByTagName("highestId").item(0).getTextContent()));
}
private void deserializeNodeDataVersion1(SceneView scene, Node data) {
HashMap<Integer, ArrayList<Integer>> widgetLinks = new HashMap<>(); // map of what this widget id targets
HashMap<Integer, ConversationWidget> widgets = new HashMap<>(); // map of all loaded widget's K = id, V = widget
for (Node node : getChildNode (data)) {
if(NODE_NODE.equals(node.getNodeName())) {
String nodeID = getAttributeValue(node, NODEID_ATTR);
int nodeID = Integer.parseInt(getAttributeValue(node, NODEID_ATTR));
int x = Integer.parseInt(getAttributeValue (node, X_NODE));
int y = Integer.parseInt(getAttributeValue (node, Y_NODE));
Widget widget = scene.findWidget(nodeID);
if (widget != null)
int optionId = Integer.parseInt(getAttributeValue(node, OPTION_ID));
boolean locked = Boolean.parseBoolean(getAttributeValue(node, LOCKED));
String targets = getAttributeValue(node, TARGETS);
String stf = getAttributeValue(node, STF);
String type = getAttributeValue(node, TYPE);
ConversationWidget widget = null;
// ConversationNode(String stf, boolean isOption, int id, boolean isEndNode, boolean isStartNode, int optionId)
switch (type) {
case "option":
widget = (ConversationWidget) scene.addNode(new ConversationNode(stf, true, nodeID, false, false, optionId));
break;
case "response":
widget = (ConversationWidget) scene.addNode(new ConversationNode(stf, false, nodeID, false, false, optionId));
break;
case "begin":
widget = (ConversationWidget) scene.addNode(new ConversationNode(stf, false, nodeID, false, true, optionId));
break;
case "end":
widget = (ConversationWidget) scene.addNode(new ConversationNode(stf, false, nodeID, true, false, optionId));
break;
}
if (widget != null) {
widget.getAttachedNode().setLocked(locked);
widget.setPreferredLocation (new Point (x, y));
widgets.put(nodeID, widget);
if (!targets.equals("")) {
ArrayList<Integer> targetIds = new ArrayList<>();
if (targets.contains(",")) {
String[] split = targets.split(",");
for (String s : split) {
targetIds.add(Integer.valueOf(s));
}
} else {
targetIds.add(Integer.valueOf(targets));
}
widgetLinks.put(nodeID, targetIds);
}
}
}
}
createConnections(widgetLinks, widgets, scene);
}
private void createConnections(HashMap<Integer, ArrayList<Integer>> links, HashMap<Integer, ConversationWidget> widgets, SceneView scene) {
for (Map.Entry<Integer, ArrayList<Integer>> entry : links.entrySet()) {
//System.out.println("Creating links for " + widgets.get(entry.getKey()).getAttachedNode().getStf());
for (Integer targetId : entry.getValue()) {
ConnectionWidget conn = new ConnectionWidget(scene);
conn.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED);
conn.setTargetAnchor(AnchorFactory.createRectangularAnchor(widgets.get(targetId)));
conn.setSourceAnchor(AnchorFactory.createRectangularAnchor(widgets.get(entry.getKey())));
scene.getConnectionLayer().addChild(conn);
}
}
}
private static String getAttributeValue(Node node, String attr) {
try {
if (node != null) {
@@ -164,5 +227,5 @@ public class SceneSaver {
for (int i = 0; i < nodes.length; i++)
nodes[i] = childNodes.item (i);
return nodes;
}
}
}

View File

@@ -5,7 +5,6 @@ import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JOptionPane;
import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.graph.GraphScene;
@@ -23,6 +22,9 @@ public class SceneView extends GraphScene<ConversationNode, String>{
private final ExplorerManager mgr;
private String name = "";
private String scenePath = "";
private int id = 1;
public SceneView(ExplorerManager mgr) {
setLookFeel(new ConversationLookFeel());
@@ -44,6 +46,7 @@ public class SceneView extends GraphScene<ConversationNode, String>{
@Override
protected Widget attachNodeWidget(ConversationNode n) {
final ConversationWidget widget = new ConversationWidget(this, mgr, n, n.isEndNode());
widget.getActions().addAction(createObjectHoverAction());
@@ -106,6 +109,27 @@ public class SceneView extends GraphScene<ConversationNode, String>{
this.name = name;
}
public String getScenePath() {
return this.scenePath;
}
public void setScenePath(String path) {
this.scenePath = path;
}
public ExplorerManager getManager() {
return mgr;
}
public int getNextId() {
this.id = id +1;
return id++;
}
public void setId(int id) {
this.id = id;
}
public LinkedHashMap<ConversationNode, ArrayList<ConversationNode>> getConversationLinks() {
List<Widget> connectedNodes = connectionLayer.getChildren();
LinkedHashMap<ConversationNode, ArrayList<ConversationNode>> conversationLinks = new LinkedHashMap<>();

View File

@@ -44,7 +44,7 @@ public final class NewConvEnd implements ActionListener {
if (scene == null)
return;
int id = scene.getNodes().size();
int id = scene.getNextId();
scene.addNode(new ConversationNode("New End Conversation " + String.valueOf(id), false, id, true, false, 0));
scene.validate();

View File

@@ -39,7 +39,7 @@ public final class NewConvOption implements ActionListener {
if (scene == null)
return;
int id = scene.getNodes().size();
int id = scene.getNextId();
scene.addNode(new ConversationNode("New Conversation Option " + String.valueOf(id), true, id, false, false, 0));
scene.validate();

View File

@@ -44,7 +44,7 @@ public final class NewConvResponse implements ActionListener {
if (scene == null)
return;
int id = scene.getNodes().size();
int id = scene.getNextId();
scene.addNode(new ConversationNode("New Conversation Response " + String.valueOf(id), false, id, false, false, 0));
scene.validate();
}

View File

@@ -33,6 +33,8 @@ public final class NewConversation implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
EditorTopComponent newEditor = new EditorTopComponent();
newEditor.blankSlate();
newEditor.getScene().validate();
newEditor.open();
newEditor.requestActive();
}

View File

@@ -1,22 +1,34 @@
package com.projectswg.tools.csc.conversationeditor.actions;
import com.projectswg.tools.csc.conversationeditor.EditorTopComponent;
import com.projectswg.tools.csc.conversationeditor.SceneSaver;
import com.projectswg.tools.csc.conversationeditor.SceneView;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.filesystems.FileChooserBuilder;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@ActionID(category = "File", id = "org.mycore.OpenFileAction")
@ActionRegistration(displayName = "Open Conversation")
@ActionRegistration(displayName = "Open")
@ActionReferences({
@ActionReference(path = "Menu/File", position = 10, separatorAfter = 11),
@ActionReference(path = "Shortcuts", name = "D-O")
})
@Messages("CTL_OpenFileAction=Open Conversation")
@Messages("CTL_OpenFileAction=Open")
public final class OpenConversation implements ActionListener {
@Override
@@ -28,8 +40,50 @@ public final class OpenConversation implements ActionListener {
setDefaultWorkingDirectory(home).setApproveText("Open").showOpenDialog();
//Result will be null if the user clicked cancel or closed the dialog w/o OK
if (toAdd != null) {
// TODO:
EditorTopComponent editor = new EditorTopComponent();
open(toAdd, editor);
editor.open();
editor.requestActive();
}
}
public static void open(File openFile, EditorTopComponent editor) {
try {
if (!openFile.getName().endsWith(".xml")) {
System.out.println("Not a valid Conversation Editor file!");
return;
}
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(openFile);
doc.getDocumentElement().normalize();
if (!doc.getDocumentElement().getNodeName().equals("Conversation")) {
System.out.println("Not a valid Conversation Editor file!");
return;
}
SceneSaver saver = new SceneSaver();
SceneView scene = editor.getScene();
Node propertiesNode = doc.getElementsByTagName("Properties").item(0);
saver.deserializeProperties(scene, propertiesNode);
Node sceneNode = doc.getElementsByTagName("SceneView").item(0);
if (sceneNode == null) {
System.out.println("NULL SCENE");
return;
}
scene.setSceneName(openFile.getName().split(".xml")[0]);
scene.setScenePath(openFile.getAbsolutePath());
saver.deserializeData(scene, sceneNode);
editor.setName(scene.getSceneName());
} catch (ParserConfigurationException | SAXException | IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}

View File

@@ -12,6 +12,8 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -32,7 +34,6 @@ import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
@@ -42,14 +43,14 @@ import org.xml.sax.SAXException;
)
@ActionRegistration(
iconBase = "com/projectswg/tools/csc/conversationeditor/actions/conversation_tb_save.png",
displayName = "Save Conversation"
displayName = "Save"
)
@ActionReferences({
@ActionReference(path = "Menu/File", position = -90, separatorBefore = -140),
@ActionReference(path = "Toolbars/File", position = 500),
@ActionReference(path = "Shortcuts", name = "D-S")
})
@Messages("CTL_SaveConversation=Save Conversation")
@Messages("CTL_SaveConversation=Save")
public final class SaveConversation implements ActionListener {
@Override
@@ -58,43 +59,55 @@ public final class SaveConversation implements ActionListener {
if (component == null || !(component instanceof EditorTopComponent))
return;
EditorTopComponent editor = (EditorTopComponent) component;
final EditorTopComponent editor = (EditorTopComponent) component;
final SceneView scene = editor.getScene();
if (scene == null)
return;
if (scene.getSceneName().equals("")) {
File home = new File(System.getProperty("user.home"));
File existingFile = null;
if (!scene.getScenePath().equals(""))
existingFile = new File(scene.getScenePath());
if (existingFile == null || !existingFile.exists()) {
saveAs(scene, editor);
} else {
final String path = existingFile.getAbsolutePath();
SwingUtilities.invokeLater(new Runnable() {
FileChooserBuilder builder = new FileChooserBuilder("user-dir").setTitle("Save Conversation").setDefaultWorkingDirectory(home).setApproveText("Save");
builder.setAcceptAllFileFilterUsed(true);
final File file = builder.showSaveDialog();
if (file != null) {
scene.setSceneName(file.getName().split(".xml")[0]);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
save(scene, file.getAbsolutePath());
} catch (ParserConfigurationException | IOException | SAXException | TransformerException ex) {
Exceptions.printStackTrace(ex);
}
@Override
public void run() {
try {
handleSave(scene, editor, path);
} catch (ParserConfigurationException | IOException | SAXException | TransformerException ex) {
Exceptions.printStackTrace(ex);
}
});
editor.setName("Conversation Editor - " + scene.getSceneName());
}
}
});
}
}
public static void save(SceneView scene, String path) throws ParserConfigurationException, IOException, SAXException, TransformerConfigurationException, TransformerException {
public static void handleSave(final SceneView scene, final EditorTopComponent editor, String path)
throws ParserConfigurationException, IOException, SAXException, TransformerConfigurationException, TransformerException {
SceneSaver saver = new SceneSaver();
File xmlFile = new File(path + ".xml");
if (!xmlFile.exists())
if (!path.endsWith(".xml"))
path = path + ".xml";
File xmlFile = new File(path);
if (!scene.getScenePath().equals(path) && xmlFile.exists()) {
int result = JOptionPane.showConfirmDialog(null, "This file already exists. Do you wish to overwrite it?",
"Conversation Script Creator", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (result == JOptionPane.YES_OPTION) {
PrintWriter writer = new PrintWriter(xmlFile);
writer.print("");
writer.flush();
} else {
return;
}
}
else
xmlFile.createNewFile();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@@ -109,9 +122,38 @@ public final class SaveConversation implements ActionListener {
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(xmlFile);
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(source, result);
if (!scene.getSceneName().equals(xmlFile.getName().split(".xml")[0]))
scene.setSceneName(xmlFile.getName().split(".xml")[0]);
scene.setScenePath(xmlFile.getAbsolutePath());
editor.setName(scene.getSceneName());
}
public static void saveAs(final SceneView scene, final EditorTopComponent editor) {
File home = new File(System.getProperty("user.home"));
FileChooserBuilder builder = new FileChooserBuilder("user-dir").setTitle("Save Conversation").setDefaultWorkingDirectory(home).setApproveText("Save");
builder.setAcceptAllFileFilterUsed(true);
final File file = builder.showSaveDialog();
if (file != null) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
handleSave(scene, editor, file.getAbsolutePath());
} catch (ParserConfigurationException | IOException | SAXException | TransformerException ex) {
Exceptions.printStackTrace(ex);
}
}
});
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.projectswg.tools.csc.conversationeditor.actions;
import com.projectswg.tools.csc.conversationeditor.ConversationNode;
import com.projectswg.tools.csc.conversationeditor.ConversationWidget;
import com.projectswg.tools.csc.conversationeditor.EditorTopComponent;
import com.projectswg.tools.csc.conversationeditor.SceneView;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.SwingUtilities;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.Widget;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
@ActionID(
category = "Edit",
id = "com.projectswg.tools.csc.conversationeditor.actions.TrashConvNode"
)
@ActionRegistration(
iconBase = "com/projectswg/tools/csc/conversationeditor/actions/conversation_tb_trash.png",
displayName = "Trash Node"
)
@ActionReferences({
@ActionReference(path = "Menu/Edit", position = 1475),
@ActionReference(path = "Toolbars/Edit", position = 450),
@ActionReference(path = "Shortcuts", name = "DELETE")
})
@Messages("CTL_TrashConvNode=Trash Node")
public final class TrashConvNode implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
TopComponent component = TopComponent.getRegistry().getActivated();
if (component == null || !(component instanceof EditorTopComponent))
return;
final EditorTopComponent editor = (EditorTopComponent) component;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
trashActiveNodes(editor);
}
});
}
private static void trashActiveNodes(final EditorTopComponent editor) {
SceneView scene = editor.getScene();
if (scene == null)
return;
Node[] selectedNodes = scene.getManager().getSelectedNodes();
HashMap<ConversationWidget, ConversationNode> widgets = new HashMap<>();
// Get the nodes widgets & remove from scene
for (Node n : selectedNodes) {
ConversationWidget found = (ConversationWidget) scene.findWidget(n);
if (found == null) {
System.err.println("COULDNT FIND WIDGET TO REMOVE");
return;
}
widgets.put(found, (ConversationNode) n);
found.removeFromParent();
}
// Remove connections for the node
ArrayList<Widget> connections = new ArrayList<>();
for (Widget child : scene.getConnectionLayer().getChildren()) {
if (!(child instanceof ConnectionWidget))
continue;
ConnectionWidget connection = (ConnectionWidget) child;
if (widgets.containsKey((ConversationWidget) connection.getTargetAnchor().getRelatedWidget())) {
connections.add(child);
}
if (widgets.containsKey((ConversationWidget) connection.getSourceAnchor().getRelatedWidget())) {
connections.add(child);
}
}
scene.getConnectionLayer().removeChildren(connections);
for (Node n : selectedNodes) {
scene.removeNode((ConversationNode) n);
}
scene.validate();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -19,6 +19,18 @@
<folder name="Edit">
<file name="Separator1.instance_hidden"/>
<file name="Separator2.instance_hidden"/>
<file name="SeparatorAfterFindPrevious.instance_hidden"/>
<file name="SeparatorAfterProjectsSearch.instance_hidden"/>
<file name="WhereUsedAction.shadow_hidden"/>
<file name="clipboard-history.shadow_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$FindNextAction.instance_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$FindPreviousAction.instance_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$FindSelectionAction.instance_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$PasteFormattedAction.instance_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$SelectAllAction.instance_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$SelectIdentifierAction.instance_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$StartMacroRecordingAction.instance_hidden"/>
<file name="org-netbeans-modules-editor-MainMenuAction$StopMacroRecordingAction.instance_hidden"/>
<file name="org-netbeans-modules-search-FindInFilesAction-separatorBefore.instance_hidden"/>
<file name="org-netbeans-modules-search-FindInFilesAction.shadow_hidden"/>
<file name="org-netbeans-modules-search-ReplaceInFilesAction.shadow_hidden"/>
@@ -66,21 +78,37 @@
<file name="RunProject_hidden"/>
<file name="Source_hidden"/>
<folder name="Tools">
<file name="CloudManagerAction3.shadow_hidden"/>
<file name="LibrariesCustomizerAction.shadow_hidden"/>
<file name="PaletteManager_hidden"/>
<file name="Separator1.instance_hidden"/>
<file name="Separator2.instance_hidden"/>
<file name="ServerManagerAction3.shadow_hidden"/>
<file name="VariablesCustomizerAction.shadow_hidden"/>
<file name="org-netbeans-modules-autoupdate-ui-actions-PluginManagerAction.shadow_hidden"/>
<file name="org-netbeans-modules-options-OptionsWindowAction-separatorBefore.instance_hidden"/>
<file name="org-netbeans-modules-templates-actions-TemplatesAction.shadow_hidden"/>
<file name="org-netbeans-modules-xml-catalog-CatalogAction.shadow_hidden"/>
<file name="org-openide-actions-ToolsAction.shadow_hidden"/>
</folder>
<file name="Versioning_hidden"/>
<folder name="View">
<file name="Separator1.instance_hidden"/>
<file name="Separator2.instance_hidden"/>
<file name="Separator3.instance_hidden"/>
<file name="org-netbeans-core-actions-LogAction.shadow_hidden"/>
<file name="org-netbeans-core-multiview-EditorsAction.instance_hidden"/>
<file name="org-netbeans-core-multiview-SplitAction.instance_hidden"/>
<file name="org-netbeans-core-windows-actions-ToolbarsListAction.shadow_hidden"/>
<file name="org-netbeans-modules-editor-NbCodeFoldingAction.instance_hidden"/>
<file name="org-netbeans-modules-project-ui-SyncEditorWithViewsAction.shadow_hidden"/>
<file name="org-netbeans-modules-versioning-core-ShowTextAnnotationsAction.shadow_hidden"/>
<file name="org-netbeans-modules-versioning-ui-diff-ShowDiffSidebarAction.shadow_hidden"/>
<file name="toggle-breadcrumbs-view.shadow_hidden"/>
<file name="toggle-line-numbers.shadow_hidden"/>
<file name="toggle-lines-view.shadow_hidden"/>
<file name="toggle-non-printable-characters.shadow_hidden"/>
<file name="toggle-toolbar.shadow_hidden"/>
</folder>
<folder name="Window">
<file name="CloseAllButThisAction.shadow_hidden"/>