Compare commits

..

13 Commits

Author SHA1 Message Date
Zukero
49f19abb91 Forgot the necessary cleanup of old jars in windows NSIS version. 2017-04-03 17:57:03 +02:00
Zukero
300b7bbbdd Fixed caching issue with spritesheet chooser. Improved actor condition
management for items.
2017-04-03 17:53:44 +02:00
Zukero
bbee5bef25 Bug fix regarding object groups and spawn areas "active in a new game"
parameter.
2017-03-31 09:29:53 +02:00
Zukero
1fc1cef233 Fixed issue with batch scripts being overly painful to use, and have
horrible quoting and escaping rules.
2017-03-06 18:01:05 +01:00
Zukero
ae9a6695b0 v0.5.2 updated. Messed up something in scripts about paths containing
spaces.
2017-03-03 17:34:21 +01:00
Zukero
572704fd73 v0.5.2 ! Upped the bash & batch game. Can run from any directory,
auto-adaptation to jar files in lib, creation, use, and preservation
upon update or reinstall of a startup customization file (Max JVM
memory, custom java binary and custom JVM options as environment
variables). This is valid for all OS types (bash or batch startup) and
all installation methods (zip and nsis). Robustified a stupid version
management for workspace settings.
2017-03-03 17:15:16 +01:00
Zukero
dfe3cc8480 UAC dirty script for better windows integration to create symlinks. More
data using a thread-safe collection. Some NPEs fixed. 
More data protection in tiled integration functions (better state
checking, backup tiled-made file before saving ATCS-made data).
jardesc file added for convenience.
2017-03-02 18:10:03 +01:00
Zukero
97ae63693a Enhanced Tiled integration. ATCS offers to save a modified map before
opening in Tiled, and attempts to save a backup of the
externally-modified one when saving in ATCS if necessary.
2017-03-02 15:30:02 +01:00
Zukero
940996aa30 Some refactoring. Replaced all "listeners" list by instances of
CopyOnWriteArrayList, to allow listeners to unregister themselves due to
an event while preventing ConcurrentModificationExceptions.
Modified all GameDataElement.elementChanged concrete implementation to
remove the backlink from the oldOne.An element pointed by an altered
element will not show the game source element in its backlink list
anymore.
2017-03-02 13:53:24 +01:00
Zukero
2a4cfb0684 Enhanced Tiled integration. Can now reload a map that has changed
externaly. Still some rough edges, notably the number of nitification
sto skip when saving in ATCS.
2017-03-01 19:02:00 +01:00
Zukero
061a0fa11b Create new TMX maps in your project, and edit them with Tiled from ATCS
!! Also, "created" elements show the "unsaved" asterisk in their
description until they're saved to disk. 
Added a button to the spritesheet editor to open image in an external
tool too. This may or may not remain in the app.
2017-02-28 18:43:47 +01:00
Zukero
41462137d6 Enhanced Tiled integration. Now in "File->Edit workspace settings" menu,
you have tools to help selecting external tools to bview/edit images and
tmx maps. Still rough.
2017-02-27 18:18:17 +01:00
Zukero
9888dfe678 Introducing the WorkspaceSettings, workspace-wide user-modifiable
settings. No UI yet, so it's useless for now.
2017-02-24 17:45:34 +01:00
52 changed files with 1556 additions and 121 deletions

18
ATCS_JAR.jardesc Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jardesc>
<jar path="ATContentStudio/ATCS_v0.5.3.jar"/>
<options buildIfNeeded="true" compress="true" descriptionLocation="/ATContentStudio/ATCS_JAR.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>
<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
<sealing sealJar="false">
<packagesToSeal/>
<packagesToUnSeal/>
</sealing>
</manifest>
<selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false">
<javaElement handleIdentifier="=ATContentStudio/res"/>
<javaElement handleIdentifier="=ATContentStudio/src"/>
<javaElement handleIdentifier="=ATContentStudio/hacked-libtiled"/>
</selectedElements>
</jardesc>

View File

@@ -1 +1,20 @@
start "" "javaw.exe" -Xmx512M -cp "lib\ATCS_v0.5.1.jar;lib\jide-oss.jar;lib\ui.jar;lib\junit-4.10.jar;lib\json_simple-1.1.jar;lib\rsyntaxtextarea.jar;lib\prefuse.jar;lib\AndorsTrainer_v0.1.3.jar;lib\bsh-2.0b4.jar" com.gpl.rpg.atcontentstudio.ATContentStudio
@echo off
set "ATCS_DIR=%~dp0"
set "MAX_MEM=512M"
set "CP=%ATCS_DIR%lib\*"
set "JAVA=javaw.exe"
set "JAVA_OPTS="
set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"
set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"
if exist "%ENV_FILE%" (
call "%ENV_FILE%"
) else (
echo REM set "MAX_MEM=%MAX_MEM%">"%ENV_FILE%"
echo REM set "JAVA=%JAVA%">>"%ENV_FILE%"
echo REM set "JAVA_OPTS=%JAVA_OPTS%">>"%ENV_FILE%"
echo.>>"%ENV_FILE%"
)
start "" "%JAVA%" %JAVA_OPTS% -Xmx%MAX_MEM% -cp "%CP%" %MAIN_CLASS%

View File

@@ -1,2 +1,22 @@
#!/bin/bash
java -Xmx512M -cp lib/AndorsTrainer_v0.1.3.jar:lib/ATCS_v0.5.1.jar:lib/prefuse.jar:lib/json_simple-1.1.jar:lib/jide-oss.jar:lib/ui.jar:lib/junit-4.10.jar:lib/rsyntaxtextarea.jar:lib/bsh-2.0b4.jar com.gpl.rpg.atcontentstudio.ATContentStudio
ATCS_DIR=$(dirname $(readlink -f "$0" || greadlink -f "$0" || stat -f "$0"))
MAX_MEM=512M
CP=$(find ${ATCS_DIR}/lib/ -name '*.jar' | paste -sd: -)
JAVA=java
JAVA_OPTS=
ENV_FILE=${ATCS_DIR}/ATCS.env
MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio
if [ -f ${ENV_FILE} ]
then
source ${ENV_FILE}
else
echo "#MAX_MEM=${MAX_MEM}" > ${ENV_FILE}
echo "#JAVA=${JAVA}" >> ${ENV_FILE}
echo "#JAVA_OPTS=${JAVA_OPTS}" >> ${ENV_FILE}
echo "" >> ${ENV_FILE}
fi
export ENV_FILE
$JAVA ${JAVA_OPTS} -Xmx${MAX_MEM} -cp ${CP} ${MAIN_CLASS}

View File

@@ -1 +1,20 @@
start "" "javaw.exe" -Xmx512M -cp "lib\ATCS_v0.5.0.jar;lib\jide-oss.jar;lib\ui.jar;lib\junit-4.10.jar;lib\json_simple-1.1.jar;lib\rsyntaxtextarea.jar;lib\prefuse.jar;lib\AndorsTrainer_v0.1.2.jar;lib\bsh-2.0b4.jar" com.gpl.rpg.atcontentstudio.ATContentStudio
@echo off
set "ATCS_DIR=%~dp0"
set "MAX_MEM=512M"
set "CP=%ATCS_DIR%lib\*"
set "JAVA=javaw.exe"
set "JAVA_OPTS="
set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"
set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"
if exist "%ENV_FILE%" (
call "%ENV_FILE%"
) else (
echo REM set "MAX_MEM=%MAX_MEM%">"%ENV_FILE%"
echo REM set "JAVA=%JAVA%">>"%ENV_FILE%"
echo REM set "JAVA_OPTS=%JAVA_OPTS%">>"%ENV_FILE%"
echo.>>"%ENV_FILE%"
)
start "" "%JAVA%" %JAVA_OPTS% -Xmx%MAX_MEM% -cp "%CP%" %MAIN_CLASS%

View File

@@ -1,7 +1,8 @@
!include MUI2.nsh
!define VERSION "0.5.1"
!define JAVA_BIN "java"
!define VERSION "0.5.3"
!define TRAINER_VERSION "0.1.3"
!define JAVA_BIN "javaw"
Name "Andor's Trail Content Studio v${VERSION}"
OutFile "ATCS_v${VERSION}_Setup.exe"
@@ -54,16 +55,37 @@ Section install
SetOutPath $INSTDIR
file "ATCS.ico"
Delete "$INSTDIR\lib\*"
Call GetJRE
Pop $R0
FileOpen $9 "ATCS.cmd" w
FileWrite $9 'start "" "$R0" -Xmx512M -cp "lib\AndorsTrainer_v0.1.1.jar;lib\jide-oss.jar;lib\ui.jar;lib\junit-4.10.jar;lib\json_simple-1.1.jar;lib\rsyntaxtextarea.jar;lib\prefuse.jar;lib\bsh-2.0b4.jar;lib\ATCS_v${VERSION}.jar" com.gpl.rpg.atcontentstudio.ATContentStudio'
FileWrite $9 '@echo off$\r$\n'
FileWrite $9 '$\r$\n'
FileWrite $9 'set "ATCS_DIR=%~dp0"$\r$\n'
FileWrite $9 'set "MAX_MEM=512M"$\r$\n'
FileWrite $9 'set "CP=%ATCS_DIR%lib\*"$\r$\n'
FileWrite $9 'set "JAVA=$R0"$\r$\n'
FileWrite $9 'set "JAVA_OPTS="$\r$\n'
FileWrite $9 'set "ENV_FILE=%ATCS_DIR%ATCS.env.bat"$\r$\n'
FileWrite $9 'set "MAIN_CLASS=com.gpl.rpg.atcontentstudio.ATContentStudio"$\r$\n'
FileWrite $9 '$\r$\n'
FileWrite $9 'if exist "%ENV_FILE%" ($\r$\n'
FileWrite $9 ' call "%ENV_FILE%"$\r$\n'
FileWrite $9 ') else ($\r$\n'
FileWrite $9 ' echo REM set "MAX_MEM=%MAX_MEM%">"%ENV_FILE%"$\r$\n'
FileWrite $9 ' echo REM set "JAVA=%JAVA%">>"%ENV_FILE%"$\r$\n'
FileWrite $9 ' echo REM set "JAVA_OPTS=%JAVA_OPTS%">>"%ENV_FILE%"$\r$\n'
FileWrite $9 ' echo.>>"%ENV_FILE%"$\r$\n'
FileWrite $9 ')$\r$\n'
FileWrite $9 '$\r$\n'
FileWrite $9 'start "" "%JAVA%" %JAVA_OPTS% -Xmx%MAX_MEM% -cp "%CP%" %MAIN_CLASS%$\r$\n'
FileClose $9
SetOutPath "$INSTDIR\lib\"
file "jide-oss.jar"
file "ui.jar"
file "AndorsTrainer_v0.1.3.jar"
file "AndorsTrainer_v${TRAINER_VERSION}.jar"
file "junit-4.10.jar"
file "json_simple-1.1.jar"
file "ATCS_v${VERSION}.jar"
@@ -93,7 +115,7 @@ Section uninstall
Delete "$INSTDIR\lib\ui.jar"
Delete "$INSTDIR\lib\junit-4.10.jar"
Delete "$INSTDIR\lib\json_simple-1.1.jar"
Delete "$INSTDIR\lib\AndorsTrainer_v0.1.3.jar"
Delete "$INSTDIR\lib\AndorsTrainer_v${TRAINER_VERSION}.jar"
Delete "$INSTDIR\lib\ATCS_v${VERSION}.jar"
Delete "$INSTDIR\lib\rsyntaxtextarea.jar"
Delete "$INSTDIR\lib\prefuse.jar"
@@ -101,6 +123,7 @@ Section uninstall
RMDir "$INSTDIR\lib\"
Delete "$INSTDIR\ATCS.ico"
Delete "$INSTDIR\ATCS.cmd"
Delete "$INSTDIR\ATCS.env.bat"
Delete "$INSTDIR\Uninstall.exe"

View File

@@ -22,7 +22,7 @@ import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector;
public class ATContentStudio {
public static final String APP_NAME = "Andor's Trail Content Studio";
public static final String APP_VERSION = "v0.5.1";
public static final String APP_VERSION = "v0.5.3";
public static boolean STARTED = false;
public static StudioFrame frame = null;

View File

@@ -2,11 +2,12 @@ package com.gpl.rpg.atcontentstudio;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class Notification {
public static List<Notification> notifs = new ArrayList<Notification>();
private static List<NotificationListener> listeners = new ArrayList<NotificationListener>();
private static List<NotificationListener> listeners = new CopyOnWriteArrayList<NotificationListener>();
public static boolean showS = true, showI = true, showW = true, showE = true;
static {

View File

@@ -4,10 +4,10 @@ import java.awt.Image;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.tree.TreeNode;
@@ -32,7 +32,7 @@ public abstract class GameDataElement implements ProjectTreeNode, Serializable {
public boolean writable = false;
//List of objects whose transition to "linked" state made them point to this instance.
private Map<GameDataElement, Integer> backlinks = new LinkedHashMap<GameDataElement, Integer>();
private Map<GameDataElement, Integer> backlinks = new ConcurrentHashMap<GameDataElement, Integer>();
public String id = null;

View File

@@ -665,6 +665,26 @@ public class Project implements ProjectTreeNode, Serializable {
return sheet;
}
public int getSpritesheetCount() {
return createdContent.gameSprites.spritesheets.size() + baseContent.gameSprites.spritesheets.size();
}
public Spritesheet getSpritesheet(int index) {
if (index < createdContent.gameSprites.spritesheets.size()) {
return createdContent.gameSprites.spritesheets.get(index);
} else if (index < getQuestCount()){
return getSpritesheet(baseContent.gameSprites.spritesheets.get(index - createdContent.gameSprites.spritesheets.size()).id);
}
return null;
}
public int getSpritesheetIndex(Spritesheet spritesheet) {
if (spritesheet.getDataType() == GameSource.Type.created) {
return createdContent.gameSprites.spritesheets.indexOf(spritesheet);
} else {
return createdContent.gameSprites.spritesheets.size() + baseContent.gameSprites.spritesheets.indexOf(baseContent.gameSprites.getSpritesheet(spritesheet.id));
}
}
public TMXMap getMap(String id) {
TMXMap map = createdContent.gameMaps.getMap(id);
@@ -850,6 +870,34 @@ public class Project implements ProjectTreeNode, Serializable {
}
}
/**
*
* @param node. Before calling this method, make sure that no other map with the same id exist in either created or altered.
*/
public void createElement(TMXMap node) {
node.writable = true;
if (getMap(node.id) != null) {
GameDataElement existingNode = getMap(node.id);
for (GameDataElement backlink : existingNode.getBacklinks()) {
backlink.elementChanged(existingNode, node);
}
existingNode.getBacklinks().clear();
node.writable = true;
node.tmxFile = new File(alteredContent.baseFolder, node.tmxFile.getName());
node.parent = alteredContent.gameMaps;
alteredContent.gameMaps.addMap(node);
node.link();
node.state = GameDataElement.State.created;
} else {
node.tmxFile = new File(createdContent.baseFolder, node.tmxFile.getName());
node.parent = createdContent.gameMaps;
createdContent.gameMaps.addMap(node);
node.link();
node.state = GameDataElement.State.created;
}
fireElementAdded(node, getNodeIndex(node));
}
public void moveToCreated(JSONElement target) {
target.childrenRemoved(new ArrayList<ProjectTreeNode>());

View File

@@ -35,6 +35,7 @@ public class Workspace implements ProjectTreeNode, Serializable {
public Preferences preferences = new Preferences();
public File baseFolder;
public File settingsFile;
public transient WorkspaceSettings settings;
public transient List<ProjectTreeNode> projects = new ArrayList<ProjectTreeNode>();
public Set<String> projectsName = new HashSet<String>();
public Map<String, Boolean> projectsOpenByName = new HashMap<String, Boolean>();
@@ -53,6 +54,7 @@ public class Workspace implements ProjectTreeNode, Serializable {
e.printStackTrace();
}
}
settings = new WorkspaceSettings(this);
settingsFile = new File(workspaceRoot, WS_SETTINGS_FILE);
if (!settingsFile.exists()) {
try {
@@ -89,6 +91,7 @@ public class Workspace implements ProjectTreeNode, Serializable {
}
public void save() {
settings.save();
SettingsSave.saveInstance(this, settingsFile, "Workspace");
}
@@ -229,6 +232,7 @@ public class Workspace implements ProjectTreeNode, Serializable {
}
public void refreshTransients() {
this.settings = new WorkspaceSettings(this);
this.projects = new ArrayList<ProjectTreeNode>();
Set<String> projectsFailed = new HashSet<String>();
for (String projectName : projectsName) {

View File

@@ -0,0 +1,204 @@
package com.gpl.rpg.atcontentstudio.model;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.io.JsonPrettyWriter;
public class WorkspaceSettings {
public static final String VERSION_KEY = "ATCS_Version";
public static final String FILENAME = "workspace_settings.json";
public static final int SETTINGS_VERSION = 1;
public Workspace parent;
public File file;
public static Boolean DEFAULT_USE_SYS_MAP_EDITOR = true;
public Setting<Boolean> useSystemDefaultMapEditor = new PrimitiveSetting<Boolean>("useSystemDefaultMapEditor", DEFAULT_USE_SYS_MAP_EDITOR);
public static String DEFAULT_MAP_EDITOR_COMMAND = "tiled";
public Setting<String> mapEditorCommand = new PrimitiveSetting<String>("mapEditorCommand", DEFAULT_MAP_EDITOR_COMMAND);
public static Boolean DEFAULT_USE_SYS_IMG_VIEWER = true;
public Setting<Boolean> useSystemDefaultImageViewer = new PrimitiveSetting<Boolean>("useSystemDefaultImageViewer", DEFAULT_USE_SYS_IMG_VIEWER);
public static Boolean DEFAULT_USE_SYS_IMG_EDITOR = false;
public Setting<Boolean> useSystemDefaultImageEditor = new PrimitiveSetting<Boolean>("useSystemDefaultImageEditor", DEFAULT_USE_SYS_IMG_EDITOR);
public static String DEFAULT_IMG_EDITOR_COMMAND = "gimp";
public Setting<String> imageEditorCommand = new PrimitiveSetting<String>("imageEditorCommand", DEFAULT_IMG_EDITOR_COMMAND);
public List<Setting<? extends Object>> settings = new ArrayList<Setting<? extends Object>>();
public WorkspaceSettings(Workspace parent) {
this.parent = parent;
settings.add(useSystemDefaultMapEditor);
settings.add(mapEditorCommand);
settings.add(useSystemDefaultImageViewer);
settings.add(useSystemDefaultImageEditor);
settings.add(imageEditorCommand);
file = new File(parent.baseFolder, FILENAME);
if (file.exists()) {
load(file);
}
}
public void load(File f) {
JSONParser parser = new JSONParser();
FileReader reader = null;
try {
reader = new FileReader(f);
@SuppressWarnings("rawtypes")
Map jsonSettings = (Map) parser.parse(reader);
Integer version = (Integer) jsonSettings.get(VERSION_KEY);
if (version != null) {
if (version >= 1) {
loadv1(jsonSettings);
}
}
} catch (FileNotFoundException e) {
Notification.addError("Error while parsing workspace settings: "+e.getMessage());
e.printStackTrace();
} catch (IOException e) {
Notification.addError("Error while parsing workspace settings: "+e.getMessage());
e.printStackTrace();
} catch (ParseException e) {
Notification.addError("Error while parsing workspace settings: "+e.getMessage());
e.printStackTrace();
} finally {
if (reader != null)
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("rawtypes")
private void loadv1(Map jsonSettings) {
for (Setting s : settings) {
s.readFromJson(jsonSettings);
}
}
@SuppressWarnings("unchecked")
public void save() {
@SuppressWarnings("rawtypes")
Map json = new LinkedHashMap();
for (Setting<? extends Object> s : settings) {
s.saveToJson(json);
}
if (json.isEmpty()) {
//Everything is default.
file.delete();
return;
}
json.put(VERSION_KEY, SETTINGS_VERSION);
StringWriter writer = new JsonPrettyWriter();
try {
JSONObject.writeJSONString(json, writer);
} catch (IOException e) {
//Impossible with a StringWriter
}
String toWrite = writer.toString();
try {
FileWriter w = new FileWriter(file);
w.write(toWrite);
w.close();
Notification.addSuccess("Workspace settings saved.");
} catch (IOException e) {
Notification.addError("Error while saving workspace settings : "+e.getMessage());
e.printStackTrace();
}
}
public void resetDefault() {
for (Setting<? extends Object> s : settings) {
s.resetDefault();
}
}
public abstract class Setting<X extends Object> {
public String id;
public X value, defaultValue;
public void setCurrentValue(X value) {
this.value = value;
}
public X getCurrentValue() {
return value;
}
public X getDefaultValue() {
return defaultValue;
}
public void resetDefault() {
value = defaultValue;
}
public abstract void readFromJson(Map json);
@SuppressWarnings({ "rawtypes", "unchecked" })
public void saveToJson(Map json) {
if (!defaultValue.equals(value)) json.put(id, value);
}
}
public class PrimitiveSetting<X extends Object> extends Setting<X> {
public PrimitiveSetting(String id, X defaultValue) {
this.id = id;
this.value = this.defaultValue = defaultValue;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void readFromJson(Map json) {
if (json.get(id) != null) value = (X)json.get(id);
}
}
public class ListSetting<X extends Object> extends Setting<List<X>> {
public ListSetting(String id, List<X> defaultValue) {
this.id = id;
this.value = this.defaultValue = defaultValue;
}
@Override
public void readFromJson(Map json) {
value = new ArrayList<X>();
if (json.get(id) != null) {
for (Object o : ((List)json.get(id))) {
value.add((X)o);
}
}
}
}
}

View File

@@ -20,6 +20,8 @@ import com.gpl.rpg.atcontentstudio.model.GameSource;
public class ActorCondition extends JSONElement {
private static final long serialVersionUID = -3969824899972048507L;
public static final Integer CLEAR_AC_MAGNITUDE = -99;
// Available from init state
//public String id; inherited.
@@ -86,7 +88,7 @@ public class ActorCondition extends JSONElement {
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+display_name+" ("+id+")";
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+display_name+" ("+id+")";
}
@SuppressWarnings("rawtypes")

View File

@@ -18,6 +18,7 @@ import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement.RequirementType;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
@@ -91,7 +92,7 @@ public class Dialogue extends JSONElement {
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+id;
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+id;
}
public static String getStaticDesc() {
@@ -348,18 +349,21 @@ public class Dialogue extends JSONElement {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (switch_to_npc == oldOne) {
oldOne.removeBacklink(this);
switch_to_npc = (NPC) newOne;
if (newOne != null) newOne.addBacklink(this);
} else {
if (replies != null) {
for (Reply r : replies) {
if (r.next_phrase == oldOne) {
oldOne.removeBacklink(this);
r.next_phrase = (Dialogue) newOne;
if (newOne != null) newOne.addBacklink(this);
}
if (r.requirements != null) {
for (Requirement req : r.requirements) {
if (req.required_obj == oldOne) {
oldOne.removeBacklink(this);
req.required_obj = newOne;
if (newOne != null) newOne.addBacklink(this);
}
@@ -370,6 +374,7 @@ public class Dialogue extends JSONElement {
if (rewards != null) {
for (Reward r : rewards) {
if (r.reward_obj == oldOne) {
oldOne.removeBacklink(this);
r.reward_obj = newOne;
if (newOne != null) newOne.addBacklink(this);
}

View File

@@ -17,6 +17,7 @@ import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
@@ -46,7 +47,7 @@ public class Droplist extends JSONElement {
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+id;
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+id;
}
public static String getStaticDesc() {
@@ -193,6 +194,7 @@ public class Droplist extends JSONElement {
if (dropped_items != null) {
for (DroppedItem di : dropped_items) {
if (di.item == oldOne) {
oldOne.removeBacklink(this);
di.item = (Item) newOne;
if (newOne != null) newOne.addBacklink(this);
}

View File

@@ -17,6 +17,7 @@ import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
public class Item extends JSONElement {
@@ -101,7 +102,7 @@ public class Item extends JSONElement {
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")";
}
public static String getStaticDesc() {
@@ -450,12 +451,14 @@ public class Item extends JSONElement {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (this.category == oldOne) {
oldOne.removeBacklink(this);
this.category = (ItemCategory) newOne;
if (newOne != null) newOne.addBacklink(this);
} else {
if (this.equip_effect != null && this.equip_effect.conditions != null) {
for (ConditionEffect c : this.equip_effect.conditions) {
if (c.condition == oldOne) {
oldOne.removeBacklink(this);
c.condition = (ActorCondition) newOne;
if (newOne != null) newOne.addBacklink(this);
}
@@ -464,6 +467,7 @@ public class Item extends JSONElement {
if (this.hit_effect != null && this.hit_effect.conditions_source != null) {
for (TimedConditionEffect c : this.hit_effect.conditions_source) {
if (c.condition == oldOne) {
oldOne.removeBacklink(this);
c.condition = (ActorCondition) newOne;
if (newOne != null) newOne.addBacklink(this);
}
@@ -472,6 +476,7 @@ public class Item extends JSONElement {
if (this.hit_effect != null && this.hit_effect.conditions_target != null) {
for (TimedConditionEffect c : this.hit_effect.conditions_target) {
if (c.condition == oldOne) {
oldOne.removeBacklink(this);
c.condition = (ActorCondition) newOne;
if (newOne != null) newOne.addBacklink(this);
}
@@ -481,6 +486,7 @@ public class Item extends JSONElement {
if (this.kill_effect != null && this.kill_effect.conditions_source != null) {
for (TimedConditionEffect c : this.kill_effect.conditions_source) {
if (c.condition == oldOne) {
oldOne.removeBacklink(this);
c.condition = (ActorCondition) newOne;
if (newOne != null) newOne.addBacklink(this);
}

View File

@@ -17,6 +17,7 @@ import org.json.simple.parser.ParseException;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
public class ItemCategory extends JSONElement {
@@ -99,7 +100,7 @@ public class ItemCategory extends JSONElement {
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")";
}
public static String getStaticDesc() {

View File

@@ -17,6 +17,7 @@ import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
public class NPC extends JSONElement {
@@ -95,7 +96,7 @@ public class NPC extends JSONElement {
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")";
}
public static String getStaticDesc() {
@@ -356,16 +357,19 @@ public class NPC extends JSONElement {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (dialogue == oldOne) {
oldOne.removeBacklink(this);
this.dialogue = (Dialogue) newOne;
if (newOne != null) newOne.addBacklink(this);
} else {
if (this.droplist == oldOne) {
oldOne.removeBacklink(this);
this.droplist = (Droplist) newOne;
if (newOne != null) newOne.addBacklink(this);
} else {
if (this.hit_effect != null && this.hit_effect.conditions_source != null) {
for (TimedConditionEffect tce : this.hit_effect.conditions_source) {
if (tce.condition == oldOne) {
oldOne.removeBacklink(this);
tce.condition = (ActorCondition) newOne;
if (newOne != null) newOne.addBacklink(this);
}
@@ -374,6 +378,7 @@ public class NPC extends JSONElement {
if (this.hit_effect != null && this.hit_effect.conditions_target != null) {
for (TimedConditionEffect tce : this.hit_effect.conditions_target) {
if (tce.condition == oldOne) {
oldOne.removeBacklink(this);
tce.condition = (ActorCondition) newOne;
if (newOne != null) newOne.addBacklink(this);
}

View File

@@ -16,6 +16,7 @@ import org.json.simple.parser.ParseException;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class Quest extends JSONElement {
@@ -48,7 +49,7 @@ public class Quest extends JSONElement {
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+name+" ("+id+")";
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")";
}
public static String getStaticDesc() {

View File

@@ -145,8 +145,9 @@ public class Requirement extends JSONElement {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (this.required_obj == oldOne) {
oldOne.removeBacklink((GameDataElement) this.parent);
this.required_obj = newOne;
if (newOne != null) newOne.addBacklink(this);
if (newOne != null) newOne.addBacklink((GameDataElement) this.parent);
}
}
@Override

View File

@@ -29,8 +29,9 @@ public class ContainerArea extends MapObject {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (oldOne == droplist) {
oldOne.removeBacklink(parentMap);
droplist = (Droplist) newOne;
newOne.addBacklink(parentMap);
if (newOne != null) newOne.addBacklink(parentMap);
}
}

View File

@@ -60,8 +60,9 @@ public class KeyArea extends MapObject {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (oldOne == dialogue) {
oldOne.removeBacklink(parentMap);
dialogue = (Dialogue) newOne;
newOne.addBacklink(parentMap);
if (newOne != null) newOne.addBacklink(parentMap);
}
requirement.elementChanged(oldOne, newOne);
}

View File

@@ -37,8 +37,9 @@ public class MapChange extends MapObject {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (oldOne == map) {
oldOne.removeBacklink(parentMap);
map = (TMXMap) newOne;
newOne.addBacklink(parentMap);
if (newOne != null) newOne.addBacklink(parentMap);
}
}

View File

@@ -42,8 +42,9 @@ public class ScriptArea extends MapObject {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (oldOne == dialogue) {
oldOne.removeBacklink(parentMap);
dialogue = (Dialogue) newOne;
newOne.addBacklink(parentMap);
if (newOne != null) newOne.addBacklink(parentMap);
}
}

View File

@@ -31,8 +31,9 @@ public class SignArea extends MapObject {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
if (oldOne == dialogue) {
oldOne.removeBacklink(parentMap);
dialogue = (Dialogue) newOne;
newOne.addBacklink(parentMap);
if (newOne != null) newOne.addBacklink(parentMap);
}
}

View File

@@ -64,8 +64,9 @@ public class SpawnArea extends MapObject {
}
}
if (replacedIndex >= 0) {
oldOne.removeBacklink(parentMap);
spawnGroup.set(replacedIndex, (NPC) newOne);
newOne.addBacklink(parentMap);
if (newOne != null) newOne.addBacklink(parentMap);
}
}

View File

@@ -12,6 +12,7 @@ import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.tree.TreeNode;
@@ -26,6 +27,7 @@ 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.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
@@ -61,6 +63,8 @@ public class TMXMap extends GameDataElement {
public ColorFilter colorFilter = null;
public boolean writable = false;
public boolean changedOnDisk = false;
public int dismissNextChangeNotif = 0;
public TMXMap(TMXMapSet parent, File f) {
this.parent = parent;
@@ -197,7 +201,7 @@ public class TMXMap extends GameDataElement {
}
@Override
public String getDesc() {
return (this.state == State.modified ? "*" : "")+id;
return ((this.state == State.modified || this.state == State.created) ? "*" : "")+id;
}
@Override
@@ -270,10 +274,13 @@ public class TMXMap extends GameDataElement {
public void save() {
if (writable) {
try {
//TODO: check in fileutils, to test the workspace's filesystem once at startup, and figure out how many of these can occur, instead of hard-coded '2'
dismissNextChangeNotif += 2;
FileWriter w = new FileWriter(tmxFile);
w.write(toXml());
w.close();
this.state = State.saved;
changedOnDisk = false;
Notification.addSuccess("TMX file "+tmxFile.getAbsolutePath()+" saved.");
} catch (IOException e) {
Notification.addError("Error while writing TMX file "+tmxFile.getAbsolutePath()+" : "+e.getMessage());
@@ -309,8 +316,10 @@ public class TMXMap extends GameDataElement {
parse();
}
if (this.state == GameDataElement.State.parsed || this.state == GameDataElement.State.created) {
for (MapObjectGroup group : groups) {
group.link();
if (groups != null) {
for (MapObjectGroup group : groups) {
group.link();
}
}
}
}
@@ -390,5 +399,77 @@ public class TMXMap extends GameDataElement {
ABOVE_LAYER_NAME.equalsIgnoreCase(name) ||
WALKABLE_LAYER_NAME.equalsIgnoreCase(name);
}
public void reload() {
tmxMap = null;
for (Spritesheet s : usedSpritesheets) {
s.elementChanged(this, null);
}
usedSpritesheets.clear();
for (MapObjectGroup g : groups) {
for (MapObject o : g.mapObjects) {
if (o instanceof ContainerArea) {
if (((ContainerArea)o).droplist != null) ((ContainerArea)o).droplist.elementChanged(this, null);
} else if (o instanceof KeyArea) {
if (((KeyArea)o).dialogue != null) ((KeyArea)o).dialogue.elementChanged(this, null);
if (((KeyArea)o).requirement != null && ((KeyArea)o).requirement.required_obj != null) ((KeyArea)o).requirement.required_obj.elementChanged(this, null);
} else if (o instanceof MapChange) {
if (((MapChange)o).map != null) ((MapChange)o).map.elementChanged(this, null);
} else if (o instanceof ReplaceArea) {
if (((ReplaceArea)o).requirement != null && ((ReplaceArea)o).requirement.required_obj != null) ((ReplaceArea)o).requirement.required_obj.elementChanged(this, null);
} else if (o instanceof RestArea) {
} else if (o instanceof ScriptArea) {
if (((ScriptArea)o).dialogue != null) ((ScriptArea)o).dialogue.elementChanged(this, null);
} else if (o instanceof SignArea) {
if (((SignArea)o).dialogue != null) ((SignArea)o).dialogue.elementChanged(this, null);
} else if (o instanceof SpawnArea) {
if (((SpawnArea)o).spawnGroup != null) {
for (NPC n : ((SpawnArea)o).spawnGroup) {
n.elementChanged(this, null);
}
}
}
}
}
groups.clear();
outside = null;
colorFilter = null;
state = GameDataElement.State.init;
this.link();
changedOnDisk = false;
for (MapChangedOnDiskListener l : listeners) {
l.mapReloaded();
}
}
public void mapChangedOnDisk() {
if (dismissNextChangeNotif > 0) {
dismissNextChangeNotif--;
} else {
changedOnDisk = true;
for (MapChangedOnDiskListener l : listeners) {
l.mapChanged();
}
}
}
public interface MapChangedOnDiskListener {
public void mapChanged();
public void mapReloaded();
}
private List<MapChangedOnDiskListener> listeners = new CopyOnWriteArrayList<TMXMap.MapChangedOnDiskListener>();
public void addMapChangedOnDiskListener(MapChangedOnDiskListener l) {
listeners.add(l);
}
public void removeMapChangedOnDiskListener(MapChangedOnDiskListener l) {
listeners.remove(l);
}
}

View File

@@ -3,9 +3,14 @@ package com.gpl.rpg.atcontentstudio.model.maps;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -23,6 +28,7 @@ import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.model.sprites.SpriteSheetSet;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.utils.FileUtils;
public class TMXMapSet implements ProjectTreeNode {
@@ -50,15 +56,7 @@ public class TMXMapSet implements ProjectTreeNode {
if (!this.mapFolder.exists()) {
this.mapFolder.mkdirs();
}
Path target = Paths.get(getProject().baseContent.gameSprites.drawableFolder.getAbsolutePath());
Path link = Paths.get(new File(mapFolder.getAbsolutePath()+File.separator+DEFAULT_REL_PATH_TO_DRAWABLE).getAbsolutePath());
if (!Files.exists(link)) {
try {
Files.createSymbolicLink(link, target);
} catch (IOException e) {
e.printStackTrace();
}
}
FileUtils.makeSymlink(getProject().baseContent.gameSprites.drawableFolder, new File(mapFolder.getAbsolutePath()+File.separator+DEFAULT_REL_PATH_TO_DRAWABLE));
}
this.tmxMaps = new ArrayList<TMXMap>();
@@ -94,6 +92,43 @@ public class TMXMapSet implements ProjectTreeNode {
return o1.id.compareTo(o2.id);
}
});
if (source.type == GameSource.Type.created | source.type == GameSource.Type.altered) {
final Path folderPath = Paths.get(mapFolder.getAbsolutePath());
Thread watcher = new Thread("Map folder watcher for "+source.type) {
public void run() {
WatchService watchService;
while(getProject().open) {
try {
watchService = FileSystems.getDefault().newWatchService();
WatchKey watchKey = folderPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
WatchKey wk;
validService: while(getProject().open) {
wk = watchService.take();
for (WatchEvent<?> event : wk.pollEvents()) {
Path changed = (Path) event.context();
String name = changed.getFileName().toString();
String id = name.substring(0, name.length() - 4);
TMXMap map = getMap(id);
if (map != null) {
map.mapChangedOnDisk();
}
}
if(!wk.reset()) {
watchService.close();
break validService;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
};
watcher.start();
}
}
@Override

View File

@@ -103,7 +103,7 @@ public class WorldmapSegment extends GameDataElement {
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
oldOne.removeBacklink(this);
newOne.addBacklink(this);
if(newOne != null) newOne.addBacklink(this);
}
@Override

View File

@@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import javax.swing.AbstractListModel;
@@ -681,7 +682,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
return null;
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {

View File

@@ -10,6 +10,7 @@ import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
@@ -518,7 +519,7 @@ public class JSONCreationWizard extends JDialog {
return DataType.values()[index];
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -584,7 +585,7 @@ public class JSONCreationWizard extends JDialog {
public void elementCreated(JSONElement created);
}
private List<CreationCompletedListener> listeners = new ArrayList<JSONCreationWizard.CreationCompletedListener>();
private List<CreationCompletedListener> listeners = new CopyOnWriteArrayList<JSONCreationWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);

View File

@@ -15,6 +15,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
@@ -603,7 +604,7 @@ public class JSONImportWizard extends JDialog {
return null;
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -639,7 +640,7 @@ public class JSONImportWizard extends JDialog {
return DataType.values()[index];
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {

View File

@@ -8,6 +8,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
@@ -101,7 +102,7 @@ public class NotificationsPane extends JList {
}
}
private List<ListDataListener> listeners = new ArrayList<ListDataListener>();
private List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);

View File

@@ -11,6 +11,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
@@ -55,7 +56,7 @@ public class ProjectCreationWizard extends JDialog {
atSourceSelectionCombo = new JComboBox<String>();
resourceSetToUse = new JComboBox<Project.ResourceSet>(new ComboBoxModel<Project.ResourceSet>() {
Project.ResourceSet selected = Project.ResourceSet.allFiles;
Project.ResourceSet selected = Project.ResourceSet.gameData;
@Override
public int getSize() {
@@ -67,7 +68,7 @@ public class ProjectCreationWizard extends JDialog {
return Project.ResourceSet.values()[index];
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {

View File

@@ -11,6 +11,7 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
@@ -202,6 +203,10 @@ public class ProjectsTree extends JPanel {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.importJSON));
}
if (actions.createMap.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.createMap));
}
if (actions.createWorldmap.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.createWorldmap));
@@ -651,7 +656,7 @@ public class ProjectsTree extends JPanel {
return ((ProjectTreeNode)parent).getIndex((ProjectTreeNode) child);
}
List<TreeModelListener> listeners = new ArrayList<TreeModelListener>();
List<TreeModelListener> listeners = new CopyOnWriteArrayList<TreeModelListener>();
@Override
public void addTreeModelListener(TreeModelListener l) {

View File

@@ -129,6 +129,8 @@ public class StudioFrame extends JFrame {
fileMenu.add(new JMenuItem(actions.closeProject));
fileMenu.add(new JMenuItem(actions.deleteProject));
fileMenu.add(new JSeparator());
fileMenu.add(new JMenuItem(actions.editWorkspaceSettings));
fileMenu.add(new JSeparator());
fileMenu.add(new JMenuItem(actions.exitATCS));
getJMenuBar().add(fileMenu);
@@ -138,6 +140,7 @@ public class StudioFrame extends JFrame {
projectMenu.add(new JSeparator());
projectMenu.add(new JMenuItem(actions.createGDE));
projectMenu.add(new JMenuItem(actions.importJSON));
projectMenu.add(new JMenuItem(actions.createMap));
projectMenu.add(new JMenuItem(actions.createWorldmap));
projectMenu.add(new JMenuItem(actions.loadSave));
getJMenuBar().add(projectMenu);

View File

@@ -0,0 +1,300 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement.State;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.jidesoft.swing.JideBoxLayout;
public class TMXMapCreationWizard extends JDialog {
private static final long serialVersionUID = -474689694453543575L;
private static final String DEFAULT_TEMPLATE = "template.tmx";
private TMXMap creation = null;
final File templateFile;
final JLabel message;
final JRadioButton useTemplate, copyMap;
final JComboBox<TMXMap> templateCombo;
final JTextField idField;
final JButton ok;
final Project proj;
@SuppressWarnings({ "unchecked", "rawtypes" })
public TMXMapCreationWizard(final Project proj) {
super(ATContentStudio.frame);
this.proj = proj;
templateFile=new File(proj.baseContent.gameMaps.mapFolder, DEFAULT_TEMPLATE);
setTitle("Create new TMX map");
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
pane.add(new JLabel("Create a new TMX map."), JideBoxLayout.FIX);
message = new JLabel("Enter new map name:");
pane.add(message, JideBoxLayout.FIX);
final JPanel idPane = new JPanel();
idPane.setLayout(new BorderLayout());
JLabel idLabel = new JLabel("Internal ID: ");
idPane.add(idLabel, BorderLayout.WEST);
idField = new JTextField("");
idField.setEditable(true);
idPane.add(idField, BorderLayout.CENTER);
pane.add(idPane, JideBoxLayout.FIX);
useTemplate = new JRadioButton("Use default template file ("+DEFAULT_TEMPLATE+")");
useTemplate.setToolTipText(templateFile.getAbsolutePath());
pane.add(useTemplate, JideBoxLayout.FIX);
copyMap = new JRadioButton("Copy existing map");
pane.add(copyMap, JideBoxLayout.FIX);
ButtonGroup radioGroup = new ButtonGroup();
radioGroup.add(useTemplate);
radioGroup.add(copyMap);
final JPanel templatePane = new JPanel();
templatePane.setLayout(new BorderLayout());
JLabel templateLabel = new JLabel("Template to copy: ");
templatePane.add(templateLabel, BorderLayout.WEST);
templateCombo = new JComboBox(new TemplateComboModel());
templateCombo.setRenderer(new TemplateComboCellRenderer());
if (proj.getMap(DEFAULT_TEMPLATE) != null) templateCombo.setSelectedItem(proj.getMap(DEFAULT_TEMPLATE));
templatePane.add(templateCombo, BorderLayout.CENTER);
pane.add(templatePane, JideBoxLayout.FIX);
pane.add(templateCombo);
if (templateFile.exists()) {
useTemplate.setSelected(true);
copyMap.setSelected(false);
templateCombo.setEnabled(false);
} else {
useTemplate.setSelected(false);
useTemplate.setEnabled(false);
useTemplate.setToolTipText("Cannot find file "+templateFile.getAbsolutePath());
templateCombo.setEnabled(true);
copyMap.setSelected(true);
}
ActionListener radioListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (useTemplate.isSelected()) {
templateCombo.setEnabled(false);
} else if(copyMap.isSelected()) {
templateCombo.setEnabled(true);
}
updateStatus();
}
};
useTemplate.addActionListener(radioListener);
copyMap.addActionListener(radioListener);
templateCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateStatus();
}
});
pane.add(new JPanel(), JideBoxLayout.VARY);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton cancel = new JButton("Cancel");
buttonPane.add(cancel, JideBoxLayout.FIX);
ok = new JButton("Ok");
buttonPane.add(ok, JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (copyMap.isSelected()) {
creation = ((TMXMap)templateCombo.getSelectedItem()).clone();
} else if (useTemplate.isSelected()) {
creation = new TMXMap(proj.createdContent.gameMaps, templateFile);
creation.parse();
}
creation.id = idField.getText();
creation.tmxFile = new File(creation.id+".tmx");
TMXMapCreationWizard.this.setVisible(false);
TMXMapCreationWizard.this.dispose();
creation.state = State.created;
proj.createElement(creation);
notifyCreated();
ATContentStudio.frame.selectInTree(creation);
ATContentStudio.frame.openEditor(creation);
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
creation = null;
TMXMapCreationWizard.this.setVisible(false);
TMXMapCreationWizard.this.dispose();
}
});
DocumentListener statusUpdater = new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void insertUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateStatus();
}
};
idField.getDocument().addDocumentListener(statusUpdater);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(350,250));
updateStatus();
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
public void updateStatus() {
boolean trouble = false;
message.setText("<html><font color=\"#00AA00\">Looks OK to me.</font></html>");
if (copyMap.isSelected() && templateCombo.getSelectedItem() == null) {
message.setText("<html><font color=\"#FF0000\">Select a map template below:</font></html>");
trouble = true;
} else if (idField.getText() == null || idField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">Internal ID must not be empty.</font></html>");
trouble = true;
} else if (proj.getMap(idField.getText()) != null) {
if (proj.getMap(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A map with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getMap(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A map with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getMap(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A map with the same ID exists in the game. The new one will be added under \"altered\".</font></html>");
}
}
ok.setEnabled(!trouble);
message.revalidate();
message.repaint();
}
public static interface CreationCompletedListener {
public void mapCreated(TMXMap created);
}
private List<CreationCompletedListener> listeners = new CopyOnWriteArrayList<TMXMapCreationWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);
}
public void notifyCreated() {
for (CreationCompletedListener l : listeners) {
l.mapCreated(creation);
}
}
class TemplateComboModel implements ComboBoxModel<TMXMap> {
Object selected;
@Override
public int getSize() {
return proj.getMapCount();
}
@Override
public TMXMap getElementAt(int index) {
return proj.getMap(index);
}
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
@Override
public void setSelectedItem(Object anItem) {
selected = anItem;
}
@Override
public Object getSelectedItem() {
return selected;
}
}
class TemplateComboCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 5621373849299980998L;
@Override
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel && value != null) {
((JLabel)c).setText(((TMXMap)value).getDesc());
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getTiledIconIcon()));
}
return c;
}
}
}

View File

@@ -12,6 +12,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.Action;
import javax.swing.JFileChooser;
@@ -226,7 +228,16 @@ public class WorkspaceActions {
}
};
public ATCSAction createMap = new ATCSAction("Create TMX Map", "Opens the TMX Map creation wizard") {
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
new TMXMapCreationWizard(selectedNode.getProject()).setVisible(true);
}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
}
};
public ATCSAction createWorldmap = new ATCSAction("Create Worldmap segment", "Opens the worldmap segment creation wizard") {
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
@@ -370,6 +381,15 @@ public class WorkspaceActions {
}
};
public ATCSAction editWorkspaceSettings = new ATCSAction("Edit Workspace Settings", "Change the preferences of this workspace.") {
public void actionPerformed(ActionEvent e) {
new WorkspaceSettingsEditor(Workspace.activeWorkspace.settings);
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(true);
};
};
List<ATCSAction> actions = new ArrayList<WorkspaceActions.ATCSAction>();
public WorkspaceActions() {
@@ -380,6 +400,7 @@ public class WorkspaceActions {
actions.add(saveElement);
actions.add(deleteSelected);
actions.add(createGDE);
actions.add(createMap);
actions.add(importJSON);
actions.add(loadSave);
actions.add(compareItems);
@@ -390,6 +411,7 @@ public class WorkspaceActions {
actions.add(testWriter);
// actions.add(testCommitWriter);
actions.add(createWriter);
actions.add(editWorkspaceSettings);
selectionChanged(null, null);
}
@@ -432,10 +454,8 @@ public class WorkspaceActions {
public void putValue(String key, Object value) {
PropertyChangeEvent event = new PropertyChangeEvent(this, key, values.get(key), value);
values.put(key, value);
synchronized(listeners) {
for (PropertyChangeListener l : listeners) {
l.propertyChange(event);
}
for (PropertyChangeListener l : listeners) {
l.propertyChange(event);
}
}
@@ -443,10 +463,8 @@ public class WorkspaceActions {
public void setEnabled(boolean b) {
PropertyChangeEvent event = new PropertyChangeEvent(this, "enabled", isEnabled(), b);
enabled = b;
synchronized(listeners) {
for (PropertyChangeListener l : listeners) {
l.propertyChange(event);
}
for (PropertyChangeListener l : listeners) {
l.propertyChange(event);
}
}
@@ -455,20 +473,16 @@ public class WorkspaceActions {
return enabled;
}
private Set<PropertyChangeListener> listeners = new HashSet<PropertyChangeListener>();
private List<PropertyChangeListener> listeners = new CopyOnWriteArrayList<PropertyChangeListener>();
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
synchronized(listeners) {
listeners.add(listener);
}
listeners.add(listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
synchronized(listeners) {
listeners.remove(listener);
}
listeners.remove(listener);
}
}

View File

@@ -0,0 +1,180 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.WorkspaceSettings;
import com.jidesoft.swing.JideBoxLayout;
public class WorkspaceSettingsEditor extends JDialog {
private static final long serialVersionUID = -1326158719217162879L;
WorkspaceSettings settings;
JRadioButton useSystemDefaultMapEditorButton, useCustomMapEditorButton;
JTextField mapEditorCommandField;
JRadioButton useSystemDefaultImageViewerButton, useSystemDefaultImageEditorButton, useCustomImageEditorButton;
JTextField imageEditorCommandField;
public WorkspaceSettingsEditor(WorkspaceSettings settings) {
super(ATContentStudio.frame, "Workspace settings", true);
setIconImage(DefaultIcons.getMainIconImage());
this.settings = settings;
JPanel pane = new JPanel();
getContentPane().setLayout(new BorderLayout());
getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS));
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
pane.add(getExternalToolsPane(), JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton ok = new JButton("Ok");
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
pushToModel();
dispose();
}
});
buttonPane.add(ok, JideBoxLayout.FIX);
JButton reset = new JButton("Reset to defaults");
reset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
resetDefaults();
}
});
buttonPane.add(reset, JideBoxLayout.FIX);
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
buttonPane.add(cancel, JideBoxLayout.FIX);
loadFromModel();
pack();
setVisible(true);
}
public JPanel getExternalToolsPane() {
CollapsiblePanel pane = new CollapsiblePanel("External tools");
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS));
//Tiled
CollapsiblePanel tiledPane = new CollapsiblePanel("TMX Map viewer/editor");
tiledPane.setLayout(new JideBoxLayout(tiledPane, JideBoxLayout.PAGE_AXIS));
ButtonGroup tiledRadioGroup = new ButtonGroup();
useSystemDefaultMapEditorButton = new JRadioButton("Use system-default TMX Map editor");
tiledRadioGroup.add(useSystemDefaultMapEditorButton);
tiledPane.add(useSystemDefaultMapEditorButton, JideBoxLayout.FIX);
useCustomMapEditorButton = new JRadioButton("Use custom command to open TMX Map files");
tiledRadioGroup.add(useCustomMapEditorButton);
tiledPane.add(useCustomMapEditorButton, JideBoxLayout.FIX);
mapEditorCommandField = new JTextField();
tiledPane.add(mapEditorCommandField, JideBoxLayout.FIX);
ActionListener tiledRadioListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (useSystemDefaultMapEditorButton.equals(e.getSource())) {
mapEditorCommandField.setEnabled(false);
} else if (useCustomMapEditorButton.equals(e.getSource())) {
mapEditorCommandField.setEnabled(true);
}
}
};
useSystemDefaultMapEditorButton.addActionListener(tiledRadioListener);
useCustomMapEditorButton.addActionListener(tiledRadioListener);
pane.add(tiledPane, JideBoxLayout.FIX);
//Images
CollapsiblePanel imgPane = new CollapsiblePanel("Image viewer/editor");
imgPane.setLayout(new JideBoxLayout(imgPane, JideBoxLayout.PAGE_AXIS));
ButtonGroup imgRadioGroup = new ButtonGroup();
useSystemDefaultImageViewerButton = new JRadioButton("Use system-default image viewer");
imgRadioGroup.add(useSystemDefaultImageViewerButton);
imgPane.add(useSystemDefaultImageViewerButton, JideBoxLayout.FIX);
useSystemDefaultImageEditorButton = new JRadioButton("Use system-default image editor");
imgRadioGroup.add(useSystemDefaultImageEditorButton);
imgPane.add(useSystemDefaultImageEditorButton, JideBoxLayout.FIX);
useCustomImageEditorButton = new JRadioButton("Use custom command to open images");
imgRadioGroup.add(useCustomImageEditorButton);
imgPane.add(useCustomImageEditorButton, JideBoxLayout.FIX);
imageEditorCommandField = new JTextField();
imgPane.add(imageEditorCommandField, JideBoxLayout.FIX);
ActionListener imgRadioListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (useSystemDefaultMapEditorButton.equals(e.getSource())) {
imageEditorCommandField.setEnabled(false);
} else if (useSystemDefaultImageViewerButton.equals(e.getSource())) {
imageEditorCommandField.setEnabled(false);
} else if (useCustomImageEditorButton.equals(e.getSource())) {
imageEditorCommandField.setEnabled(true);
}
}
};
useSystemDefaultImageViewerButton.addActionListener(imgRadioListener);
useSystemDefaultImageEditorButton.addActionListener(imgRadioListener);
useCustomImageEditorButton.addActionListener(imgRadioListener);
pane.add(imgPane, JideBoxLayout.FIX);
pane.expand();
return pane;
}
public void loadFromModel() {
//Tiled
useSystemDefaultMapEditorButton.setSelected(settings.useSystemDefaultMapEditor.getCurrentValue());
useCustomMapEditorButton.setSelected(!settings.useSystemDefaultMapEditor.getCurrentValue());
mapEditorCommandField.setText(settings.mapEditorCommand.getCurrentValue());
//Images
useSystemDefaultImageViewerButton.setSelected(settings.useSystemDefaultImageViewer.getCurrentValue());
useSystemDefaultImageEditorButton.setSelected(settings.useSystemDefaultImageEditor.getCurrentValue());
useCustomImageEditorButton.setSelected(!(settings.useSystemDefaultImageViewer.getCurrentValue() || settings.useSystemDefaultImageEditor.getCurrentValue()));
imageEditorCommandField.setText(settings.imageEditorCommand.getCurrentValue());
}
public void pushToModel() {
//Tiled
settings.useSystemDefaultMapEditor.setCurrentValue(useSystemDefaultMapEditorButton.isSelected());
settings.mapEditorCommand.setCurrentValue(mapEditorCommandField.getText());
//Images
settings.useSystemDefaultImageViewer.setCurrentValue(useSystemDefaultImageViewerButton.isSelected());
settings.useSystemDefaultImageEditor.setCurrentValue(useSystemDefaultImageEditorButton.isSelected());
settings.imageEditorCommand.setCurrentValue(imageEditorCommandField.getText());
settings.save();
}
public void resetDefaults() {
settings.resetDefault();
settings.save();
loadFromModel();
}
}

View File

@@ -7,6 +7,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.JButton;
import javax.swing.JDialog;
@@ -144,7 +145,7 @@ public class WorldmapCreationWizard extends JDialog {
public void segmentCreated(WorldmapSegment created);
}
private List<CreationCompletedListener> listeners = new ArrayList<WorldmapCreationWizard.CreationCompletedListener>();
private List<CreationCompletedListener> listeners = new CopyOnWriteArrayList<WorldmapCreationWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);

View File

@@ -7,6 +7,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.JButton;
import javax.swing.JDialog;
@@ -176,7 +177,7 @@ public class WorldmapLabelEditionWizard extends JDialog {
public void labelCreated(WorldmapSegment.NamedArea created);
}
private List<CreationCompletedListener> listeners = new ArrayList<WorldmapLabelEditionWizard.CreationCompletedListener>();
private List<CreationCompletedListener> listeners = new CopyOnWriteArrayList<WorldmapLabelEditionWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);

View File

@@ -12,6 +12,7 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
@@ -752,7 +753,7 @@ public class DialogueEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -917,7 +918,7 @@ public class DialogueEditor extends JSONElementEditor {
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -1031,7 +1032,7 @@ public class DialogueEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {

View File

@@ -5,6 +5,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
@@ -196,7 +197,7 @@ public class DroplistEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {

View File

@@ -5,7 +5,9 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
@@ -14,6 +16,7 @@ import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
@@ -97,6 +100,8 @@ public class ItemEditor extends JSONElementEditor {
@SuppressWarnings("rawtypes")
private JList hitSourceConditionsList;
private MyComboBox hitSourceConditionBox;
private JRadioButton hitSourceConditionClear;
private JRadioButton hitSourceConditionApply;
private JSpinner hitSourceConditionMagnitude;
private JSpinner hitSourceConditionDuration;
private JSpinner hitSourceConditionChance;
@@ -104,6 +109,8 @@ public class ItemEditor extends JSONElementEditor {
@SuppressWarnings("rawtypes")
private JList hitTargetConditionsList;
private MyComboBox hitTargetConditionBox;
private JRadioButton hitTargetConditionClear;
private JRadioButton hitTargetConditionApply;
private JSpinner hitTargetConditionMagnitude;
private JSpinner hitTargetConditionDuration;
private JSpinner hitTargetConditionChance;
@@ -118,6 +125,8 @@ public class ItemEditor extends JSONElementEditor {
@SuppressWarnings("rawtypes")
private JList killSourceConditionsList;
private MyComboBox killSourceConditionBox;
private JRadioButton killSourceConditionClear;
private JRadioButton killSourceConditionApply;
private JSpinner killSourceConditionMagnitude;
private JSpinner killSourceConditionDuration;
private JSpinner killSourceConditionChance;
@@ -460,55 +469,169 @@ public class ItemEditor extends JSONElementEditor {
}
public void updateHitSourceTimedConditionEditorPane(JPanel pane, Item.TimedConditionEffect condition, FieldUpdateListener listener) {
public void updateHitSourceTimedConditionEditorPane(JPanel pane, Item.TimedConditionEffect condition, final FieldUpdateListener listener) {
pane.removeAll();
if (hitSourceConditionBox != null) {
removeElementListener(hitSourceConditionBox);
}
if (condition == null) {
pane.revalidate();
pane.repaint();
return;
}
boolean writable = ((Item)target).writable;
Project proj = ((Item)target).getProject();
hitSourceConditionBox = addActorConditionBox(pane, proj, "Actor Condition: ", condition.condition, writable, listener);
hitSourceConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude, false, writable, listener);
hitSourceConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
hitSourceConditionChance = addDoubleField(pane, "Chance: ", condition.chance, writable, listener);
hitSourceConditionApply = new JRadioButton("Apply new condition");
pane.add(hitSourceConditionApply, JideBoxLayout.FIX);
hitSourceConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude == null ? null : condition.magnitude >= 0 ? condition.magnitude : 0, false, writable, listener);
hitSourceConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
hitSourceConditionClear = new JRadioButton("Clear active condition");
pane.add(hitSourceConditionClear, JideBoxLayout.FIX);
ButtonGroup radioGroup = new ButtonGroup();
radioGroup.add(hitSourceConditionApply);
radioGroup.add(hitSourceConditionClear);
if (condition != null && condition.magnitude != null && condition.magnitude == ActorCondition.CLEAR_AC_MAGNITUDE) {
hitSourceConditionClear.setSelected(true);
hitSourceConditionApply.setSelected(false);
hitSourceConditionMagnitude.setEnabled(false);
hitSourceConditionDuration.setEnabled(false);
} else {
hitSourceConditionClear.setSelected(false);
hitSourceConditionApply.setSelected(true);
hitSourceConditionMagnitude.setEnabled(true);
hitSourceConditionDuration.setEnabled(true);
}
hitSourceConditionClear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(hitSourceConditionClear, new Boolean(hitSourceConditionClear.isSelected()));
}
});
hitSourceConditionApply.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(hitSourceConditionApply, new Boolean(hitSourceConditionApply.isSelected()));
}
});
pane.revalidate();
pane.repaint();
}
public void updateHitTargetTimedConditionEditorPane(JPanel pane, Item.TimedConditionEffect condition, FieldUpdateListener listener) {
public void updateHitTargetTimedConditionEditorPane(JPanel pane, Item.TimedConditionEffect condition, final FieldUpdateListener listener) {
pane.removeAll();
if (hitTargetConditionBox != null) {
removeElementListener(hitTargetConditionBox);
}
if (condition == null) {
pane.revalidate();
pane.repaint();
return;
}
boolean writable = ((Item)target).writable;
Project proj = ((Item)target).getProject();
hitTargetConditionBox = addActorConditionBox(pane, proj, "Actor Condition: ", condition.condition, writable, listener);
hitTargetConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude, false, writable, listener);
hitTargetConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
hitTargetConditionChance = addDoubleField(pane, "Chance: ", condition.chance, writable, listener);
hitTargetConditionApply = new JRadioButton("Apply new condition");
pane.add(hitTargetConditionApply, JideBoxLayout.FIX);
hitTargetConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude == null ? null : condition.magnitude >= 0 ? condition.magnitude : 0, false, writable, listener);
hitTargetConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
hitTargetConditionClear = new JRadioButton("Clear active condition");
pane.add(hitTargetConditionClear, JideBoxLayout.FIX);
ButtonGroup radioGroup = new ButtonGroup();
radioGroup.add(hitTargetConditionApply);
radioGroup.add(hitTargetConditionClear);
if (condition != null && condition.magnitude != null && condition.magnitude == ActorCondition.CLEAR_AC_MAGNITUDE) {
hitTargetConditionClear.setSelected(true);
hitTargetConditionApply.setSelected(false);
hitTargetConditionMagnitude.setEnabled(false);
hitTargetConditionDuration.setEnabled(false);
} else {
hitTargetConditionClear.setSelected(false);
hitTargetConditionApply.setSelected(true);
hitTargetConditionMagnitude.setEnabled(true);
hitTargetConditionDuration.setEnabled(true);
}
hitTargetConditionClear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(hitTargetConditionClear, new Boolean(hitTargetConditionClear.isSelected()));
}
});
hitTargetConditionApply.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(hitTargetConditionApply, new Boolean(hitTargetConditionApply.isSelected()));
}
});
pane.revalidate();
pane.repaint();
}
public void updateKillSourceTimedConditionEditorPane(JPanel pane, Item.TimedConditionEffect condition, FieldUpdateListener listener) {
public void updateKillSourceTimedConditionEditorPane(JPanel pane, Item.TimedConditionEffect condition, final FieldUpdateListener listener) {
pane.removeAll();
if (killSourceConditionBox != null) {
removeElementListener(killSourceConditionBox);
}
if (condition == null) {
pane.revalidate();
pane.repaint();
return;
}
boolean writable = ((Item)target).writable;
Project proj = ((Item)target).getProject();
killSourceConditionBox = addActorConditionBox(pane, proj, "Actor Condition: ", condition.condition, writable, listener);
killSourceConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude, false, writable, listener);
killSourceConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
killSourceConditionChance = addDoubleField(pane, "Chance: ", condition.chance, writable, listener);
killSourceConditionApply = new JRadioButton("Apply new condition");
pane.add(killSourceConditionApply, JideBoxLayout.FIX);
killSourceConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude == null ? null : condition.magnitude >= 0 ? condition.magnitude : 0, false, writable, listener);
killSourceConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
killSourceConditionClear = new JRadioButton("Clear active condition");
pane.add(killSourceConditionClear, JideBoxLayout.FIX);
ButtonGroup radioGroup = new ButtonGroup();
radioGroup.add(killSourceConditionApply);
radioGroup.add(killSourceConditionClear);
if (condition != null && condition.magnitude != null && condition.magnitude == ActorCondition.CLEAR_AC_MAGNITUDE) {
killSourceConditionClear.setSelected(true);
killSourceConditionApply.setSelected(false);
killSourceConditionMagnitude.setEnabled(false);
killSourceConditionDuration.setEnabled(false);
} else {
killSourceConditionClear.setSelected(false);
killSourceConditionApply.setSelected(true);
killSourceConditionMagnitude.setEnabled(true);
killSourceConditionDuration.setEnabled(true);
}
killSourceConditionClear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(killSourceConditionClear, new Boolean(killSourceConditionClear.isSelected()));
}
});
killSourceConditionApply.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(killSourceConditionApply, new Boolean(killSourceConditionApply.isSelected()));
}
});
pane.revalidate();
pane.repaint();
}
@@ -518,6 +641,11 @@ public class ItemEditor extends JSONElementEditor {
if (equipConditionBox != null) {
removeElementListener(equipConditionBox);
}
if (condition == null) {
pane.revalidate();
pane.repaint();
return;
}
boolean writable = ((Item)target).writable;
Project proj = ((Item)target).getProject();
@@ -578,7 +706,7 @@ public class ItemEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -640,7 +768,7 @@ public class ItemEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -665,7 +793,11 @@ public class ItemEditor extends JSONElementEditor {
if (effect.condition != null) {
label.setIcon(new ImageIcon(effect.condition.getIcon()));
label.setText(effect.chance+"% chances to give "+effect.duration+" rounds of "+effect.condition.getDesc()+" x"+effect.magnitude);
if (effect.magnitude == ActorCondition.CLEAR_AC_MAGNITUDE) {
label.setText(effect.chance+"% chances to clear "+effect.condition.getDesc());
} else {
label.setText(effect.chance+"% chances to give "+effect.duration+" rounds of "+effect.condition.getDesc()+" x"+effect.magnitude);
}
} else {
label.setText("New, undefined actor condition effect.");
}
@@ -723,7 +855,7 @@ public class ItemEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -983,6 +1115,20 @@ public class ItemEditor extends JSONElementEditor {
}
hitSourceConditionsModel.itemChanged(selectedHitEffectSourceCondition);
updateHit = true;
} else if (source == hitSourceConditionClear) {
selectedHitEffectSourceCondition.magnitude = ActorCondition.CLEAR_AC_MAGNITUDE;
selectedHitEffectSourceCondition.duration = null;
hitSourceConditionMagnitude.setEnabled(false);
hitSourceConditionDuration.setEnabled(false);
hitSourceConditionsModel.itemChanged(selectedHitEffectSourceCondition);
updateHit = true;
} else if (source == hitSourceConditionApply) {
selectedHitEffectSourceCondition.magnitude = 0;
selectedHitEffectSourceCondition.duration = 0;
hitSourceConditionMagnitude.setEnabled(true);
hitSourceConditionDuration.setEnabled(true);
hitSourceConditionsModel.itemChanged(selectedHitEffectSourceCondition);
updateHit = true;
} else if (source == hitSourceConditionMagnitude) {
selectedHitEffectSourceCondition.magnitude = (Integer) value;
hitSourceConditionsModel.itemChanged(selectedHitEffectSourceCondition);
@@ -1010,6 +1156,20 @@ public class ItemEditor extends JSONElementEditor {
}
hitTargetConditionsModel.itemChanged(selectedHitEffectTargetCondition);
updateHit = true;
} else if (source == hitTargetConditionClear) {
selectedHitEffectTargetCondition.magnitude = ActorCondition.CLEAR_AC_MAGNITUDE;
selectedHitEffectTargetCondition.duration = null;
hitTargetConditionMagnitude.setEnabled(false);
hitTargetConditionDuration.setEnabled(false);
hitTargetConditionsModel.itemChanged(selectedHitEffectTargetCondition);
updateHit = true;
} else if (source == hitTargetConditionApply) {
selectedHitEffectTargetCondition.magnitude = 0;
selectedHitEffectTargetCondition.duration = 0;
hitTargetConditionMagnitude.setEnabled(true);
hitTargetConditionDuration.setEnabled(true);
hitTargetConditionsModel.itemChanged(selectedHitEffectTargetCondition);
updateHit = true;
} else if (source == hitTargetConditionMagnitude) {
selectedHitEffectTargetCondition.magnitude = (Integer) value;
hitTargetConditionsModel.itemChanged(selectedHitEffectTargetCondition);
@@ -1053,6 +1213,20 @@ public class ItemEditor extends JSONElementEditor {
}
killSourceConditionsModel.itemChanged(selectedKillEffectCondition);
updateKill = true;
} else if (source == killSourceConditionClear) {
selectedKillEffectCondition.magnitude = ActorCondition.CLEAR_AC_MAGNITUDE;
selectedKillEffectCondition.duration = null;
killSourceConditionMagnitude.setEnabled(false);
killSourceConditionDuration.setEnabled(false);
killSourceConditionsModel.itemChanged(selectedKillEffectCondition);
updateKill = true;
} else if (source == killSourceConditionApply) {
selectedKillEffectCondition.magnitude = 0;
selectedKillEffectCondition.duration = 0;
killSourceConditionMagnitude.setEnabled(true);
killSourceConditionDuration.setEnabled(true);
killSourceConditionsModel.itemChanged(selectedKillEffectCondition);
updateKill = true;
} else if (source == killSourceConditionMagnitude) {
selectedKillEffectCondition.magnitude = (Integer) value;
killSourceConditionsModel.itemChanged(selectedKillEffectCondition);

View File

@@ -6,6 +6,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
@@ -397,7 +398,7 @@ public class NPCEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -459,7 +460,7 @@ public class NPCEditor extends JSONElementEditor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {

View File

@@ -6,6 +6,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
@@ -293,7 +294,7 @@ public class QuestEditor extends JSONElementEditor {
if (quest.stages.isEmpty()) quest.stages = null;
}
public List<TableModelListener> listeners = new ArrayList<TableModelListener>();
public List<TableModelListener> listeners = new CopyOnWriteArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {

View File

@@ -18,11 +18,12 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.io.IOException;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
@@ -35,6 +36,7 @@ import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
@@ -99,16 +101,20 @@ import com.gpl.rpg.atcontentstudio.ui.Editor;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.gpl.rpg.atcontentstudio.ui.IntegerBasedCheckBox;
import com.gpl.rpg.atcontentstudio.ui.ScrollablePanel;
import com.gpl.rpg.atcontentstudio.utils.DesktopIntegration;
import com.gpl.rpg.atcontentstudio.utils.FileUtils;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideTabbedPane;
public class TMXMapEditor extends Editor {
public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListener{
private static final long serialVersionUID = -3079451876618342442L;
Map<String, JPanel> editorTabs = new LinkedHashMap<String, JPanel>();
JideTabbedPane editorTabsHolder;
private JButton reload;
private RSyntaxTextArea editorPane;
@@ -125,7 +131,7 @@ public class TMXMapEditor extends Editor {
private JPanel layerDetailsPane;
private BooleanBasedCheckBox layerVisibleBox;
//private BooleanBasedCheckBox activeLayerBox;
private JCheckBox groupActiveForNewGame;
private JTextField layerNameField;
private MapObjectsListModel groupObjectsListModel;
@SuppressWarnings("rawtypes")
@@ -154,7 +160,7 @@ public class TMXMapEditor extends Editor {
@SuppressWarnings("rawtypes")
private JComboBox evaluateTriggerBox;
private JSpinner quantityField;
private JCheckBox activeForNewGame;
private JCheckBox spawnActiveForNewGame;
private JTextField spawngroupField;
@SuppressWarnings("rawtypes")
private JList npcList;
@@ -188,6 +194,7 @@ public class TMXMapEditor extends Editor {
this.name = map.getDesc();
this.icon = new ImageIcon(DefaultIcons.getTiledIconIcon());
map.addMapChangedOnDiskListener(this);
setLayout(new BorderLayout());
editorTabsHolder = new JideTabbedPane(JideTabbedPane.BOTTOM);
@@ -325,7 +332,7 @@ public class TMXMapEditor extends Editor {
break;
}
}
activeForNewGame = addBooleanBasedCheckBox(groupDetailPane, "Active for new game", objGroup.active, map.writable, listener);
groupActiveForNewGame = addBooleanBasedCheckBox(groupDetailPane, "Active for new game", objGroup.active, map.writable, listener);
groupObjectsListModel = new MapObjectsListModel(objGroup);
groupObjectsList = new JList(groupObjectsListModel);
groupObjectsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -569,7 +576,7 @@ public class TMXMapEditor extends Editor {
areaField = addTextField(pane, "Spawn area ID: ", ((SpawnArea)selected).name, ((TMXMap)target).writable, listener);
spawngroupField = addTextField(pane, "Spawn group ID: ", ((SpawnArea)selected).spawngroup_id, ((TMXMap)target).writable, listener);
quantityField = addIntegerField(pane, "Number of spawned NPCs: ", ((SpawnArea)selected).quantity, false, ((TMXMap)target).writable, listener);
activeForNewGame = addBooleanBasedCheckBox(pane, "Active in a new game: ", ((SpawnArea)selected).active, ((TMXMap)target).writable, listener);
spawnActiveForNewGame = addBooleanBasedCheckBox(pane, "Active in a new game: ", ((SpawnArea)selected).active, ((TMXMap)target).writable, listener);
npcListModel = new SpawnGroupNpcListModel((SpawnArea) selected);
npcList = new JList(npcListModel);
npcList.setCellRenderer(new GDERenderer(true, ((TMXMap)target).writable));
@@ -886,7 +893,7 @@ public class TMXMapEditor extends Editor {
return index;
}
List<TreeModelListener> listeners = new ArrayList<TreeModelListener>();
List<TreeModelListener> listeners = new CopyOnWriteArrayList<TreeModelListener>();
@Override
public void addTreeModelListener(TreeModelListener l) {
@@ -995,7 +1002,7 @@ public class TMXMapEditor extends Editor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -1074,7 +1081,7 @@ public class TMXMapEditor extends Editor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -1146,7 +1153,7 @@ public class TMXMapEditor extends Editor {
return availableLayers.size();
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
@@ -1202,7 +1209,7 @@ public class TMXMapEditor extends Editor {
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -1247,7 +1254,7 @@ public class TMXMapEditor extends Editor {
return area.spawnGroup.get(index);
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -1529,7 +1536,7 @@ public class TMXMapEditor extends Editor {
return null;
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -1600,22 +1607,44 @@ public class TMXMapEditor extends Editor {
}
public JButton createButtonPane(JPanel pane, final Project proj, final TMXMap map, final FieldUpdateListener listener) {
final JButton gdeIcon = new JButton(new ImageIcon(DefaultIcons.getTiledIconImage()));
JPanel savePane = new JPanel();
savePane.add(gdeIcon, JideBoxLayout.FIX);
savePane.setLayout(new JideBoxLayout(savePane, JideBoxLayout.LINE_AXIS, 6));
final JButton gdeIcon = new JButton(new ImageIcon(DefaultIcons.getTiledIconImage()));
savePane.add(gdeIcon, JideBoxLayout.FIX);
if (map.writable) {
gdeIcon.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
Runtime.getRuntime().exec(new String[]{"tiled",map.tmxFile.getAbsolutePath()});
} catch (IOException e1) {
e1.printStackTrace();
if (map.state == GameDataElement.State.modified || map.state == GameDataElement.State.created) {
int confirm = JOptionPane.showConfirmDialog(TMXMapEditor.this, "You have unsaved changes in ATCS.\nYou'd better save your changes in ATCS before opening this map with the external editor.\nDo you want to save before opening the file?", "Save before opening?", JOptionPane.YES_NO_CANCEL_OPTION);
if (confirm == JOptionPane.CANCEL_OPTION) return;
if (confirm == JOptionPane.YES_OPTION) {
map.save();
ATContentStudio.frame.nodeChanged(map);
}
}
DesktopIntegration.openTmxMap(map.tmxFile);
}
});
reload = new JButton("Reload");
reload.setEnabled(map.changedOnDisk);
savePane.add(reload, JideBoxLayout.FIX);
reload.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (map.state == GameDataElement.State.modified) {
int confirm = JOptionPane.showConfirmDialog(TMXMapEditor.this, "You modified this map in ATCS. All ATCS-made changes will be lost if you confirm.\n On the other hand, if you save using ATCS, all external changes will be lost.\n Do you want to reload?", "Confirm reload?", JOptionPane.OK_CANCEL_OPTION);
if (confirm == JOptionPane.CANCEL_OPTION) return;
}
reload.setEnabled(false);
(new Thread(){
public void run() {
map.reload();
}
}).start();
}
});
if (map.getDataType() == GameSource.Type.altered) {
savePane.add(message = new JLabel(ALTERED_MESSAGE), JideBoxLayout.FIX);
} else if (map.getDataType() == GameSource.Type.created) {
@@ -1626,6 +1655,16 @@ public class TMXMapEditor extends Editor {
@Override
public void actionPerformed(ActionEvent e) {
if (map.state != TMXMap.State.saved) {
if (map.changedOnDisk) {
int confirm = JOptionPane.showConfirmDialog(TMXMapEditor.this, "You modified this map in an external tool. All external changes will be lost if you confirm.\n On the other hand, if you reload in ATCS, all ATCS-made changes will be lost.\n Do you want to save?", "Confirm save?", JOptionPane.OK_CANCEL_OPTION);
if (confirm == JOptionPane.CANCEL_OPTION) return;
File backup = FileUtils.backupFile(map.tmxFile);
if (backup != null) {
JOptionPane.showMessageDialog(TMXMapEditor.this, "The externally-modified file was backed up as "+backup.getAbsolutePath(), "File backed up", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(TMXMapEditor.this, "The externally-modified file could not be backed up.", "File backup failed", JOptionPane.ERROR_MESSAGE);
}
}
map.save();
ATContentStudio.frame.nodeChanged(map);
}
@@ -1736,9 +1775,9 @@ public class TMXMapEditor extends Editor {
modified = false;
tmxViewer.revalidate();
tmxViewer.repaint();
} else if (source == activeForNewGame) {
} else if (source == groupActiveForNewGame) {
if (selectedLayer instanceof tiled.core.ObjectGroup) {
map.getGroup((tiled.core.ObjectGroup) selectedLayer).active = activeForNewGame.isSelected();
map.getGroup((tiled.core.ObjectGroup) selectedLayer).active = groupActiveForNewGame.isSelected();
}
modified = true;
} else if (source == layerList) {
@@ -1865,7 +1904,7 @@ public class TMXMapEditor extends Editor {
SpawnArea area = (SpawnArea) selectedMapObject;
area.quantity = (Integer) value;
}
} else if (source == activeForNewGame) {
} else if (source == spawnActiveForNewGame) {
if (selectedMapObject instanceof SpawnArea) {
SpawnArea area = (SpawnArea) selectedMapObject;
area.active = (Boolean) value;
@@ -2294,5 +2333,23 @@ public class TMXMapEditor extends Editor {
g2d.fillRect(object.x + 2, object.y + 2, img.getWidth(null), img.getHeight(null));
g2d.drawImage(object.getIcon(), object.x + 2, object.y + 2, null);
}
@Override
public void mapChanged() {
if (reload != null) reload.setEnabled(true);
}
@Override
public void mapReloaded() {
ATContentStudio.frame.nodeChanged(target);
((TMXMap)target).removeMapChangedOnDiskListener(this);
ATContentStudio.frame.closeEditor(target);
ATContentStudio.frame.openEditor(target);
}
}

View File

@@ -35,13 +35,26 @@ public class SpriteChooser extends JDialog {
private static final int MAX_PER_ROW = 10;
public static Map<Project, Map<Spritesheet.Category, SpriteChooser>> cache = new LinkedHashMap<Project, Map<Spritesheet.Category,SpriteChooser>>();
public static Map<Project, Map<Spritesheet.Category, List<Spritesheet>>> cacheValidator = new LinkedHashMap<Project, Map<Category,List<Spritesheet>>>();
public static SpriteChooser getChooser(Project proj, Spritesheet.Category category) {
if (cache.get(proj) == null) {
cache.put(proj, new LinkedHashMap<Spritesheet.Category, SpriteChooser>());
}
if (cache.get(proj).get(category) == null) {
cache.get(proj).put(category, new SpriteChooser(proj, category));
} else {
List<Spritesheet> spritesheets = new ArrayList<Spritesheet>();
for (int i=0; i<proj.getSpritesheetCount(); i++) {
Spritesheet sheet = proj.getSpritesheet(i);
if (sheet.category == category) {
spritesheets.add(sheet);
}
}
if ( !spritesheets.equals(cacheValidator.get(proj).get(category)) ) {
cache.get(proj).put(category, new SpriteChooser(proj, category));
}
}
SpriteChooser wanted = cache.get(proj).get(category);
wanted.group.clearSelection();
@@ -65,11 +78,16 @@ public class SpriteChooser extends JDialog {
setTitle("Select a sprite");
setModalityType(ModalityType.APPLICATION_MODAL);
List<Spritesheet> spritesheets = new ArrayList<Spritesheet>();
for (Spritesheet sheet : proj.baseContent.gameSprites.spritesheets) {
for (int i=0; i<proj.getSpritesheetCount(); i++) {
Spritesheet sheet = proj.getSpritesheet(i);
if (sheet.category == category) {
spritesheets.add(sheet);
}
}
if (cacheValidator.get(proj) == null) {
cacheValidator.put(proj, new LinkedHashMap<Spritesheet.Category, List<Spritesheet>>());
}
cacheValidator.get(proj).put(category, spritesheets);
JPanel pane = new JPanel();

View File

@@ -4,6 +4,8 @@ import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
@@ -13,10 +15,12 @@ import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
@@ -41,8 +45,10 @@ import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.Editor;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.gpl.rpg.atcontentstudio.utils.DesktopIntegration;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideTabbedPane;
@@ -64,8 +70,8 @@ public class SpritesheetEditor extends Editor {
public static JComponent getWarningLabel() {
JLabel label = new JLabel(
"<html><i>" +
"The data presented here is not part of the game.<br/>" +
"What you change here will be changed in your ATCS project.<br/>" +
"The data accompamying the image here is not part of the game.<br/>" +
"What you change here will be changed in your ATCS project only.<br/>" +
"None of this is exported to JSON or TMX, although it must be set correctly in order to choose tiles & icons correctly.<br/>" +
"</i></html>");
return label;
@@ -83,7 +89,19 @@ public class SpritesheetEditor extends Editor {
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
add(getWarningLabel(), JideBoxLayout.FIX);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS));
JButton openImage = new JButton(new ImageIcon(DefaultIcons.getTileLayerImage()));
openImage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DesktopIntegration.openImage(((Spritesheet)target).spritesheetFile);
}
});
buttonPane.add(openImage, JideBoxLayout.FIX);
buttonPane.add(getWarningLabel(), JideBoxLayout.FIX);
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
addLabelField(pane, "Spritesheet ID: ", sheet.id);
addLabelField(pane, "File: ", sheet.spritesheetFile.getAbsolutePath());
widthField = addIntegerField(pane, "Sprite width (px): ", sheet.spriteWidth, false, true, listener);
@@ -242,7 +260,7 @@ public class SpritesheetEditor extends Editor {
}
List<TableModelListener> listeners = new ArrayList<TableModelListener>();
List<TableModelListener> listeners = new CopyOnWriteArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {
@@ -341,7 +359,7 @@ public class SpritesheetEditor extends Editor {
return null;
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
@@ -427,6 +445,7 @@ public class SpritesheetEditor extends Editor {
} else if (source == categoryBox) {
sheet.category = (Spritesheet.Category) value;
}
sheet.save();
}
}

View File

@@ -2,6 +2,7 @@ package com.gpl.rpg.atcontentstudio.ui.tools;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.Icon;
import javax.swing.ImageIcon;
@@ -200,7 +201,7 @@ public class ItemsTableView extends ElementTableView {
//not editable.
}
List<TableModelListener> listeners = new ArrayList<TableModelListener>();
List<TableModelListener> listeners = new CopyOnWriteArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {

View File

@@ -2,6 +2,7 @@ package com.gpl.rpg.atcontentstudio.ui.tools;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.Icon;
import javax.swing.ImageIcon;
@@ -157,7 +158,7 @@ public class NPCsTableView extends ElementTableView {
//not editable.
}
List<TableModelListener> listeners = new ArrayList<TableModelListener>();
List<TableModelListener> listeners = new CopyOnWriteArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {

View File

@@ -0,0 +1,67 @@
package com.gpl.rpg.atcontentstudio.utils;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import com.gpl.rpg.atcontentstudio.model.Workspace;
public class DesktopIntegration {
public static void openTmxMap(File f) {
if (Workspace.activeWorkspace.settings.useSystemDefaultMapEditor.getCurrentValue()) {
try {
Desktop.getDesktop().open(f);
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
Runtime.getRuntime().exec(Workspace.activeWorkspace.settings.mapEditorCommand.getCurrentValue()+" "+f.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void openImage(File f) {
if (Workspace.activeWorkspace.settings.useSystemDefaultImageViewer.getCurrentValue()) {
try {
Desktop.getDesktop().open(f);
} catch (IOException e) {
e.printStackTrace();
}
} else if (Workspace.activeWorkspace.settings.useSystemDefaultImageEditor.getCurrentValue()) {
try {
Desktop.getDesktop().edit(f);
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
Runtime.getRuntime().exec(Workspace.activeWorkspace.settings.imageEditorCommand.getCurrentValue()+" "+f.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static enum OSType {
Windows, MacOS, NIX, Other
}
public static OSType detectedOS = detectOS();
private static OSType detectOS() {
String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
if ((os.indexOf("mac") >= 0) || (os.indexOf("darwin") >= 0)) return OSType.MacOS;
if (os.indexOf("win") >= 0) return OSType.Windows;
if ((os.indexOf("nux") >= 0) || (os.indexOf("nix") >= 0) || (os.indexOf("aix") >= 0) || (os.indexOf("sunos") >= 0) || (os.indexOf("solaris") >= 0)) return OSType.NIX;
return OSType.Other;
}
}

View File

@@ -6,9 +6,15 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@@ -108,7 +114,85 @@ public class FileUtils {
}
}
}
}
public static boolean makeSymlink(File targetFile, File linkFile) {
Path target = Paths.get(targetFile.getAbsolutePath());
Path link = Paths.get(linkFile.getAbsolutePath());
if (!Files.exists(link)) {
try {
Files.createSymbolicLink(link, target);
} catch (Exception e) {
System.err.println("Failed to create symbolic link to target \""+targetFile.getAbsolutePath()+"\" as \""+linkFile.getAbsolutePath()+"\" the java.nio way:");
e.printStackTrace();
switch (DesktopIntegration.detectedOS) {
case Windows:
System.err.println("Trying the Windows way with mklink");
try {
Runtime.getRuntime().exec("cmd.exe /C mklink "+(targetFile.isDirectory() ? "/J " : "")+linkFile.getAbsolutePath()+" "+targetFile.getAbsolutePath());
} catch (IOException e1) {
e1.printStackTrace();
}
System.err.println("Attempting UAC elevation through VBS script.");
if (!linkFile.exists()) {
runWithUac("cmd.exe /C mklink "+(targetFile.isDirectory() ? "/J " : "")+linkFile.getAbsolutePath()+" "+targetFile.getAbsolutePath(), 3, linkFile);
}
break;
case MacOS:
case NIX:
case Other:
System.err.println("Trying the unix way with ln -s");
try {
Runtime.getRuntime().exec("ln -s "+targetFile.getAbsolutePath()+" "+linkFile.getAbsolutePath());
} catch (IOException e1) {
e1.printStackTrace();
}
break;
default:
System.out.println("Unrecognized OS. Please contact ATCS dev.");
break;
}
}
}
if (!Files.exists(link)) {
System.err.println("Failed to create link \""+linkFile.getAbsolutePath()+"\" targetting \""+targetFile.getAbsolutePath()+"\"");
System.err.println("You can try running ATCS with administrative privileges once, or create the symbolic link manually.");
}
return true;
}
public static File backupFile(File f) {
try {
Path returned = Files.copy(Paths.get(f.getAbsolutePath()), Paths.get(f.getAbsolutePath()+".bak"), StandardCopyOption.REPLACE_EXISTING);
return returned.toFile();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
static final String uacBatName = "ATCS_elevateWithUac.bat";
public static void runWithUac(String command, int tries, File checkExists) {
File tmpFolder = new File(System.getProperty("java.io.tmpdir"));
File batFile = new File(tmpFolder, uacBatName);
batFile.deleteOnExit();
FileWriter writer;
try {
writer = new FileWriter(batFile, false);
writer.write(
"@echo Set objShell = CreateObject(\"Shell.Application\") > %temp%\\sudo.tmp.vbs\r\n"
+ "@echo args = Right(\"%*\", (Len(\"%*\") - Len(\"%1\"))) >> %temp%\\sudo.tmp.vbs\r\n"
+ "@echo objShell.ShellExecute \"%1\", args, \"\", \"runas\" >> %temp%\\sudo.tmp.vbs\r\n"
+ "@cscript %temp%\\sudo.tmp.vbs\r\n"
+ "del /f %temp%\\sudo.tmp.vbs\r\n");
writer.close();
while (!checkExists.exists() && tries-- > 0) {
Runtime.getRuntime().exec(new String[]{"cmd.exe","/C", batFile.getAbsolutePath()+" "+command});
}
} catch (IOException e) {
e.printStackTrace();
}
}