mirror of
https://github.com/AndorsTrailRelease/ATCS.git
synced 2025-10-27 18:44:03 +01:00
First drafts of "Writer Mode".
Some bug fixes.
This commit is contained in:
@@ -5,10 +5,14 @@ import java.awt.Toolkit;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.File;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
|
||||
import prefuse.data.expression.parser.ExpressionParser;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.model.Workspace;
|
||||
import com.gpl.rpg.atcontentstudio.ui.StudioFrame;
|
||||
import com.gpl.rpg.atcontentstudio.ui.WorkerDialog;
|
||||
@@ -30,6 +34,8 @@ public class ATContentStudio {
|
||||
|
||||
ConfigCache.init();
|
||||
|
||||
Logger.getLogger(ExpressionParser.class.getName()).setLevel(Level.OFF);
|
||||
|
||||
try {
|
||||
String laf = ConfigCache.getFavoriteLaFClassName();
|
||||
if (laf == null) laf = UIManager.getSystemLookAndFeelClassName();
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.gpl.rpg.atcontentstudio.model.maps.Worldmap;
|
||||
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
|
||||
import com.gpl.rpg.atcontentstudio.model.sprites.SpriteSheetSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
public class GameSource implements ProjectTreeNode, Serializable {
|
||||
@@ -44,6 +45,7 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
public transient TMXMapSet gameMaps;
|
||||
public transient SpriteSheetSet gameSprites;
|
||||
public transient Worldmap worldmap;
|
||||
public transient WriterModeDataSet writerModeDataSet;
|
||||
private transient SavedSlotCollection v;
|
||||
|
||||
public static enum Type {
|
||||
@@ -86,6 +88,9 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
readResourceList();
|
||||
}
|
||||
}
|
||||
if (type == Type.created) {
|
||||
this.writerModeDataSet = new WriterModeDataSet(this);
|
||||
}
|
||||
this.gameData = new GameDataSet(this);
|
||||
this.gameMaps = new TMXMapSet(this);
|
||||
this.gameSprites = new SpriteSheetSet(this);
|
||||
@@ -95,6 +100,9 @@ public class GameSource implements ProjectTreeNode, Serializable {
|
||||
v.add(gameMaps);
|
||||
v.add(gameSprites);
|
||||
v.add(worldmap);
|
||||
if (type == Type.created) {
|
||||
v.add(writerModeDataSet);
|
||||
}
|
||||
}
|
||||
|
||||
public void readResourceList() {
|
||||
|
||||
@@ -247,7 +247,7 @@ public class Dialogue extends JSONElement {
|
||||
case spawnAll:
|
||||
case removeSpawnArea:
|
||||
case deactivateSpawnArea:
|
||||
reward.map = proj.getMap(reward.map_name);
|
||||
reward.map = reward.map_name != null ? proj.getMap(reward.map_name) : null;
|
||||
break;
|
||||
case actorCondition:
|
||||
reward.reward_obj = proj.getActorCondition(reward.reward_obj_id);
|
||||
@@ -315,6 +315,11 @@ public class Dialogue extends JSONElement {
|
||||
if (rclone.reward_obj != null) {
|
||||
rclone.reward_obj.addBacklink(clone);
|
||||
}
|
||||
rclone.map = r.map;
|
||||
rclone.map_name = r.map_name;
|
||||
if (rclone.map != null) {
|
||||
rclone.map.addBacklink(clone);
|
||||
}
|
||||
clone.rewards.add(rclone);
|
||||
}
|
||||
}
|
||||
|
||||
251
src/com/gpl/rpg/atcontentstudio/model/tools/WriterModeData.java
Normal file
251
src/com/gpl/rpg/atcontentstudio/model/tools/WriterModeData.java
Normal file
@@ -0,0 +1,251 @@
|
||||
package com.gpl.rpg.atcontentstudio.model.tools;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
|
||||
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeData.WriterDialogue;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
public class WriterModeData extends GameDataElement {
|
||||
|
||||
public WriterModeDataSet parent;
|
||||
|
||||
public Image npcIcon;
|
||||
public WriterDialogue begin;
|
||||
public Map<String, WriterDialogue> dialogueThreads = new LinkedHashMap<String, WriterDialogue>();
|
||||
public Map<String, Integer> threadsNextIndex = new LinkedHashMap<String, Integer>();
|
||||
|
||||
|
||||
public WriterModeData(WriterModeDataSet parent, String id_prefix){
|
||||
this.parent = parent;
|
||||
this.begin = new WriterDialogue();
|
||||
begin.id_prefix = id_prefix;
|
||||
begin.index = getNextIndex(id_prefix);
|
||||
begin.text = "";
|
||||
}
|
||||
|
||||
public WriterModeData(WriterModeDataSet parent, Map jsonObj) {
|
||||
this.parent = parent;
|
||||
this.begin = new WriterDialogue(jsonObj);
|
||||
this.state = State.parsed;
|
||||
}
|
||||
|
||||
public int getNextIndex(String id_prefix) {
|
||||
Integer index = threadsNextIndex.get(id_prefix);
|
||||
if (index == null) index = 0;
|
||||
while (getProject().getDialogue(id_prefix+index) != null) {
|
||||
index++;
|
||||
}
|
||||
threadsNextIndex.put(id_prefix, index + 1);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
public abstract class WriterNode {
|
||||
public String text;
|
||||
|
||||
public abstract String getTitle();
|
||||
public abstract Map toJson();
|
||||
|
||||
}
|
||||
|
||||
public class WriterDialogue extends WriterNode {
|
||||
public String id_prefix;
|
||||
public int index;
|
||||
public List<WriterReply> replies = new LinkedList<WriterReply>();
|
||||
|
||||
|
||||
public WriterDialogue() {}
|
||||
|
||||
public WriterDialogue(String id_prefix) {
|
||||
text = "";
|
||||
this.id_prefix = id_prefix;
|
||||
index = getNextIndex(id_prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Dialogue "+id_prefix+index;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map dialogueJson = new HashMap();
|
||||
dialogueJson.put("id_prefix", id_prefix);
|
||||
dialogueJson.put("index", index);
|
||||
dialogueJson.put("text", text);
|
||||
if (!replies.isEmpty()) {
|
||||
List repliesJson = new ArrayList();
|
||||
for (WriterReply reply : replies) {
|
||||
repliesJson.add(reply.toJson());
|
||||
}
|
||||
dialogueJson.put("replies", repliesJson);
|
||||
}
|
||||
return dialogueJson;
|
||||
}
|
||||
|
||||
public WriterDialogue(Map json) {
|
||||
this.index = Integer.parseInt((String) json.get("index"));
|
||||
this.id_prefix = (String) json.get("id_prefix");
|
||||
this.text = (String) json.get("text");
|
||||
List repliesJson = (List) json.get("replies");
|
||||
for (Object rJson : repliesJson) {
|
||||
this.replies.add(new WriterReply(this, (Map)rJson));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SpecialDialogue extends WriterDialogue {}
|
||||
public class SelectorDialogue extends SpecialDialogue {}
|
||||
public class ShopDialogue extends SpecialDialogue {}
|
||||
public class FightDialogue extends SpecialDialogue {}
|
||||
public class EndDialogue extends SpecialDialogue {}
|
||||
|
||||
public class WriterReply extends WriterNode {
|
||||
public WriterDialogue parent;
|
||||
public WriterDialogue next_dialogue;
|
||||
|
||||
public WriterReply() {}
|
||||
|
||||
public WriterReply(WriterDialogue parent) {
|
||||
this.parent = parent;
|
||||
this.text = "";
|
||||
parent.replies.add(this);
|
||||
}
|
||||
|
||||
public WriterReply(WriterDialogue parent, Map json) {
|
||||
this.parent = parent;
|
||||
this.text = (String) json.get("text");
|
||||
if (json.containsKey("next_dialogue")) {
|
||||
next_dialogue = new WriterDialogue((Map) json.get("next_dialogue"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Reply in "+parent.id_prefix+parent.index;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Map toJson() {
|
||||
Map replyJson = new HashMap();
|
||||
replyJson.put("text", text);
|
||||
if (next_dialogue != null) {
|
||||
replyJson.put("next_dialogue", next_dialogue.toJson());
|
||||
}
|
||||
return replyJson;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SpecialReply extends WriterReply {
|
||||
|
||||
public SpecialReply(WriterDialogue parent) {
|
||||
super(parent);
|
||||
}
|
||||
}
|
||||
public class EmptyReply extends SpecialReply {
|
||||
|
||||
public EmptyReply(WriterDialogue parent) {
|
||||
super(parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return (this.state == State.modified ? "*" : "")+begin.id_prefix;
|
||||
}
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return parent.getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getIcon() {
|
||||
return DefaultIcons.getDialogueIcon();
|
||||
}
|
||||
@Override
|
||||
public Image getOpenIcon() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Image getClosedIcon() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Image getLeafIcon() {
|
||||
return getIcon();
|
||||
}
|
||||
@Override
|
||||
public GameDataSet getDataSet() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void parse() {
|
||||
// TODO
|
||||
|
||||
}
|
||||
@Override
|
||||
public void link() {
|
||||
//Useless here.
|
||||
}
|
||||
@Override
|
||||
public GameDataElement clone() {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
|
||||
// Useless here.
|
||||
|
||||
}
|
||||
@Override
|
||||
public String getProjectFilename() {
|
||||
return WriterModeDataSet.DEFAULT_REL_PATH_IN_PROJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
parent.save();
|
||||
}
|
||||
@Override
|
||||
public List<SaveEvent> attemptSave() {
|
||||
List<SaveEvent> events = parent.attemptSave();
|
||||
if (events == null || events.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (events.size() == 1 && events.get(0).type == SaveEvent.Type.alsoSave && events.get(0).target == this) {
|
||||
save();
|
||||
return null;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Map toJson() {
|
||||
return begin.toJson();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package com.gpl.rpg.atcontentstudio.model.tools;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.Notification;
|
||||
import com.gpl.rpg.atcontentstudio.io.JsonPrettyWriter;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameSource.Type;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.Project;
|
||||
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
|
||||
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
public class WriterModeDataSet implements ProjectTreeNode, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5434504851883441971L;
|
||||
public static final String DEFAULT_REL_PATH_IN_PROJECT = "writer.json";
|
||||
|
||||
|
||||
public GameSource parent;
|
||||
public File writerFile;
|
||||
|
||||
List<WriterModeData> writerModeDataList = new LinkedList<WriterModeData>();
|
||||
|
||||
public WriterModeDataSet(GameSource gameSource) {
|
||||
this.parent = gameSource;
|
||||
writerFile = new File(parent.baseFolder, DEFAULT_REL_PATH_IN_PROJECT);
|
||||
parse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getChildAt(int childIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return writerModeDataList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex(TreeNode node) {
|
||||
return writerModeDataList.indexOf(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllowsChildren() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeaf() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration children() {
|
||||
return Collections.enumeration(writerModeDataList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenAdded(List<ProjectTreeNode> path) {
|
||||
path.add(0,this);
|
||||
parent.childrenAdded(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenChanged(List<ProjectTreeNode> path) {
|
||||
path.add(0,this);
|
||||
parent.childrenChanged(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenRemoved(List<ProjectTreeNode> path) {
|
||||
path.add(0,this);
|
||||
parent.childrenRemoved(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyCreated() {
|
||||
childrenAdded(new ArrayList<ProjectTreeNode>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDesc() {
|
||||
return "Dialogue sketchs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return parent.getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameDataSet getDataSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getIcon() {
|
||||
return DefaultIcons.getStdClosedIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getOpenIcon() {
|
||||
return DefaultIcons.getStdOpenIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getClosedIcon() {
|
||||
return DefaultIcons.getStdClosedIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getLeafIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getDataType() {
|
||||
return parent.getDataType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return writerModeDataList.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void save() {
|
||||
List<Map> dataToSave = new LinkedList<Map>();
|
||||
for (WriterModeData data : writerModeDataList) {
|
||||
dataToSave.add(data.toJson());
|
||||
}
|
||||
if (dataToSave.isEmpty() && writerFile.exists()) {
|
||||
if (writerFile.delete()) {
|
||||
Notification.addSuccess("File "+writerFile.getAbsolutePath()+" deleted.");
|
||||
} else {
|
||||
Notification.addError("Error deleting file "+writerFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
StringWriter writer = new JsonPrettyWriter();
|
||||
try {
|
||||
JSONArray.writeJSONString(dataToSave, writer);
|
||||
} catch (IOException e) {
|
||||
//Impossible with a StringWriter
|
||||
}
|
||||
String toWrite = writer.toString();
|
||||
try {
|
||||
FileWriter w = new FileWriter(writerFile);
|
||||
w.write(toWrite);
|
||||
w.close();
|
||||
for (WriterModeData element : writerModeDataList) {
|
||||
element.state = GameDataElement.State.saved;
|
||||
}
|
||||
Notification.addSuccess("Json file "+writerFile.getAbsolutePath()+" saved.");
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error while writing json file "+writerFile.getAbsolutePath()+" : "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public List<SaveEvent> attemptSave() {
|
||||
List<SaveEvent> events = new LinkedList<SaveEvent>();
|
||||
for (WriterModeData data : writerModeDataList) {
|
||||
if (data.state == State.created || data.state == State.modified) {
|
||||
events.add(new SaveEvent(SaveEvent.Type.alsoSave, data));
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public void parse() {
|
||||
if (!writerFile.exists()) return;
|
||||
JSONParser parser = new JSONParser();
|
||||
FileReader reader = null;
|
||||
try {
|
||||
reader = new FileReader(writerFile);
|
||||
List writerDataListJson = (List) parser.parse(reader);
|
||||
for (Object obj : writerDataListJson) {
|
||||
Map jsonObj = (Map)obj;
|
||||
writerModeDataList.add(new WriterModeData(this, jsonObj));
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Notification.addError("Error while parsing JSON file "+writerFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
Notification.addError("Error while parsing JSON file "+writerFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (ParseException e) {
|
||||
Notification.addError("Error while parsing JSON file "+writerFile.getAbsolutePath()+": "+e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (reader != null)
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -236,6 +236,15 @@ public class ProjectsTree extends JPanel {
|
||||
addNextSeparator = false;
|
||||
}
|
||||
|
||||
if (actions.testWriter.isEnabled()) {
|
||||
addNextSeparator = true;
|
||||
popupMenu.add(new JMenuItem(actions.testWriter));
|
||||
}
|
||||
if (addNextSeparator) {
|
||||
popupMenu.add(new JSeparator());
|
||||
addNextSeparator = false;
|
||||
}
|
||||
|
||||
if (konamiCodeEntered) {
|
||||
JMenuItem openTrainer = new JMenuItem("Start Andor's Trainer...");
|
||||
popupMenu.add(openTrainer);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.gpl.rpg.atcontentstudio.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
@@ -15,6 +17,7 @@ import java.util.Set;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.tree.TreePath;
|
||||
@@ -34,9 +37,11 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
|
||||
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.saves.SavedGamesSet;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeData;
|
||||
import com.gpl.rpg.atcontentstudio.ui.tools.BeanShellView;
|
||||
import com.gpl.rpg.atcontentstudio.ui.tools.ItemsTableView;
|
||||
import com.gpl.rpg.atcontentstudio.ui.tools.NPCsTableView;
|
||||
import com.gpl.rpg.atcontentstudio.ui.tools.writermode.WriterModeEditor;
|
||||
|
||||
public class WorkspaceActions {
|
||||
|
||||
@@ -314,6 +319,20 @@ public class WorkspaceActions {
|
||||
};
|
||||
};
|
||||
|
||||
public ATCSAction testWriter = new ATCSAction("Create dialogue sketch", "Test the Writer Mode"){
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (selectedNode == null || selectedNode.getProject() == null) return;
|
||||
WriterModeData data = new WriterModeData(selectedNode.getProject().createdContent.writerModeDataSet, "test_");
|
||||
JFrame frame = new JFrame("Writer Mode tests");
|
||||
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
frame.getContentPane().setLayout(new BorderLayout());
|
||||
frame.getContentPane().add(new WriterModeEditor(data), BorderLayout.CENTER);
|
||||
frame.setMinimumSize(new Dimension(250, 200));
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
};
|
||||
};
|
||||
|
||||
List<ATCSAction> actions = new ArrayList<WorkspaceActions.ATCSAction>();
|
||||
|
||||
public WorkspaceActions() {
|
||||
@@ -331,6 +350,7 @@ public class WorkspaceActions {
|
||||
actions.add(exportProject);
|
||||
actions.add(showAbout);
|
||||
actions.add(exitATCS);
|
||||
actions.add(testWriter);
|
||||
selectionChanged(null, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -109,15 +109,43 @@ public class DialogueEditor extends JSONElementEditor {
|
||||
private JSpinner requirementValue;
|
||||
private BooleanBasedCheckBox requirementNegated;
|
||||
|
||||
private DialogueGraphView dialogueGraphView;
|
||||
|
||||
|
||||
public DialogueEditor(Dialogue dialogue) {
|
||||
super(dialogue, dialogue.getDesc(), dialogue.getIcon());
|
||||
addEditorTab(form_view_id, getFormView());
|
||||
addEditorTab(json_view_id, getJSONView());
|
||||
JPanel pane = new JPanel();
|
||||
addEditorTab(graph_view_id, createDialogueGraphView(dialogue));
|
||||
}
|
||||
|
||||
public JPanel createDialogueGraphView(final Dialogue dialogue) {
|
||||
final JPanel pane = new JPanel();
|
||||
pane.setLayout(new BorderLayout());
|
||||
pane.add(new JScrollPane(new DialogueGraphView(dialogue, null)), BorderLayout.CENTER);
|
||||
addEditorTab(graph_view_id, pane);
|
||||
|
||||
dialogueGraphView = new DialogueGraphView(dialogue, null);
|
||||
pane.add(dialogueGraphView, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonPane = new JPanel();
|
||||
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS));
|
||||
JButton reloadButton = new JButton("Refresh graph");
|
||||
buttonPane.add(reloadButton, JideBoxLayout.FIX);
|
||||
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
|
||||
pane.add(buttonPane, BorderLayout.NORTH);
|
||||
|
||||
|
||||
reloadButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
pane.remove(dialogueGraphView);
|
||||
dialogueGraphView = new DialogueGraphView(dialogue, null);
|
||||
pane.add(dialogueGraphView, BorderLayout.CENTER);
|
||||
pane.revalidate();
|
||||
pane.repaint();
|
||||
}
|
||||
});
|
||||
|
||||
return pane;
|
||||
}
|
||||
|
||||
public void insertFormViewDataField(final JPanel pane) {
|
||||
|
||||
@@ -65,6 +65,15 @@ public abstract class JSONElementEditor extends Editor {
|
||||
editorTabs.put(id, editor);
|
||||
}
|
||||
|
||||
public void removeEditorTab(String id) {
|
||||
if (id == null) return;
|
||||
for (int i =0; i <editorTabsHolder.getTabCount(); i++) {
|
||||
if (id.equals(editorTabsHolder.getTitleAt(i))) {
|
||||
editorTabsHolder.removeTabAt(i);
|
||||
editorTabs.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
public JPanel getJSONView() {
|
||||
jsonEditorPane = new RSyntaxTextArea();
|
||||
jsonEditorPane.setText(((JSONElement)target).toJsonString());
|
||||
|
||||
@@ -47,6 +47,7 @@ public class NPCEditor extends JSONElementEditor {
|
||||
|
||||
private static final String form_view_id = "Form";
|
||||
private static final String json_view_id = "JSON";
|
||||
private static final String dialogue_tree_id = "Dialogue Tree";
|
||||
|
||||
private NPC.TimedConditionEffect selectedHitEffectSourceCondition;
|
||||
private NPC.TimedConditionEffect selectedHitEffectTargetCondition;
|
||||
@@ -96,15 +97,62 @@ public class NPCEditor extends JSONElementEditor {
|
||||
private JSpinner targetConditionDuration;
|
||||
private JSpinner targetConditionChance;
|
||||
|
||||
private JPanel dialogueGraphPane;
|
||||
private DialogueGraphView dialogueGraphView;
|
||||
|
||||
public NPCEditor(NPC npc) {
|
||||
super(npc, npc.getDesc(), npc.getIcon());
|
||||
addEditorTab(form_view_id, getFormView());
|
||||
addEditorTab(json_view_id, getJSONView());
|
||||
if (npc.dialogue != null) {
|
||||
JPanel pane = new JPanel();
|
||||
pane.setLayout(new BorderLayout());
|
||||
pane.add(new JScrollPane(new DialogueGraphView(npc.dialogue, npc)), BorderLayout.CENTER);
|
||||
addEditorTab("Dialogue Tree", pane);
|
||||
createDialogueGraphView(npc);
|
||||
addEditorTab(dialogue_tree_id, dialogueGraphPane);
|
||||
}
|
||||
}
|
||||
|
||||
public JPanel createDialogueGraphView(final NPC npc) {
|
||||
dialogueGraphPane = new JPanel();
|
||||
dialogueGraphPane.setLayout(new BorderLayout());
|
||||
|
||||
dialogueGraphView = new DialogueGraphView(npc.dialogue, npc);
|
||||
dialogueGraphPane.add(dialogueGraphView, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonPane = new JPanel();
|
||||
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS));
|
||||
JButton reloadButton = new JButton("Refresh graph");
|
||||
buttonPane.add(reloadButton, JideBoxLayout.FIX);
|
||||
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
|
||||
dialogueGraphPane.add(buttonPane, BorderLayout.NORTH);
|
||||
|
||||
|
||||
reloadButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
reloadGraphView(npc);
|
||||
}
|
||||
});
|
||||
|
||||
return dialogueGraphPane;
|
||||
}
|
||||
|
||||
public void reloadGraphView(NPC npc) {
|
||||
if (npc.dialogue != null) {
|
||||
if (dialogueGraphPane != null) {
|
||||
dialogueGraphPane.remove(dialogueGraphView);
|
||||
dialogueGraphView = new DialogueGraphView(npc.dialogue, npc);
|
||||
dialogueGraphPane.add(dialogueGraphView, BorderLayout.CENTER);
|
||||
dialogueGraphPane.revalidate();
|
||||
dialogueGraphPane.repaint();
|
||||
} else {
|
||||
createDialogueGraphView(npc);
|
||||
addEditorTab(dialogue_tree_id, dialogueGraphPane);
|
||||
}
|
||||
} else {
|
||||
if (dialogueGraphPane != null) {
|
||||
removeEditorTab(dialogue_tree_id);
|
||||
dialogueGraphPane = null;
|
||||
dialogueGraphView = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,6 +535,7 @@ public class NPCEditor extends JSONElementEditor {
|
||||
} else {
|
||||
npc.dialogue_id = null;
|
||||
}
|
||||
reloadGraphView(npc);
|
||||
} else if (source == droplistBox) {
|
||||
if (npc.droplist != null) {
|
||||
npc.droplist.removeBacklink(npc);
|
||||
|
||||
@@ -17,7 +17,6 @@ import javax.swing.JTable;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
@@ -25,8 +24,6 @@ import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import org.fife.ui.rtextarea.ColorBackgroundPainterStrategy;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.ATContentStudio;
|
||||
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
|
||||
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
|
||||
@@ -70,8 +67,8 @@ public class QuestEditor extends JSONElementEditor {
|
||||
createButtonPane(pane, quest.getProject(), quest, Quest.class, quest.getImage(), null, listener);
|
||||
|
||||
|
||||
addTextField(pane, "Internal ID: ", quest.id, quest.writable, listener);
|
||||
addTextField(pane, "Quest Name: ", quest.name, quest.writable, listener);
|
||||
idField = addTextField(pane, "Internal ID: ", quest.id, quest.writable, listener);
|
||||
nameField = addTextField(pane, "Quest Name: ", quest.name, quest.writable, listener);
|
||||
visibleBox = addIntegerBasedCheckBox(pane, "Visible in quest log", quest.visible_in_log, quest.writable, listener);
|
||||
|
||||
JPanel stagesPane = new JPanel();
|
||||
|
||||
@@ -2,8 +2,6 @@ package com.gpl.rpg.atcontentstudio.ui.gamedataeditors.dialoguetree;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -55,7 +53,6 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
|
||||
import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DialogueEditor;
|
||||
import com.gpl.rpg.atcontentstudio.ui.map.TMXMapEditor.TMXReplacementViewer;
|
||||
import com.jidesoft.swing.JideBoxLayout;
|
||||
|
||||
public class DialogueGraphView extends Display {
|
||||
@@ -66,7 +63,6 @@ public class DialogueGraphView extends Display {
|
||||
public static final String NODES = "graph.nodes";
|
||||
public static final String EDGES = "graph.edges";
|
||||
public static final String EDGES_LABELS = "edgesLabels";
|
||||
public static final String AGGR = "aggregates";
|
||||
|
||||
public static final String LABEL = "label";
|
||||
public static final String ICON = "icon";
|
||||
|
||||
@@ -0,0 +1,921 @@
|
||||
package com.gpl.rpg.atcontentstudio.ui.tools.writermode;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
|
||||
import prefuse.Display;
|
||||
import prefuse.Visualization;
|
||||
import prefuse.action.Action;
|
||||
import prefuse.action.ActionList;
|
||||
import prefuse.action.RepaintAction;
|
||||
import prefuse.action.assignment.ColorAction;
|
||||
import prefuse.action.assignment.FontAction;
|
||||
import prefuse.action.assignment.StrokeAction;
|
||||
import prefuse.action.layout.graph.NodeLinkTreeLayout;
|
||||
import prefuse.activity.Activity;
|
||||
import prefuse.controls.ControlAdapter;
|
||||
import prefuse.controls.PanControl;
|
||||
import prefuse.controls.WheelZoomControl;
|
||||
import prefuse.controls.ZoomControl;
|
||||
import prefuse.data.Edge;
|
||||
import prefuse.data.FilteredSpanningTree;
|
||||
import prefuse.data.Graph;
|
||||
import prefuse.data.Node;
|
||||
import prefuse.data.Schema;
|
||||
import prefuse.data.SpanningTree;
|
||||
import prefuse.data.Tree;
|
||||
import prefuse.data.expression.BooleanLiteral;
|
||||
import prefuse.data.expression.ColumnExpression;
|
||||
import prefuse.render.DefaultRendererFactory;
|
||||
import prefuse.render.EdgeRenderer;
|
||||
import prefuse.render.LabelRenderer;
|
||||
import prefuse.render.NullRenderer;
|
||||
import prefuse.util.ColorLib;
|
||||
import prefuse.util.PrefuseLib;
|
||||
import prefuse.visual.VisualItem;
|
||||
import prefuse.visual.expression.InGroupPredicate;
|
||||
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeData;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeData.EmptyReply;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeData.WriterDialogue;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeData.WriterNode;
|
||||
import com.gpl.rpg.atcontentstudio.model.tools.WriterModeData.WriterReply;
|
||||
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
|
||||
|
||||
public class WriterModeEditor extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = -6591631891278528494L;
|
||||
|
||||
private JComponent overlay = null;
|
||||
private Display view;
|
||||
|
||||
private WriterModeData data;
|
||||
private WriterNode selected = null;
|
||||
private WriterNode prevSelected = null;
|
||||
|
||||
public WriterModeEditor(WriterModeData data) {
|
||||
this.data = data;
|
||||
selected = data.begin;
|
||||
view = new WriterGraphView();
|
||||
view.setLocation(0, 0);
|
||||
setLayout(new BorderLayout());
|
||||
add(view, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private void disposeOverlay() {
|
||||
if (overlay != null) view.remove(overlay);
|
||||
overlay = null;
|
||||
view.requestFocus();
|
||||
view.revalidate();
|
||||
}
|
||||
|
||||
|
||||
public static final String GRAPH = "graph";
|
||||
public static final String NODES = "graph.nodes";
|
||||
public static final String NULL_NODES = "graph.nullNodes";
|
||||
public static final String EDGES = "graph.edges";
|
||||
public static final String EDGES_LABELS = "edgesLabels";
|
||||
|
||||
public static final String LABEL = "label";
|
||||
public static final String ICON = "icon";
|
||||
public static final String TARGET = "target";
|
||||
|
||||
public static final String IS_REPLY = "reply";
|
||||
public static final String THREAD_START = "threadStart";
|
||||
public static final String SELECTED = "selected";
|
||||
public static final String IS_TREE_EDGE = "isTreeEdge";
|
||||
|
||||
private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema();
|
||||
|
||||
private class WriterGraphView extends Display {
|
||||
private static final long serialVersionUID = -7992763190713052045L;
|
||||
|
||||
private MyGraph graph;
|
||||
private Map<WriterModeData.WriterNode, Node> cells = new HashMap<WriterModeData.WriterNode, Node>();
|
||||
|
||||
private Node nullNode = null;
|
||||
private Edge pendingEdge = null;
|
||||
private boolean edgePending = false;
|
||||
|
||||
public WriterGraphView() {
|
||||
super(new Visualization());
|
||||
loadGraph();
|
||||
nullNode = graph.addNode();
|
||||
nullNode.setBoolean(NULL_NODES, true);
|
||||
|
||||
// add visual data groups
|
||||
m_vis.addGraph(GRAPH, graph);
|
||||
m_vis.setInteractive(EDGES, null, false);
|
||||
|
||||
LabelRenderer nodeR = new MyLabelRenderer(LABEL);
|
||||
nodeR.setHorizontalTextAlignment(prefuse.Constants.LEFT);
|
||||
|
||||
EdgeRenderer edgeR = new EdgeRenderer(prefuse.Constants.EDGE_TYPE_LINE, prefuse.Constants.EDGE_ARROW_FORWARD);
|
||||
|
||||
LabelRenderer edgeLabelR = new LabelRenderer(LABEL);
|
||||
edgeLabelR.setRenderType(LabelRenderer.RENDER_TYPE_DRAW);
|
||||
|
||||
DefaultRendererFactory drf = new DefaultRendererFactory();
|
||||
drf.setDefaultRenderer(nodeR);
|
||||
drf.setDefaultEdgeRenderer(edgeR);
|
||||
drf.add(new InGroupPredicate(EDGES_LABELS), edgeLabelR);
|
||||
drf.add(new ColumnExpression(NULL_NODES), new NullRenderer());
|
||||
m_vis.setRendererFactory(drf);
|
||||
DECORATOR_SCHEMA.setDefault(VisualItem.FILLCOLOR, ColorLib.gray(255));
|
||||
DECORATOR_SCHEMA.setDefault(VisualItem.STROKECOLOR, ColorLib.rgba(0, 0, 0, 0));
|
||||
DECORATOR_SCHEMA.setDefault(VisualItem.TEXTCOLOR, ColorLib.gray(0));
|
||||
m_vis.addDecorators(EDGES_LABELS, EDGES, DECORATOR_SCHEMA);
|
||||
|
||||
// set up the visual operators
|
||||
// first set up all the color actions
|
||||
ColorAction nStrokeColor = new NodeStrokeColorAction(NODES, VisualItem.STROKECOLOR);
|
||||
// nStrokeColor.setDefaultColor(ColorLib.gray(100));
|
||||
// nStrokeColor.add("_hover", ColorLib.rgb(255,100,100));
|
||||
StrokeAction nStroke = new StrokeAction(NODES);
|
||||
|
||||
ColorAction nFill = new ColorAction(NODES, VisualItem.FILLCOLOR);
|
||||
nFill.setDefaultColor(ColorLib.gray(255));
|
||||
// ColorAction nFill = new NPCPhraseColorAction(NODES, VisualItem.FILLCOLOR);
|
||||
//
|
||||
ColorAction eEdges = new ColorAction(EDGES, VisualItem.STROKECOLOR);
|
||||
eEdges.setDefaultColor(ColorLib.gray(100));
|
||||
ColorAction eArrows = new ColorAction(EDGES, VisualItem.FILLCOLOR);
|
||||
eArrows.setDefaultColor(ColorLib.gray(100));
|
||||
// ColorAction eEdgesLabels = new ConnectedEdgeColorAction(EDGES_LABELS, VisualItem.TEXTCOLOR);
|
||||
|
||||
// StrokeAction eStroke = new EdgesStrokeAction(EDGES);
|
||||
|
||||
FontAction aFont = new FontAction();
|
||||
ColorAction aFontColor = new ColorAction(NODES, VisualItem.TEXTCOLOR);
|
||||
aFontColor.setDefaultColor(ColorLib.rgb(0, 0, 0));
|
||||
|
||||
// bundle the color actions
|
||||
ActionList colors = new ActionList(Activity.INFINITY);
|
||||
colors.add(nStrokeColor);
|
||||
colors.add(nFill);
|
||||
colors.add(nStroke);
|
||||
colors.add(eEdges);
|
||||
colors.add(eArrows);
|
||||
// colors.add(eEdgesLabels);
|
||||
// colors.add(eStroke);
|
||||
colors.add(aFont);
|
||||
colors.add(aFontColor);
|
||||
colors.add(new RepaintAction());
|
||||
m_vis.putAction("colors", colors);
|
||||
|
||||
// now create the main layout routine
|
||||
ActionList layout = new ActionList();//Activity.INFINITY);
|
||||
NodeLinkTreeLayout treeLayout = new NodeLinkTreeLayout(GRAPH, prefuse.Constants.ORIENT_LEFT_RIGHT, 120, 40, 40);
|
||||
treeLayout.setLayoutAnchor(new Point2D.Double(25,300));
|
||||
layout.add(treeLayout);
|
||||
// layout.add(new EdgesLabelDecoratorLayout(EDGES_LABELS));
|
||||
layout.add(new RepaintAction());
|
||||
m_vis.putAction("layout", layout);
|
||||
|
||||
ActionList scrollToSelectedList = new ActionList();
|
||||
Action scrollToSelected = new ScrollToSelectedAction(false);
|
||||
scrollToSelectedList.add(scrollToSelected);
|
||||
m_vis.putAction("scrollToSelected", scrollToSelectedList);
|
||||
|
||||
|
||||
ActionList scrollToSelectedAndEditList = new ActionList();
|
||||
Action scrollToSelectedAndEdit = new ScrollToSelectedAction(true);
|
||||
scrollToSelectedAndEditList.add(scrollToSelectedAndEdit);
|
||||
m_vis.putAction("scrollToSelectedAndEdit", scrollToSelectedAndEditList);
|
||||
|
||||
|
||||
// set up the display
|
||||
setSize(500,500);
|
||||
pan(250, 250);
|
||||
setHighQuality(true);
|
||||
// addControlListener(new TooltipControl());
|
||||
addControlListener(new GraphInputControl());
|
||||
addControlListener(new WheelZoomControl());
|
||||
addControlListener(new ZoomControl());
|
||||
addControlListener(new PanControl());
|
||||
|
||||
// set things running
|
||||
m_vis.run("colors");
|
||||
m_vis.run("layout");
|
||||
m_vis.run("scrollToSelected");
|
||||
|
||||
setFocusTraversalKeysEnabled(false);
|
||||
}
|
||||
|
||||
public void loadGraph() {
|
||||
graph = new MyGraph(true, IS_TREE_EDGE);
|
||||
|
||||
graph.addColumn(LABEL, String.class, "");
|
||||
graph.addColumn(ICON, Image.class, DefaultIcons.getNullifyIcon());
|
||||
graph.addColumn(TARGET, WriterModeData.WriterNode.class, null);
|
||||
|
||||
graph.addColumn(IS_REPLY, boolean.class, false);
|
||||
graph.addColumn(THREAD_START, boolean.class, false);
|
||||
graph.addColumn(SELECTED, boolean.class, false);
|
||||
graph.addColumn(IS_TREE_EDGE, boolean.class, true);
|
||||
graph.addColumn(NULL_NODES, boolean.class, false);
|
||||
|
||||
if (data != null && data.begin != null) {
|
||||
selected = data.begin;
|
||||
addDialogueNode(data.begin);
|
||||
}
|
||||
}
|
||||
|
||||
public Node addDialogueNode(WriterModeData.WriterDialogue dialogue) {
|
||||
if (cells.get(dialogue) == null) {
|
||||
Node dNode = graph.addNode();
|
||||
cells.put(dialogue, dNode);
|
||||
dNode.setString(LABEL, dialogue.text);
|
||||
dNode.set(TARGET, dialogue);
|
||||
|
||||
if (dialogue.index == 0) {
|
||||
dNode.setBoolean(THREAD_START, true);
|
||||
}
|
||||
|
||||
Node rNode;
|
||||
int i = 1;
|
||||
for (WriterModeData.WriterReply reply : dialogue.replies) {
|
||||
if (reply instanceof EmptyReply && reply.next_dialogue != null) {
|
||||
if (cells.get(reply.next_dialogue) == null) {
|
||||
rNode = addDialogueNode(reply.next_dialogue);
|
||||
Edge e = graph.addEdge(dNode, rNode);
|
||||
} else {
|
||||
rNode = cells.get(reply.next_dialogue);
|
||||
Edge e = graph.addEdge(dNode, rNode);
|
||||
e.setBoolean(IS_TREE_EDGE, false);
|
||||
}
|
||||
} else {
|
||||
if (cells.get(reply) == null) {
|
||||
rNode = addReplyNode(reply);
|
||||
Edge e = graph.addEdge(dNode, rNode);
|
||||
// e.setString(LABEL, "#"+i++);
|
||||
} else {
|
||||
rNode = cells.get(reply);
|
||||
Edge e = graph.addEdge(dNode, rNode);
|
||||
e.setBoolean(IS_TREE_EDGE, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cells.get(dialogue);
|
||||
}
|
||||
|
||||
public Node addReplyNode(WriterModeData.WriterReply reply) {
|
||||
if (cells.get(reply) == null) {
|
||||
Node rNode = graph.addNode();
|
||||
rNode.setBoolean(IS_REPLY, true);
|
||||
cells.put(reply, rNode);
|
||||
if (reply.text != null) {
|
||||
rNode.setString(LABEL, reply.text);
|
||||
rNode.set(TARGET, reply);
|
||||
|
||||
if (reply.next_dialogue != null) {
|
||||
if (cells.get(reply.next_dialogue) == null) {
|
||||
Node dNode = addDialogueNode(reply.next_dialogue);
|
||||
Edge e = graph.addEdge(rNode, dNode);
|
||||
} else {
|
||||
Node dNode = cells.get(reply.next_dialogue);
|
||||
Edge e = graph.addEdge(rNode, dNode);
|
||||
e.setBoolean(IS_TREE_EDGE, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cells.get(reply);
|
||||
}
|
||||
|
||||
|
||||
class MyLabelRenderer extends LabelRenderer {
|
||||
public MyLabelRenderer(String label) {
|
||||
super(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Image getImage(VisualItem item) {
|
||||
return item.getBoolean(IS_REPLY) ? DefaultIcons.getHeroIcon() : DefaultIcons.getNPCIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getText(VisualItem item) {
|
||||
return wordWrap(super.getText(item), 40);
|
||||
}
|
||||
|
||||
public String wordWrap(String in, int length) {
|
||||
final String newline = "\n";
|
||||
//:: Trim
|
||||
while(in.length() > 0 && (in.charAt(0) == '\t' || in.charAt(0) == ' ')) in = in.substring(1);
|
||||
//:: If Small Enough Already, Return Original
|
||||
if(in.length() < length) return in;
|
||||
//:: If Next length Contains Newline, Split There
|
||||
if(in.substring(0, length).contains(newline)) return in.substring(0, in.indexOf(newline)).trim() + newline + wordWrap(in.substring(in.indexOf("\n") + 1), length);
|
||||
//:: Otherwise, Split Along Nearest Previous Space/Tab/Dash
|
||||
int spaceIndex = Math.max(Math.max( in.lastIndexOf(" ", length), in.lastIndexOf("\t", length)), in.lastIndexOf("-", length));
|
||||
//:: If No Nearest Space, Split At length
|
||||
if(spaceIndex == -1) spaceIndex = length;
|
||||
//:: Split
|
||||
return in.substring(0, spaceIndex).trim() + newline + wordWrap(in.substring(spaceIndex), length);
|
||||
}
|
||||
}
|
||||
|
||||
class NodeStrokeColorAction extends ColorAction {
|
||||
|
||||
final int defaultColor = ColorLib.gray(100);
|
||||
final int hoverColor = ColorLib.rgb(255,100,100);
|
||||
final int selectedColor = ColorLib.rgb(100,100,255);
|
||||
|
||||
public NodeStrokeColorAction(String group, String field) {
|
||||
super(group, field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor(VisualItem item) {
|
||||
if (item.get(TARGET) != null && item.get(TARGET) == selected) {
|
||||
return selectedColor;
|
||||
}
|
||||
if (item.isHover()) {
|
||||
return hoverColor;
|
||||
}
|
||||
return defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
class GraphInputControl extends ControlAdapter {
|
||||
@Override
|
||||
public void itemClicked(VisualItem item, MouseEvent e) {
|
||||
if (!edgePending) {
|
||||
if (e.getClickCount() == 1) {
|
||||
if (item.get(TARGET) != null) {
|
||||
prevSelected = selected;
|
||||
selected = (WriterModeData.WriterNode)item.get(TARGET);
|
||||
}
|
||||
} else if (e.getClickCount() == 2) {
|
||||
if (item.get(TARGET) != null) {
|
||||
|
||||
showEditorOnSelectedAt(e.getPoint());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
selected = null;
|
||||
view.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if (edgePending && e.getKeyCode() == KeyEvent.VK_SHIFT) {
|
||||
stopPendingEdge();
|
||||
}
|
||||
KeyStroke event = KeyStroke.getKeyStrokeForEvent(e);
|
||||
if (event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true))) {
|
||||
selectAndScroll(nextNodeUp(selected));
|
||||
} else if (event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true))) {
|
||||
selectAndScroll(nextNodeDown(selected));
|
||||
} else if (event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true)) || event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK, true))) {
|
||||
selectAndScroll(nextNodeLeft(selected));
|
||||
} else if (event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true)) || event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0, true))) {
|
||||
selectAndScroll(nextNodeRight(selected));
|
||||
} else if (event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true))) {
|
||||
showEditorOnSelected();
|
||||
} else if (event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.ALT_DOWN_MASK, true))) {
|
||||
createNextDefaultNode.actionPerformed(null);
|
||||
} else if (event.equals(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_DOWN_MASK, true))) {
|
||||
createContinueTalkingNode.actionPerformed(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void itemKeyReleased(VisualItem item, KeyEvent e) {
|
||||
keyReleased(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (selected != null && e.getKeyCode() == KeyEvent.VK_SHIFT) {
|
||||
startPendingEdge();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void itemKeyPressed(VisualItem item, KeyEvent e) {
|
||||
keyPressed(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (edgePending) {
|
||||
Point p = e.getPoint();
|
||||
Point2D p2 = getAbsoluteCoordinate(p, null);
|
||||
m_vis.getVisualItem(NODES, nullNode).setX(p2.getX());
|
||||
m_vis.getVisualItem(NODES, nullNode).setY(p2.getY());
|
||||
m_vis.run("colors");
|
||||
revalidate();
|
||||
repaint();
|
||||
disposeOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void itemMoved(VisualItem item, MouseEvent e) {
|
||||
mouseMoved(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void startPendingEdge() {
|
||||
pendingEdge = graph.addEdge(cells.get(selected), nullNode);
|
||||
edgePending = true;
|
||||
m_vis.run("colors");
|
||||
m_vis.run("layout");
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public void stopPendingEdge() {
|
||||
graph.removeEdge(pendingEdge);
|
||||
pendingEdge = null;
|
||||
edgePending = false;
|
||||
m_vis.run("colors");
|
||||
m_vis.run("layout");
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
static final String disposeEditorString = "disposeEditor";
|
||||
final AbstractAction disposeEditor = new AbstractAction("Dispose Editor") {
|
||||
private static final long serialVersionUID = 6640035253411399809L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
disposeOverlay();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static final String commitEditAndDisposeEditorString = "commitEditAndDisposeEditor";
|
||||
final AbstractAction commitEditAndDisposeEditor = new AbstractAction("Commit Edit") {
|
||||
private static final long serialVersionUID = 8039766217709796328L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (area == null) return;
|
||||
selected.text = area.getText();
|
||||
cells.get(selected).set(LABEL, selected.text);
|
||||
m_vis.run("colors");
|
||||
revalidate();
|
||||
repaint();
|
||||
disposeOverlay();
|
||||
}
|
||||
};
|
||||
|
||||
private void commitAreaText() {
|
||||
selected.text = area.getText();
|
||||
cells.get(selected).set(LABEL, selected.text);
|
||||
}
|
||||
|
||||
static final String createNextDefaultNodeString = "createNextDefaultNode";
|
||||
final AbstractAction createNextDefaultNode = new AbstractAction("Create next default") {
|
||||
private static final long serialVersionUID = 1658086056088672748L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
WriterNode newWrNode = null;
|
||||
Node newNode = null;
|
||||
if (selected instanceof WriterDialogue) {
|
||||
newWrNode = data.new WriterReply((WriterDialogue) selected);
|
||||
newNode = addReplyNode(((WriterReply)newWrNode));
|
||||
} else if (selected instanceof WriterReply) {
|
||||
if (((WriterReply)selected).next_dialogue != null) {
|
||||
newWrNode = ((WriterReply)selected).next_dialogue;
|
||||
newNode = cells.get(newWrNode);
|
||||
} else {
|
||||
newWrNode = data.new WriterDialogue(((WriterReply)selected).parent.id_prefix);
|
||||
((WriterReply)selected).next_dialogue = ((WriterDialogue)newWrNode);
|
||||
newNode = addDialogueNode(((WriterDialogue)newWrNode));
|
||||
}
|
||||
}
|
||||
Edge edge = graph.addEdge(cells.get(selected), newNode);
|
||||
setSelected(newWrNode);
|
||||
|
||||
m_vis.run("colors");
|
||||
m_vis.run("layout");
|
||||
m_vis.run("scrollToSelectedAndEdit");
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
};
|
||||
|
||||
static final String commitAndCreateNextDefaultNodeString = "commitAndCreateNextDefaultNode";
|
||||
final AbstractAction commitAndCreateNextDefaultNode = new AbstractAction("Commit And Create next default") {
|
||||
private static final long serialVersionUID = 1658086056088672748L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
commitAreaText();
|
||||
createNextDefaultNode.actionPerformed(e);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static final String createContinueTalkingNodeString = "createContinueTalkingNode";
|
||||
final AbstractAction createContinueTalkingNode = new AbstractAction("Create next phrase without reply") {
|
||||
private static final long serialVersionUID = 1658086056088672748L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
commitAreaText();
|
||||
WriterDialogue newWrNode = null;
|
||||
Node newNode = null;
|
||||
if (selected instanceof WriterDialogue) {
|
||||
EmptyReply temp = data.new EmptyReply((WriterDialogue) selected);
|
||||
newWrNode = data.new WriterDialogue(((WriterDialogue) selected).id_prefix);
|
||||
temp.next_dialogue = newWrNode;
|
||||
|
||||
newNode = addDialogueNode(newWrNode);
|
||||
Edge edge = graph.addEdge(cells.get(selected), newNode);
|
||||
setSelected(newWrNode);
|
||||
}
|
||||
|
||||
m_vis.run("colors");
|
||||
m_vis.run("layout");
|
||||
m_vis.run("scrollToSelectedAndEdit");
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
};
|
||||
|
||||
class ScrollToSelectedAction extends Action {
|
||||
|
||||
final boolean openEditor;
|
||||
|
||||
public ScrollToSelectedAction(boolean openEditor) {
|
||||
super();
|
||||
this.openEditor = openEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(double frac) {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (selected == null) return;
|
||||
VisualItem newItem = WriterGraphView.this.m_vis.getVisualItem(NODES, cells.get(selected));
|
||||
if (prevSelected != null) {
|
||||
VisualItem prevItem = m_vis.getVisualItem(NODES, cells.get(prevSelected));
|
||||
Point2D target = getScreenCoordinates(new Point2D.Double(prevItem.getX(), prevItem.getY()), null);
|
||||
animatePan(prevItem.getX() - newItem.getX(), prevItem.getY() - newItem.getY(), 200);
|
||||
if (openEditor)showEditorOnSelectedAt(target);
|
||||
} else {
|
||||
animatePanToAbs(new Point2D.Double(newItem.getX(), newItem.getY()), 200);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private void showEditorOnSelected() {
|
||||
if (selected == null) return;
|
||||
Node selNode = cells.get(selected);
|
||||
if (selNode != null) {
|
||||
VisualItem vItem = m_vis.getVisualItem(NODES, selNode);
|
||||
if (vItem != null) {
|
||||
showEditorOnSelectedAt(getScreenCoordinates(new Point2D.Double(vItem.getX(), vItem.getY()),null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JTextArea area;
|
||||
private void showEditorOnSelectedAt(final Point2D p) {
|
||||
if (overlay != null) disposeOverlay();
|
||||
|
||||
//System.out.println(p);
|
||||
area = new JTextArea(selected.text);
|
||||
JInternalFrame frame = new JInternalFrame(selected.getTitle(), true);
|
||||
frame.getContentPane().setLayout(new BorderLayout());
|
||||
JPanel pane = new JPanel();
|
||||
pane.setLayout(new BorderLayout());
|
||||
pane.add(new JScrollPane(area));
|
||||
frame.setSize(250, 80);
|
||||
frame.setLocation(new Point((int)p.getX(), (int)p.getY()));
|
||||
frame.setVisible(true);
|
||||
frame.getContentPane().add(pane, BorderLayout.CENTER);
|
||||
((BasicInternalFrameUI)frame.getUI()).getNorthPane().remove(0);
|
||||
|
||||
JButton commit = new JButton(commitEditAndDisposeEditor);
|
||||
commit.setToolTipText("Save text and close editor (Ctrl + Enter)");
|
||||
|
||||
JButton cancel = new JButton(disposeEditor);
|
||||
cancel.setToolTipText("Discard changes and close editor (Escape)");
|
||||
|
||||
|
||||
view.add(frame);
|
||||
overlay = frame;
|
||||
frame.requestFocus();
|
||||
area.requestFocus();
|
||||
area.addFocusListener(new FocusListener() {
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
disposeOverlay();
|
||||
}
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {}
|
||||
});
|
||||
|
||||
area.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), disposeEditorString);
|
||||
area.getActionMap().put(disposeEditorString, disposeEditor);
|
||||
|
||||
area.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.CTRL_DOWN_MASK, true), commitEditAndDisposeEditorString);
|
||||
area.getActionMap().put(commitEditAndDisposeEditorString, commitEditAndDisposeEditor);
|
||||
|
||||
area.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.ALT_DOWN_MASK, true), commitAndCreateNextDefaultNodeString);
|
||||
area.getActionMap().put(commitAndCreateNextDefaultNodeString, commitAndCreateNextDefaultNode);
|
||||
|
||||
area.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_DOWN_MASK, true), createContinueTalkingNodeString);
|
||||
area.getActionMap().put(createContinueTalkingNodeString, createContinueTalkingNode);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setSelected(WriterNode wrNode) {
|
||||
prevSelected = selected;
|
||||
selected = wrNode;
|
||||
}
|
||||
|
||||
public void selectAndScroll(WriterNode node) {
|
||||
if (node != null) {
|
||||
setSelected(node);
|
||||
|
||||
m_vis.run("colors");
|
||||
m_vis.run("layout");
|
||||
m_vis.run("scrollToSelected");
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
public void selectScrollAndEdit(WriterNode node) {
|
||||
if (node != null) {
|
||||
setSelected(node);
|
||||
|
||||
m_vis.run("colors");
|
||||
m_vis.run("layout");
|
||||
m_vis.run("scrollToSelectedAndEdit");
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public WriterNode nextNodeRight(WriterNode wrNode) {
|
||||
Node node = cells.get(wrNode);
|
||||
Node nextNode = graph.getFirstTreeChild(node);
|
||||
return nextNode == null ? null : (WriterNode) nextNode.get(TARGET);
|
||||
}
|
||||
|
||||
public WriterNode nextNodeLeft(WriterNode wrNode) {
|
||||
Node node = cells.get(wrNode);
|
||||
Node nextNode = graph.getTreeParent(node);
|
||||
return nextNode == null ? null : (WriterNode) nextNode.get(TARGET);
|
||||
}
|
||||
|
||||
public WriterNode nextNodeUp(WriterNode wrNode) {
|
||||
if (wrNode == null) return null;
|
||||
Node node = cells.get(wrNode);
|
||||
Node nextNode = graph.getPreviousTreeSibling(node);
|
||||
if (nextNode == null) nextNode = findPreviousSiblingWithLastChildAtDepth(node, 0);
|
||||
return nextNode == null ? null : (WriterNode) nextNode.get(TARGET);
|
||||
}
|
||||
|
||||
|
||||
private Node findPreviousSiblingWithLastChildAtDepth(Node node, int depth) {
|
||||
if (graph.getTreeParent(node) == null) return null;
|
||||
Node prevSibl = graph.getPreviousTreeSibling(node);
|
||||
if (prevSibl != null) {
|
||||
Node candidate = findLastChildAtDepth(prevSibl, depth);
|
||||
return candidate != null ? candidate : findPreviousSiblingWithLastChildAtDepth(prevSibl, depth);
|
||||
} else {
|
||||
return findPreviousSiblingWithLastChildAtDepth(graph.getTreeParent(node), depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private Node findLastChildAtDepth(Node node, int depth) {
|
||||
if (depth == 0) return node;
|
||||
if (graph.getLastTreeChild(node) != null) return findLastChildAtDepth(graph.getLastTreeChild(node), depth - 1);
|
||||
return findPreviousSiblingWithLastChildAtDepth(node, depth);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public WriterNode nextNodeDown(WriterNode wrNode) {
|
||||
if (wrNode == null) return null;
|
||||
Node node = cells.get(wrNode);
|
||||
Node nextNode = graph.getNextTreeSibling(node);
|
||||
if (nextNode == null) nextNode = findNextSiblingWithLastChildAtDepth(node, 0);
|
||||
return nextNode == null ? null : (WriterNode) nextNode.get(TARGET);
|
||||
}
|
||||
|
||||
|
||||
private Node findNextSiblingWithLastChildAtDepth(Node node, int depth) {
|
||||
if (graph.getTreeParent(node) == null) return null;
|
||||
Node nextSibl = graph.getNextTreeSibling(node);
|
||||
if (nextSibl != null) {
|
||||
Node candidate = findFirstChildAtDepth(nextSibl, depth);
|
||||
return candidate != null ? candidate : findNextSiblingWithLastChildAtDepth(nextSibl, depth);
|
||||
} else {
|
||||
return findNextSiblingWithLastChildAtDepth(graph.getTreeParent(node), depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private Node findFirstChildAtDepth(Node node, int depth) {
|
||||
if (depth == 0) return node;
|
||||
if (graph.getFirstTreeChild(node) != null) return findFirstChildAtDepth(graph.getFirstTreeChild(node), depth - 1);
|
||||
return findNextSiblingWithLastChildAtDepth(node, depth);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public Point2D getScreenCoordinates(Point2D abs, Point2D screen) {
|
||||
return getTransform().transform(abs, screen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public class MyGraph extends Graph {
|
||||
|
||||
|
||||
private String m_spanningTreeFilter;
|
||||
private FilteredSpanningTree m_filteredSpanning = null;
|
||||
|
||||
public MyGraph(boolean directed, String spanningFilterColumn) {
|
||||
super(directed);
|
||||
m_spanningTreeFilter = spanningFilterColumn;
|
||||
}
|
||||
|
||||
public Tree getFilteredSpanningTree() {
|
||||
if ( m_filteredSpanning == null )
|
||||
return getFilteredSpanningTree((Node)nodes().next());
|
||||
else
|
||||
return m_filteredSpanning;
|
||||
}
|
||||
|
||||
public Tree getFilteredSpanningTree(Node root) {
|
||||
nodeCheck(root, true);
|
||||
if ( m_filteredSpanning == null ) {
|
||||
m_filteredSpanning = new FilteredSpanningTree(this, root, m_spanningTreeFilter);
|
||||
} else if ( m_filteredSpanning.getRoot() != root ) {
|
||||
m_filteredSpanning.buildSpanningTree(root);
|
||||
}
|
||||
return m_filteredSpanning;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateDegrees(int e, int s, int t, int incr) {
|
||||
super.updateDegrees(e, s, t, incr);
|
||||
clearFilteredSpanningTree();
|
||||
}
|
||||
|
||||
public void clearFilteredSpanningTree() {
|
||||
m_filteredSpanning = null;
|
||||
}
|
||||
|
||||
public Node getTreeParent(Node n) {
|
||||
return getFilteredSpanningTree().getParent(n);
|
||||
}
|
||||
|
||||
public Node getNextTreeSibling(Node n) {
|
||||
return getFilteredSpanningTree().getNextSibling(n);
|
||||
}
|
||||
|
||||
public Node getPreviousTreeSibling(Node n) {
|
||||
return getFilteredSpanningTree().getPreviousSibling(n);
|
||||
}
|
||||
|
||||
public Node getFirstTreeChild(Node n) {
|
||||
return getFilteredSpanningTree().getFirstChild(n);
|
||||
}
|
||||
|
||||
public Node getLastTreeChild(Node n) {
|
||||
return getFilteredSpanningTree().getLastChild(n);
|
||||
}
|
||||
}
|
||||
|
||||
// class TooltipControl extends ControlAdapter {
|
||||
//
|
||||
// @Override
|
||||
// public void itemEntered(VisualItem item, MouseEvent e) {
|
||||
// if (item.get(TARGET) != null) {
|
||||
// tooltippedItem = item;
|
||||
// if (!tooltipActivated) {
|
||||
// setToolTipText("");
|
||||
// ToolTipManager.sharedInstance().registerComponent(WriterGraphView.this);
|
||||
// ToolTipManager.sharedInstance().setEnabled(true);
|
||||
// tooltipActivated = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// @Override
|
||||
// public void itemExited(VisualItem item, MouseEvent e) {
|
||||
// //Hides the tooltip...
|
||||
// ToolTipManager.sharedInstance().setEnabled(false);
|
||||
// ToolTipManager.sharedInstance().unregisterComponent(WriterGraphView.this);
|
||||
// tooltipActivated = false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// JToolTip tt = null;
|
||||
// private VisualItem tooltippedItem = null;
|
||||
// private VisualItem lastTTItem = null;
|
||||
// private boolean tooltipActivated = false;
|
||||
//
|
||||
// @Override
|
||||
// public Point getToolTipLocation(MouseEvent event) {
|
||||
// return new Point(event.getX() + 5, event.getY() + 5);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public JToolTip createToolTip() {
|
||||
// if (tt == null) tt = super.createToolTip();
|
||||
// if (tooltippedItem == lastTTItem) {
|
||||
// return tt;
|
||||
// }
|
||||
// tt = super.createToolTip();
|
||||
// lastTTItem = tooltippedItem;
|
||||
// tt.setLayout(new BorderLayout());
|
||||
// JPanel content = new JPanel();
|
||||
// content.setLayout(new JideBoxLayout(content, JideBoxLayout.PAGE_AXIS));
|
||||
// JLabel label;
|
||||
// if (tooltippedItem != null) {
|
||||
// Object target = tooltippedItem.get(TARGET);
|
||||
// if (target != null) {
|
||||
// if (target instanceof Dialogue) {
|
||||
// Dialogue d = (Dialogue) target;
|
||||
// label = new JLabel(new ImageIcon(DefaultIcons.getDialogueIcon()));
|
||||
// label.setText(d.id);
|
||||
// content.add(label, JideBoxLayout.FIX);
|
||||
// if (tooltippedItem.get(REPLY) == null) {
|
||||
// if (d.rewards != null && !d.rewards.isEmpty()) {
|
||||
// for (Dialogue.Reward r : d.rewards) {
|
||||
// label = new JLabel();
|
||||
// DialogueEditor.decorateRewardJLabel(label, r);
|
||||
// content.add(label, JideBoxLayout.FIX);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// Object replObj = tooltippedItem.get(REPLY);
|
||||
// if (replObj instanceof Dialogue.Reply) {
|
||||
// Dialogue.Reply r = (Dialogue.Reply) replObj;
|
||||
// if (r.requirements != null && !r.requirements.isEmpty()) {
|
||||
// for (Requirement req : r.requirements) {
|
||||
// label = new JLabel();
|
||||
// DialogueEditor.decorateRequirementJLabel(label, req);
|
||||
// content.add(label, JideBoxLayout.FIX);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// tt.add(content, BorderLayout.CENTER);
|
||||
// tt.setPreferredSize(tt.getLayout().preferredLayoutSize(tt));
|
||||
// return tt;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
302
src/prefuse/data/FilteredSpanningTree.java
Normal file
302
src/prefuse/data/FilteredSpanningTree.java
Normal file
@@ -0,0 +1,302 @@
|
||||
package prefuse.data;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import prefuse.data.Edge;
|
||||
import prefuse.data.Graph;
|
||||
import prefuse.data.Node;
|
||||
import prefuse.data.Schema;
|
||||
import prefuse.data.Table;
|
||||
import prefuse.data.Tree;
|
||||
import prefuse.data.Tuple;
|
||||
import prefuse.data.tuple.TupleManager;
|
||||
import prefuse.visual.tuple.TableEdgeItem;
|
||||
|
||||
public class FilteredSpanningTree extends Tree {
|
||||
|
||||
/** Extra edge table data field recording the id of the source edge
|
||||
* a tree edge represents. */
|
||||
public static final String SOURCE_EDGE = "source";
|
||||
/** Edge table schema used by the spanning tree. */
|
||||
protected static final Schema EDGE_SCHEMA = new Schema();
|
||||
static {
|
||||
EDGE_SCHEMA.addColumn(DEFAULT_SOURCE_KEY, int.class, new Integer(-1));
|
||||
EDGE_SCHEMA.addColumn(DEFAULT_TARGET_KEY, int.class, new Integer(-1));
|
||||
EDGE_SCHEMA.addColumn(SOURCE_EDGE, int.class);
|
||||
}
|
||||
|
||||
/** A reference to the backing graph that this tree spans. */
|
||||
protected Graph m_backing;
|
||||
/** The boolean field to check. If false, edge is filtered out. */
|
||||
protected int m_filter;
|
||||
|
||||
/**
|
||||
* Create a new SpanningTree.
|
||||
* @param g the backing Graph to span
|
||||
* @param root the Node to use as the root of the spanning tree
|
||||
* @param filterField the Edge column to use to filter out non-tree edges (must be boolean);
|
||||
*/
|
||||
public FilteredSpanningTree(Graph g, Node root, String filterField) {
|
||||
super(g.getNodeTable(), EDGE_SCHEMA.instantiate());
|
||||
m_filter = g.getEdgeTable().getColumnNumber(filterField);
|
||||
if (g.getEdgeTable().getColumn(m_filter) != null && !g.getEdgeTable().getColumn(m_filter).canGetBoolean()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"The filter column must be boolean.");
|
||||
}
|
||||
m_backing = g;
|
||||
TupleManager etm = new TupleManager(getEdgeTable(), null,
|
||||
TableEdgeItem.class) {
|
||||
public Tuple getTuple(int row) {
|
||||
return m_backing.getEdge(m_table.getInt(row, SOURCE_EDGE));
|
||||
}
|
||||
};
|
||||
getEdgeTable().setTupleManager(etm);
|
||||
super.setTupleManagers(g.m_nodeTuples, etm);
|
||||
buildSpanningTree(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the spanning tree, starting at the given root. Uses an
|
||||
* unweighted breadth first traversal to build the spanning tree.
|
||||
* @param root the root node of the spanning tree
|
||||
*/
|
||||
public void buildSpanningTree(Node root) {
|
||||
// re-use a previously allocated tree if possible
|
||||
super.clearEdges();
|
||||
super.setRoot(root);
|
||||
|
||||
// build unweighted spanning tree by BFS
|
||||
LinkedList q = new LinkedList();
|
||||
BitSet visit = new BitSet();
|
||||
q.add(root); visit.set(root.getRow());
|
||||
Table edges = getEdgeTable();
|
||||
|
||||
while ( !q.isEmpty() ) {
|
||||
Node p = (Node)q.removeFirst();
|
||||
for ( Iterator iter = p.edges(); iter.hasNext(); ) {
|
||||
Edge e = (Edge)iter.next();
|
||||
if (e.getBoolean(m_filter)) {
|
||||
Node n = e.getAdjacentNode(p);
|
||||
if ( !visit.get(n.getRow()) ) {
|
||||
q.add(n); visit.set(n.getRow());
|
||||
int er = super.addChildEdge(p.getRow(), n.getRow());
|
||||
edges.setInt(er, SOURCE_EDGE, e.getRow());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Disallow most mutator methods
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#addChild(int)
|
||||
*/
|
||||
public int addChild(int parent) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#addChild(prefuse.data.Node)
|
||||
*/
|
||||
public Node addChild(Node parent) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#addChildEdge(int, int)
|
||||
*/
|
||||
public int addChildEdge(int parent, int child) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#addChildEdge(prefuse.data.Node, prefuse.data.Node)
|
||||
*/
|
||||
public Edge addChildEdge(Node parent, Node child) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#addRoot()
|
||||
*/
|
||||
public Node addRoot() {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#addRootRow()
|
||||
*/
|
||||
public int addRootRow() {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#removeChild(int)
|
||||
*/
|
||||
public boolean removeChild(int node) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#removeChild(prefuse.data.Node)
|
||||
*/
|
||||
public boolean removeChild(Node n) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#removeChildEdge(prefuse.data.Edge)
|
||||
*/
|
||||
public boolean removeChildEdge(Edge e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#removeChildEdge(int)
|
||||
*/
|
||||
public boolean removeChildEdge(int edge) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Tree#setRoot(prefuse.data.Node)
|
||||
*/
|
||||
void setRoot(Node root) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to tree structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#addEdge(int, int)
|
||||
*/
|
||||
public int addEdge(int s, int t) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#addEdge(prefuse.data.Node, prefuse.data.Node)
|
||||
*/
|
||||
public Edge addEdge(Node s, Node t) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#addNode()
|
||||
*/
|
||||
public Node addNode() {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#addNodeRow()
|
||||
*/
|
||||
public int addNodeRow() {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.tuple.TupleSet#clear()
|
||||
*/
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#removeEdge(prefuse.data.Edge)
|
||||
*/
|
||||
public boolean removeEdge(Edge e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#removeEdge(int)
|
||||
*/
|
||||
public boolean removeEdge(int edge) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#removeNode(int)
|
||||
*/
|
||||
public boolean removeNode(int node) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#removeNode(prefuse.data.Node)
|
||||
*/
|
||||
public boolean removeNode(Node n) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.tuple.TupleSet#removeTuple(prefuse.data.Tuple)
|
||||
*/
|
||||
public boolean removeTuple(Tuple t) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#setEdgeTable(prefuse.data.Table)
|
||||
*/
|
||||
public void setEdgeTable(Table edges) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported operation. Spanning trees should not be edited.
|
||||
* @see prefuse.data.Graph#setTupleManagers(prefuse.data.tuple.TupleManager, prefuse.data.tuple.TupleManager)
|
||||
*/
|
||||
public void setTupleManagers(TupleManager ntm, TupleManager etm) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Changes to graph structure not allowed for spanning trees.");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user