Revise IDE configurations (KDEV4)

This commit is contained in:
Nicholas George
2021-10-21 21:53:26 -05:00
commit 9e8224e73e
70 changed files with 5639 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
package org.worlio.WorldsOrganizer;
import javafx.scene.image.Image;
public class AppIcon {
public static Image logo = new Image(Main.class.getResourceAsStream("/logo.png"));
public static Image config = new Image(Main.class.getResourceAsStream("/icons/conf.png"), getSize(), getSize(), false, true);
public static Image newFile = new Image(Main.class.getResourceAsStream("/icons/file-plus.png"), getSize(), getSize(), false, true);
public static Image openFile = new Image(Main.class.getResourceAsStream("/icons/folder.png"), getSize(), getSize(), false, true);
public static Image saveFile = new Image(Main.class.getResourceAsStream("/icons/save.png"), getSize(), getSize(), false, true);
public static Image saveFileAs = new Image(Main.class.getResourceAsStream("/icons/save-as.png"), getSize(), getSize(), false, true);
public static Image undo = new Image(Main.class.getResourceAsStream("/icons/undo.png"), getSize(), getSize(), false, true);
public static Image redo = new Image(Main.class.getResourceAsStream("/icons/redo.png"), getSize(), getSize(), false, true);
public static Image quitApp = new Image(Main.class.getResourceAsStream("/icons/quit.png"), getSize(), getSize(), false, true);
public static Image add = new Image(Main.class.getResourceAsStream("/icons/plus.png"), getSize(), getSize(), false, true);
public static Image remove = new Image(Main.class.getResourceAsStream("/icons/delete.png"), getSize(), getSize(), false, true);
public static Image removeAll = new Image(Main.class.getResourceAsStream("/icons/delete-all.png"), getSize(), getSize(), false, true);
public static Image moveUp = new Image(Main.class.getResourceAsStream("/icons/up.png"), getSize(), getSize(), false, true);
public static Image moveDown = new Image(Main.class.getResourceAsStream("/icons/down.png"), getSize(), getSize(), false, true);
public static Image findReplace = new Image(Main.class.getResourceAsStream("/icons/find.png"), getSize(), getSize(), false, true);
public static Image linkCheck = new Image(Main.class.getResourceAsStream("/icons/link.png"), getSize(), getSize(), false, true);
public static Image unknownFile = new Image(Main.class.getResourceAsStream("/icons/file.png"), getSize(), getSize(), false, true);
public static Image avatarFile = new Image(Main.class.getResourceAsStream("/icons/avatar.png"), getSize(), getSize(), false, true);
public static Image markFile = new Image(Main.class.getResourceAsStream("/icons/mark.png"), getSize(), getSize(), false, true);
private static int getSize() {
return Main.configManager.getIntValue(ConfigEntry.iconSize);
}
}

View File

@@ -0,0 +1,28 @@
package org.worlio.WorldsOrganizer;
public class AvatarObject implements WorldList {
private String name;
private String value;
AvatarObject(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String code) {
this.value = code;
}
}

View File

@@ -0,0 +1,9 @@
package org.worlio.WorldsOrganizer;
interface Command {
public void execute();
public void undo();
}

View File

@@ -0,0 +1,57 @@
package org.worlio.WorldsOrganizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CommandStack {
private List<Command> commands = Collections.emptyList();
private int nextPointer = 0;
public void doCommand(Command command) {
List<Command> newList = new ArrayList<>(nextPointer + 1);
for(int k = 0; k < nextPointer; k++) {
newList.add(commands.get(k));
}
newList.add(command);
commands = newList;
nextPointer++;
// Do the command here, or return it to whatever called this to be done, or maybe it has already been done by now or something
// (I can only guess on what your code currently looks like...)
command.execute();
}
public boolean canUndo() {
return nextPointer > 0;
}
public void undo() {
if(canUndo()) {
nextPointer--;
Command commandToUndo = commands.get(nextPointer);
// Undo the command, or return it to whatever called this to be undone, or something
commandToUndo.undo();
} else {
throw new IllegalStateException("Cannot undo");
}
}
public boolean canRedo() {
return nextPointer < commands.size();
}
public void redo() {
if(canRedo()) {
Command commandToDo = commands.get(nextPointer);
nextPointer++;
// Do the command, or return it to whatever called this to be re-done, or something
commandToDo.execute();
} else {
throw new IllegalStateException("Cannot redo");
}
}
}

View File

@@ -0,0 +1,197 @@
package org.worlio.WorldsOrganizer;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
enum ToolBarPosition {
TOP("Top", 0),
RIGHT("Right", 1),
BOTTOM("Bottom", 2),
LEFT("Left", 3);
private String name;
private int value;
ToolBarPosition(String name, int value) {
this.name = name;
this.value = value;
}
}
enum ConfigEntry {
updateURL("update-url"),
iconSize("icon-size"),
fileBackup("file-backup"),
darkMode("dark-mode"),
toolbarPos("toolbar-position"),
channel("channel"),
status("show-status"),
debug("debug");
private String name;
ConfigEntry(String name) {
this.name = name;
}
}
public class ConfigManager {
private File configFile;
public static final List<String> channels = Arrays.asList("stable", "beta");
public static final List<String> toolBarPos = Arrays.asList("Top", "Right", "Bottom", "Left");
private static HashMap<String, Object> defaultConfiguration = new HashMap<>();
static HashMap<String, Object> configuration = new HashMap<>();
private static ObjectMapper mapper;
private void initialize() {
mapper = new ObjectMapper();
Console.print("Initializing default config values", 1, ConsoleType.INFO);
defaultConfiguration.put(ConfigEntry.updateURL.name(), "https://worlio.com/WorldsOrganizer.json");
defaultConfiguration.put(ConfigEntry.iconSize.name(), 24);
defaultConfiguration.put(ConfigEntry.fileBackup.name(), true);
defaultConfiguration.put(ConfigEntry.darkMode.name(), false);
defaultConfiguration.put(ConfigEntry.toolbarPos.name(), 3);
defaultConfiguration.put(ConfigEntry.channel.name(), "stable");
defaultConfiguration.put(ConfigEntry.status.name(), true);
defaultConfiguration.put(ConfigEntry.debug.name(), false);
}
public ConfigManager() {
initialize();
}
public ConfigManager(File file) {
initialize();
configFile = file;
try {
if (!configFile.exists()) {
Console.print("Config doesn't exist! Writing new one...", 1, ConsoleType.INFO);
write();
configuration = defaultConfiguration;
} else {
Console.print("Mapping config", 1, ConsoleType.INFO);
configuration = mapper.readValue(new FileInputStream(configFile), new TypeReference<HashMap<String, Object>>() {});
}
} catch (IOException ioException) {
write();
}
}
public boolean write() {
Console.print("Updating config", ConsoleType.INFO);
return write(configFile);
}
public boolean write(HashMap<String, Object> hash) {
if (!configFile.exists()) {
if (!createFile(configFile)) return false;
}
assert configFile.exists();
try(FileOutputStream fos = new FileOutputStream(configFile);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
bos.write(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(hash).getBytes());
bos.close();
fos.close();
configuration = mapper.readValue(new FileInputStream(configFile), new TypeReference<HashMap<String, Object>>() {
});
return true;
} catch (IOException e) {
Console.print("IOException encountered while writing config file. Aborted!", ConsoleType.ERROR);
return false;
}
}
public boolean write(File file) {
if (!file.exists()) {
if (!createFile(file)) return false;
}
ObjectMapper mapper = new ObjectMapper();
try(FileOutputStream fos = new FileOutputStream(configFile);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
bos.write(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(configuration).getBytes());
bos.close();
fos.close();
configuration = mapper.readValue(new FileInputStream(file), new TypeReference<HashMap<String, Object>>() {});
return true;
} catch (IOException e) {
Console.print("IOException encountered while writing config file. Aborted!", ConsoleType.ERROR);
return false;
}
}
private boolean createFile(File file) {
try {
assert file.createNewFile();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean getBooleanValue(ConfigEntry entry) {
return (boolean)getValue(entry);
}
public String getStringValue(ConfigEntry entry) {
return (String)getValue(entry);
}
public int getIntValue(ConfigEntry entry) {
return (int)getValue(entry);
}
public double getDoubleValue(ConfigEntry entry) {
return (double)getValue(entry);
}
private Object getValue(ConfigEntry entry) {
try {
Object o = configuration.get(entry.name());
if (o == null) throw new NullPointerException();
else return o;
} catch (NullPointerException e) {
return defaultConfiguration.get(entry.name());
}
}
private void set(ConfigEntry entry, Object value) {
if (configuration.containsKey(entry.name())) configuration.replace(entry.name(), value);
else configuration.put(entry.name(), value);
}
public void setValue(ConfigEntry entry, Object value) {
switch (entry) {
default:
set(entry, value);
break;
case toolbarPos:
switch ((String)value) {
case "Top":
set(entry, 0);
break;
case "Right":
set(entry, 1);
break;
case "Bottom":
set(entry, 2);
break;
default:
case "Left":
set(entry, 3);
break;
}
break;
}
}
}

View File

@@ -0,0 +1,139 @@
package org.worlio.WorldsOrganizer;
import java.io.File;
import java.io.IOException;
import java.net.*;
import java.util.List;
import java.util.Properties;
enum ConsoleType {
ERROR(5),
WARNING(4),
DEBUG(3),
SUCCESS(2),
INFO(1),
DEFAULT(0);
private final int value;
ConsoleType(int value) {
this.value = value;
}
}
public class Console {
public static final String RESET = "\u001B[0m";
public static final String RED = "\u001B[31m";
public static final String GREEN = "\u001B[32m";
public static final String YELLOW = "\u001B[33m";
public static final String BLUE = "\u001B[34m";
public static final String CYAN = "\u001B[36m";
final static Properties properties = new Properties();
public static void print(String message) {
print(message, ConsoleType.INFO);
}
public static void print(String message, ConsoleType type) {
print(message, 0, type);
}
public static void print(String message, int debug, ConsoleType type) {
if (Main.debugMode >= debug) {
String output = "";
switch (type) {
case DEFAULT:
break;
case INFO:
output = BLUE + "INFO " + RESET;
break;
case SUCCESS:
output = GREEN + "SUCCESS " + RESET;
break;
case DEBUG:
output = CYAN + "DEBUG " + RESET;
break;
case WARNING:
output = YELLOW + "WARNING " + RESET;
break;
case ERROR:
output = RED + "ERROR " + RESET;
break;
}
output += message;
System.out.println(output);
}
}
private static String getProperty(String property) {
try {
properties.load(Main.class.getClassLoader().getResourceAsStream("project.properties"));
return properties.getProperty(property);
} catch (IOException e) {
return "?";
}
}
public static String getVersion(){
return getProperty("version");
}
public static String getDate(){
return getProperty("buildDate");
}
public static String getHelp() {
String command;
command = "WorldsOrganizer.jar [OPTIONS]\n" +
"Commands:\n" +
commandCreate(" --debug=n", "Enable debug mode, which displays extra log information in the command-line. (1 - Logging, 2 - Complete Debug)") + "\n" +
commandCreate("-i --input", "Start application with input files.") + "\n" +
commandCreate("-h --help", "Show this output.");
return command;
}
private static String commandCreate(String cmd, String info) {
return " " + cmd + " ".substring(cmd.length()) + info;
}
public static boolean testURL(String address) throws IOException {
int responseCode;
try {
URL url = new URL(address);
HttpURLConnection huc = (HttpURLConnection) url.openConnection();
huc.setRequestMethod("HEAD");
huc.setConnectTimeout(15000);
responseCode = huc.getResponseCode();
} catch (Exception e) {
responseCode = 404;
}
return HttpURLConnection.HTTP_OK == responseCode;
}
public static void process() {
Dialog.process();
}
public static File getParent() {
try {
return new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile();
} catch (URISyntaxException e) {
Dialog.showException(e);
return null;
}
}
public static String changelogify(List<String> list) {
StringBuilder changes = new StringBuilder();
for (String line : list) {
changes.append(" - ").append(line).append("\n");
}
return changes.toString();
}
}

View File

@@ -0,0 +1,170 @@
package org.worlio.WorldsOrganizer;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
public class Dialog {
public static void showWindowDialog(String title, Pane pane) {
showWindowDialog(title, pane, null);
}
public static void showWindowDialog(String title, Pane pane, Collection<Button> buttons) {
Stage dStage = new Stage();
dStage.initOwner(Main.mainStage);
dStage.setTitle(title);
Button cancelButton = new Button("Close");
cancelButton.setCancelButton(true);
cancelButton.addEventFilter(MouseEvent.MOUSE_CLICKED, a -> dStage.close());
ButtonBar buttonBar = new ButtonBar();
buttonBar.getButtons().add(cancelButton);
if (buttons != null) buttonBar.getButtons().addAll(buttons);
buttonBar.setPadding(new Insets(10, 10, 10, 10));
dStage.setMinWidth(400);
dStage.setMinHeight(400);
dStage.setScene(new Scene(new VBox(pane, buttonBar), 400, 400));
dStage.show();
}
public static void showError(String header, String content) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("An Error Occurred");
alert.setHeaderText(header);
alert.setContentText(content);
alert.initOwner(Main.mainStage);
alert.getDialogPane().setMinSize(200,200);
alert.showAndWait();
}
public static void showException(Exception ex) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Exception Dialog");
alert.setHeaderText("An Exception was encountered.");
alert.setContentText("Please file a bug report if this problem persists.");
alert.initOwner(Main.mainStage);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
String exceptionText = sw.toString();
Label label = new Label("The exception stacktrace was:");
TextArea textArea = new TextArea(exceptionText);
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setMaxWidth(Double.MAX_VALUE);
textArea.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(textArea, Priority.ALWAYS);
GridPane.setHgrow(textArea, Priority.ALWAYS);
GridPane expContent = new GridPane();
expContent.setMaxWidth(Double.MAX_VALUE);
expContent.add(label, 0, 0);
expContent.add(textArea, 0, 1);
alert.getDialogPane().setExpandableContent(expContent);
alert.getDialogPane().setMinSize(200,200);
alert.showAndWait();
}
public static WorldsType newFileList() {
List<String> choices = new ArrayList<>();
choices.add("Avatars");
choices.add("WorldsMarks");
ChoiceDialog<String> dialog = new ChoiceDialog<>(choices.get(0), choices);
dialog.setTitle("New File");
dialog.setHeaderText("Select a type for the new file.");
dialog.setContentText("Type:");
dialog.initOwner(Main.mainStage);
dialog.getDialogPane().setMinSize(200,200);
Optional<String> result = dialog.showAndWait();
if (result.isPresent()){
if (result.get().equals(choices.get(0)))
return WorldsType.AVATAR;
else if (result.get().equals(choices.get(1)))
return WorldsType.WORLDSMARK;
else return WorldsType.NULL;
} else {
return WorldsType.NULL;
}
}
public static void showUpdate(Version newVer) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
assert Main.verMan != null;
alert.setTitle("Update Dialog");
alert.setHeaderText("A new version (v" + newVer.get() + ") of Organizer is available for download.\nYou are currently on v" + Console.getVersion() + ".");
alert.initOwner(Main.mainStage);
ButtonType updateButton = new ButtonType("Open");
ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
Label label = new Label("View Changelog");
TextArea textArea = new TextArea(Console.changelogify(Main.verMan.getChangelog(newVer)));
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setMaxWidth(Double.MAX_VALUE);
textArea.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(textArea, Priority.ALWAYS);
GridPane.setHgrow(textArea, Priority.ALWAYS);
GridPane expContent = new GridPane();
expContent.setMaxWidth(Double.MAX_VALUE);
expContent.add(label, 0, 0);
expContent.add(textArea, 0, 1);
alert.getDialogPane().setExpandableContent(expContent);
alert.getButtonTypes().setAll(updateButton, buttonTypeCancel);
alert.getDialogPane().setMinSize(200,200);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == updateButton) {
Console.print("Displaying webpage in native browser.", 1, ConsoleType.INFO);
Main.hostServices.showDocument(Main.verMan.url.replace("{ver}", newVer.get()));
} else {
alert.close();
}
}
public static void process() {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Message");
alert.setHeaderText(
"For all you give me, an " + "ea" + "st" + "er" + " " + "e" + "gg" + " for you."
);
alert.setContentText(
"I" + " l" + "ov" + "e" + " yo" + "u," + "DO" + "SF" + "OX" + "!"
);
alert.initOwner(Main.mainStage);
alert.getDialogPane().setMinSize(200,200);
alert.showAndWait();
}
}

View File

@@ -0,0 +1,23 @@
package org.worlio.WorldsOrganizer;
import java.io.IOException;
public class InvalidPersisterException extends IOException {
public InvalidPersisterException() {
super();
}
public InvalidPersisterException(String message) {
super(message);
}
public InvalidPersisterException(String message, Throwable cause) {
super(message, cause);
}
public InvalidPersisterException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,705 @@
package org.worlio.WorldsOrganizer;
import javafx.application.Application;
import javafx.application.HostServices;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.*;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class Main extends Application {
static int debugMode = 0;
static ConfigManager configManager;
static VersionManager verMan;
static List<File> startFiles = new ArrayList<>();
static List<WorldsTab> tabs = new ArrayList<>();
private TabPane tabPane;
private static Pane statusPane;
public static Stage mainStage;
static HostServices hostServices;
@Override
public void init() {
Console.print("Worlds Organizer v" + Console.getVersion());
Console.print("Running on Java " + System.getProperty("java.version"));
configManager = new ConfigManager(new File((Console.getParent() + "/config.json")));
try {
verMan = new VersionManager();
} catch (IOException e) {
Console.print("An IOException was encountered attempting to obtain the version.", 1, ConsoleType.ERROR);
e.printStackTrace();
}
if (debugMode < 1) debugMode = configManager.getBooleanValue(ConfigEntry.debug) ? 1 : 0;
Console.print("Initializing main application.", ConsoleType.INFO);
hostServices = this.getHostServices();
}
public static void main(String[] args) {
boolean doRun = true;
for (int a = 0; a < args.length; a++) {
String arg = args[a];
if (arg.startsWith("--debug")) {
try {
debugMode = Integer.parseInt(args[a+1]);
Console.print("Debug mode set to: " + debugMode, 1, ConsoleType.INFO);
a++;
} catch (NumberFormatException e) {
debugMode = 0;
Console.print("NumberFormatException encountered! Defaulting to 0.", 1, ConsoleType.WARNING);
}
} else if (arg.equals("-i") || arg.equals("--input")) {
try {
File newFile = new File(args[a + 1]);
startFiles.add(newFile);
a++;
} catch (Exception e) {
Console.print("Invalid file location in argument!", 0, ConsoleType.ERROR);
}
} else if (arg.equals("-h") || arg.equals("--help")) {
doRun = false;
Console.getHelp();
break;
} else {
doRun = false;
Console.print(arg + " is not a valid argument. Please use '-help' to see a list of options and arguments.", 0, ConsoleType.WARNING);
break;
}
}
if (doRun) launch(args);
}
@Override
public void start(final Stage stage) {
mainStage = stage;
mainStage.setTitle("Worlds Organizer");
mainStage.getIcons().add(AppIcon.logo);
Console.print("Starting Window", 1, ConsoleType.INFO);
mainStage.setOnCloseRequest(a -> {
quit();
});
ToolBar menuBar = new ToolBar();
Button newFileBtn = new Button("New");
newFileBtn.setGraphic(new ImageView(AppIcon.newFile));
menuBar.getItems().add(newFileBtn);
Button openFileBtn = new Button("Open");
openFileBtn.setGraphic(new ImageView(AppIcon.openFile));
menuBar.getItems().add(openFileBtn);
Button saveFileBtn = new Button("Save");
saveFileBtn.setGraphic(new ImageView(AppIcon.saveFile));
menuBar.getItems().add(saveFileBtn);
Button saveAsFileBtn = new Button("Save As");
saveAsFileBtn.setGraphic(new ImageView(AppIcon.saveFileAs));
menuBar.getItems().add(saveAsFileBtn);
menuBar.getItems().add(new Separator());
Button undoBtn = new Button();
undoBtn.setGraphic(new ImageView(AppIcon.undo));
undoBtn.setTooltip(new Tooltip("Undo"));
menuBar.getItems().add(undoBtn);
Button redoBtn = new Button();
redoBtn.setGraphic(new ImageView(AppIcon.redo));
redoBtn.setTooltip(new Tooltip("Redo"));
menuBar.getItems().add(redoBtn);
menuBar.getItems().add(new Separator());
Button confBtn = new Button();
confBtn.setTooltip(new Tooltip("Preferences"));
confBtn.setGraphic(new ImageView(AppIcon.config));
menuBar.getItems().add(confBtn);
Button quitBtn = new Button("Quit");
quitBtn.setGraphic(new ImageView(AppIcon.quitApp));
menuBar.getItems().add(quitBtn);
// Adding a tab pane
tabPane = new TabPane();
Console.print("Initializing Start Page", 1, ConsoleType.INFO);
// This will be permanent, and be exempt from the tab values we record.
Tab startTab = getStartPage();
startTab.setClosable(false);
tabPane.getTabs().add(startTab);
// Assigning all the events now.
Console.print("Assigning Events", 1, ConsoleType.INFO);
tabPane.addEventFilter(Tab.CLOSED_EVENT, f -> {
Console.print("Detected Tab Closed. Index " + (tabPane.getSelectionModel().getSelectedIndex() - 1) + ".", 1, ConsoleType.INFO);
tabs.remove(tabPane.getSelectionModel().getSelectedIndex() - 1);
});
// First adding the status bar
statusPane = new VBox(new Text());
statusPane.setPadding(new Insets(4, 4, 4, 4));
VBox vBox = new VBox(menuBar, tabPane);
if (configManager.getBooleanValue(ConfigEntry.status)) vBox.getChildren().add(statusPane);
Console.print("Completed Base Window Initialization", 1, ConsoleType.INFO);
Scene scene = new Scene(vBox, 960, 600);
newFileBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
if (e.isShiftDown()) {
try {
WorldListObject tempW = tabs.get(0).worldList;
if (tempW.size() <= 1) {
if (
tempW.get(0).getName().equals(
"D" + "F"
) && tempW.get(0).getValue().equals(
"6" + "/" + "2" + "7" + "/" + "2" + "0"
)
) {
Console.process();
} else newFile();
} else newFile();
} catch (NullPointerException | IndexOutOfBoundsException ignored) {}
} else newFile();
});
openFileBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
openFile(null);
});
saveFileBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
try {
WorldsTab tableObj = tabs.get(tabPane.getSelectionModel().getSelectedIndex() - 1);
saveFile(tableObj, tableObj.file);
Main.setStatusText("Saved file to '" + tableObj.file.getAbsolutePath() + "'.");
} catch (IndexOutOfBoundsException i) {
Console.print("IndexOutOfBoundsException encountered! Must be on file tab to save.", ConsoleType.ERROR);
}
});
saveAsFileBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
try {
WorldsTab tableObj = tabs.get(tabPane.getSelectionModel().getSelectedIndex() - 1);
saveFile(tableObj);
} catch (IndexOutOfBoundsException i) {
Console.print("IndexOutOfBoundsException encountered! Must be on file tab to save.", ConsoleType.ERROR);
}
});
undoBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
if (tabs.size() > 0 && tabPane.getSelectionModel().getSelectedIndex() > 0) {
WorldsTab tableObj = tabs.get(tabPane.getSelectionModel().getSelectedIndex() - 1);
tableObj.doUndo();
}
});
redoBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
if (tabs.size() > 0 && tabPane.getSelectionModel().getSelectedIndex() > 0) {
WorldsTab tableObj = tabs.get(tabPane.getSelectionModel().getSelectedIndex() - 1);
tableObj.doRedo();
}
});
confBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
// This is it's own window to circumvent the issues with Buttons
// and design on Dialog.
Stage confStage = new Stage();
confStage.initOwner(mainStage);
confStage.setTitle("Preferences");
Console.print("Displaying Configuration Window", 1, ConsoleType.INFO);
// General Tab
Label channelName = new Label("Update Channel");
channelName.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 12));
Label channelInfo = new Label("Channel to use for update checks and links: 'stable' will provide tested " +
"build updates while 'beta' is more of an experimental bug-finding experience.");
channelInfo.setWrapText(true);
ObservableList<String> channels =
FXCollections.observableArrayList(ConfigManager.channels);
ComboBox<String> channelOption = new ComboBox(channels);
channelOption.getSelectionModel().select(configManager.getStringValue(ConfigEntry.channel));
HBox.setHgrow(channelOption, Priority.ALWAYS);
// Appearance Tab
Label darkName = new Label("Use Dark Mode");
darkName.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 12));
Label darkInfo = new Label("Changes the style of the application to use a basic dark theme.");
darkInfo.setWrapText(true);
CheckBox darkOption = new CheckBox("Enabled");
darkOption.setSelected(configManager.getBooleanValue(ConfigEntry.darkMode));
darkOption.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
configManager.setValue(ConfigEntry.darkMode, isSelected);
});
VBox.setVgrow(darkOption, Priority.ALWAYS);
Label statusName = new Label("Display Status Bar");
statusName.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 12));
Label statusInfo = new Label("Changes the style of the application to use a basic dark theme. Requires a restart to apply.");
statusInfo.setWrapText(true);
CheckBox statusOption = new CheckBox("Enabled");
statusOption.setSelected(configManager.getBooleanValue(ConfigEntry.status));
statusOption.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
configManager.setValue(ConfigEntry.status, isSelected);
});
VBox.setVgrow(statusOption, Priority.ALWAYS);
Label toolName = new Label("Toolbar Location");
toolName.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 12));
Label toolInfo = new Label("The edge to place the toolbar that holds the file tools. Default is 'LEFT'.");
toolInfo.setWrapText(true);
Label toolLabel = new Label("Toolbar Location: ");
HBox.setHgrow(toolLabel, Priority.SOMETIMES);
ObservableList<String> toolPos =
FXCollections.observableArrayList(ConfigManager.toolBarPos);
ComboBox<String> toolPosOption = new ComboBox<>(toolPos);
toolPosOption.getSelectionModel().select(configManager.getIntValue(ConfigEntry.toolbarPos));
HBox.setHgrow(toolPosOption, Priority.ALWAYS);
Label sizeName = new Label("Icon Size");
sizeName.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 12));
Label sizeInfo = new Label("Size (in pixels) of icons in the window. Requires a restart to apply.");
sizeInfo.setWrapText(true);
Slider iconSizeSlider = new Slider(16, 96, configManager.getIntValue(ConfigEntry.iconSize));
iconSizeSlider.setTooltip(new Tooltip("Set icon size for the interface icons."));
HBox.setHgrow(iconSizeSlider, Priority.SOMETIMES);
iconSizeSlider.setShowTickLabels(true);
iconSizeSlider.setShowTickMarks(true);
iconSizeSlider.setMajorTickUnit(16);
iconSizeSlider.setMinorTickCount(1);
iconSizeSlider.setSnapToTicks(true);
// Advanced Tab
Label backupName = new Label("Use Backups");
backupName.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 12));
Label backupInfo = new Label("Creates a backup of the file before the save process.");
backupInfo.setWrapText(true);
CheckBox backupOption = new CheckBox("Enabled");
backupOption.setSelected(configManager.getBooleanValue(ConfigEntry.fileBackup));
backupOption.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
configManager.setValue(ConfigEntry.fileBackup, isSelected);
});
VBox.setVgrow(backupOption, Priority.ALWAYS);
Label debugName = new Label("Print Debug");
debugName.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 12));
Label debugInfo = new Label("Prints out debug information in the commandline output. Requires a restart to apply.");
debugInfo.setWrapText(true);
CheckBox debugCheck = new CheckBox("Enabled");
debugCheck.setSelected(configManager.getBooleanValue(ConfigEntry.debug));
debugCheck.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
configManager.setValue(ConfigEntry.debug, isSelected);
});
VBox.setVgrow(debugCheck, Priority.ALWAYS);
Button applyButton = new Button("Apply");
applyButton.setDefaultButton(true);
applyButton.addEventFilter(MouseEvent.MOUSE_CLICKED, a -> {
configManager.setValue(ConfigEntry.toolbarPos, toolPosOption.getValue());
configManager.setValue(ConfigEntry.channel, channelOption.getValue());
configManager.setValue(ConfigEntry.iconSize, (int)iconSizeSlider.getValue());
configManager.write();
toggleDark(scene);
Main.setStatusText("Applied new settings.");
});
Button okButton = new Button("Ok");
okButton.addEventFilter(MouseEvent.MOUSE_CLICKED, a -> {
configManager.setValue(ConfigEntry.toolbarPos, toolPosOption.getValue());
configManager.setValue(ConfigEntry.channel, channelOption.getValue());
configManager.setValue(ConfigEntry.iconSize, (int)iconSizeSlider.getValue());
configManager.write();
toggleDark(scene);
confStage.close();
Main.setStatusText("Applied new settings.");
});
Button cancelButton = new Button("Cancel");
cancelButton.setCancelButton(true);
cancelButton.addEventFilter(MouseEvent.MOUSE_CLICKED, a -> {
confStage.close();
});
// Tabbing every option into their own VBox so we can have them split off in their own containers.
// This makes it easier to add to tabs because it's just a simple declare. Also good for design.
VBox vGeneral = new VBox(channelName, channelInfo, channelOption);
ScrollPane general = new ScrollPane(vGeneral);
general.setFitToWidth(true);
Tab generalTab = new Tab("General", general);
VBox.setVgrow(general, Priority.ALWAYS);
vGeneral.setPadding(new Insets(10, 10, 10, 10));
vGeneral.setSpacing(10);
VBox vSkin = new VBox(darkName, darkInfo, darkOption, statusName, statusInfo, statusOption,
toolName, toolInfo, toolPosOption, sizeName, sizeInfo, iconSizeSlider);
ScrollPane skin = new ScrollPane(vSkin);
skin.setFitToWidth(true);
Tab skinTab = new Tab("Appearance", skin);
VBox.setVgrow(skin, Priority.ALWAYS);
vSkin.setPadding(new Insets(10, 10, 10, 10));
vSkin.setSpacing(10);
VBox vAdvance = new VBox(backupName, backupInfo, backupOption, debugName, debugInfo, debugCheck);
ScrollPane advance = new ScrollPane(vAdvance);
advance.setFitToWidth(true);
Tab advanceTab = new Tab("Advanced", advance);
VBox.setVgrow(advance, Priority.ALWAYS);
vAdvance.setPadding(new Insets(10, 10, 10, 10));
vAdvance.setSpacing(10);
TabPane prefPane = new TabPane(generalTab, skinTab, advanceTab);
VBox.setVgrow(prefPane, Priority.ALWAYS);
prefPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
general.maxWidthProperty().bind(prefPane.widthProperty());
skin.maxWidthProperty().bind(prefPane.widthProperty());
advance.maxWidthProperty().bind(prefPane.widthProperty());
ButtonBar bBar = new ButtonBar();
bBar.getButtons().addAll(applyButton, okButton, cancelButton);
bBar.setPadding(new Insets(10, 10, 10, 10));
confStage.setMinWidth(350);
confStage.setMinHeight(250);
confStage.setScene(new Scene(new VBox(prefPane, bBar), 350, 350));
confStage.show();
});
quitBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
e.consume();
quit();
});
VBox.setVgrow(tabPane, Priority.ALWAYS);
toggleDark(scene);
Console.print("Scene Prepared", 1, ConsoleType.INFO);
mainStage.setScene(scene);
mainStage.show();
Console.print("Displaying Main Window", 1, ConsoleType.INFO);
// Going through files set up on command-line arguments.
Console.print("Iterating through argument files", 1, ConsoleType.INFO);
if (startFiles != null && startFiles.size() > 0) {
try {
for (File start : startFiles) {
if (start.exists()) openFile(start);
else Console.print("Unable to open file: File Not Found:\n'" + start.getPath() + "'", ConsoleType.ERROR);
}
} catch (Exception e) {
Console.print("An unknown error occurred attempting to open argument files.", 1, ConsoleType.ERROR);
}
}
}
public static void setStatusText(String message) {
statusPane.getChildren().set(0, new Text(message));
// 2.5 Seconds later, the text will disappear. Makes it look neater and also makes sure you
// aren't frozen I guess.
Task<Void> sleeper = new Task<Void>() {
@Override
protected Void call() {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
statusPane = new VBox(new Text());
}
return null;
}
};
sleeper.setOnSucceeded(event -> statusPane.getChildren().set(0, new Text()));
new Thread(sleeper).start();
}
private void toggleDark(Scene curScene) {
if (configManager.getBooleanValue(ConfigEntry.darkMode)) curScene.getStylesheets().add("dark.css");
else curScene.getStylesheets().remove("dark.css");
}
public Tab getStartPage() {
VBox mainBox = new VBox();
// Styling fancy texts.
ImageView logoView = new ImageView(AppIcon.logo);
Text nameTxt = new Text("Worlds Organizer v" + Console.getVersion());
nameTxt.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 20));
Text buildTxt = new Text("Build Date: " + Console.getDate());
buildTxt.setFont(Font.font("Verdana", FontWeight.NORMAL, FontPosture.REGULAR, 12));
buildTxt.setFill(Color.GRAY);
Text devTxt = new Text("Developed by Worlio LLC");
devTxt.setFont(Font.font("Verdana", FontWeight.MEDIUM, FontPosture.REGULAR, 12));
logoView.setPreserveRatio(true);
logoView.fitHeightProperty().bind(mainBox.heightProperty().multiply(0.5));
mainBox.setAlignment(Pos.CENTER);
Button updateButton = new Button("Check for Updates");
updateButton.addEventFilter(MouseEvent.MOUSE_CLICKED, a -> {
boolean isUpdatable;
try {
// Simply restarting the manager so it gets everything fresh.
// Simple yet effective at what we want, without issues.
verMan = new VersionManager();
isUpdatable = verMan.hasUpdate();
if (isUpdatable) {
Console.print("Update detected! Showing dialog.", ConsoleType.INFO);
verMan.pushUpdate();
} else Console.print("No updates available.", ConsoleType.INFO);
} catch (IOException e) {
Console.print("Could not check for updates!", ConsoleType.ERROR);
isUpdatable = false;
}
if (!isUpdatable) Dialog.showError("Update Check", "No new updates are available.");
});
Button changelogButton = new Button("What's new?");
changelogButton.addEventFilter(MouseEvent.MOUSE_CLICKED, a -> {
Stage changelogStage = new Stage();
changelogStage.initOwner(mainStage);
changelogStage.setTitle("What's new?");
VBox changesBox = new VBox();
// Reading the json file remotely, and then looking through every single value in the list.
// It's simple text, so it makes it easy to parse and style.
for (Map.Entry<?, ?> vC : ((Map<?, ?>)((Map<?, ?>)verMan.json.get("versions")).get(configManager.getStringValue(ConfigEntry.channel))).entrySet()) {
// UPDATES UPDATES UPDATES
if (new Version((String)vC.getKey()).equals(new Version(Console.getVersion()))) {
Text channel = new Text("Current Version");
channel.setFont(Font.font("Verdana", FontWeight.LIGHT, FontPosture.ITALIC, 12));
changesBox.getChildren().add(channel);
}
Text version = new Text((String)vC.getKey());
version.setFont(Font.font("Verdana", FontWeight.BOLD, FontPosture.REGULAR, 14));
changesBox.getChildren().add(version);
for (String line : verMan.getChangelog(new Version((String)vC.getKey()))) {
Text lineTxt = new Text(" - " + line);
lineTxt.wrappingWidthProperty().bind(changesBox.prefWidthProperty().multiply(0.95));
changesBox.getChildren().add(lineTxt);
}
changesBox.getChildren().add(new Separator());
}
changesBox.setPadding(new Insets(10, 10, 10, 10));
// Organize it nicely within a small ScrollPane.
// It took forever to get the text to wrap so this works.
ScrollPane changesPane = new ScrollPane(changesBox);
VBox.setVgrow(changesPane, Priority.ALWAYS);
changesPane.prefWidthProperty().bind(changelogStage.widthProperty());
changesPane.setFitToWidth(true);
changesBox.prefWidthProperty().bind(changesPane.widthProperty());
Button cancelButton = new Button("Close");
cancelButton.setCancelButton(true);
cancelButton.addEventFilter(MouseEvent.MOUSE_CLICKED, (e) -> changelogStage.close());
ButtonBar bBar = new ButtonBar();
bBar.getButtons().addAll(cancelButton);
bBar.setPadding(new Insets(10, 10, 10, 10));
changelogStage.setMinWidth(450);
changelogStage.setMinHeight(400);
changelogStage.setScene(new Scene(new VBox(changesPane, bBar), 450, 400));
changelogStage.show();
});
HBox bBar = new HBox(changelogButton, updateButton);
bBar.setAlignment(Pos.CENTER);
bBar.setSpacing(10);
bBar.setPadding(new Insets(10, 10, 10, 10));
mainBox.getChildren().addAll(logoView, nameTxt, buildTxt, devTxt, bBar);
return new Tab("Start Page", mainBox);
}
void newFile() {
// Essentially a bare bones way of opening a file without the file.
WorldsTab tableObj = new WorldsTab();
WorldsType newType = Dialog.newFileList();
if (newType != WorldsType.NULL) {
Console.print("Creating a new tab", 1, ConsoleType.INFO);
Tab tab = tableObj.getTab(newType);
tabPane.getTabs().add(tab);
tabs.add(tableObj);
Main.setStatusText("Opened new tab.");
tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1);
}
}
void openFile(File file) {
File openedFile;
if (file == null) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open File");
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("All Files", "*"),
new FileChooser.ExtensionFilter("All Supported Formats", "*.avatars", "*.worldsmarks", "*.organizer-bkup"),
new FileChooser.ExtensionFilter("Gamma Avatars (*.avatars)", "*.avatars"),
new FileChooser.ExtensionFilter("Gamma WorldsMarks (*.worldsmarks)", "*.worldsmarks")
);
openedFile = fileChooser.showOpenDialog(mainStage);
} else {
openedFile = file;
}
if (openedFile != null) {
WorldsTab tableObj = new WorldsTab();
Tab tab = tableObj.getTab(openedFile);
if (tab != null) {
Main.setStatusText("Opened file '" + openedFile.getAbsolutePath() + "'.");
tabPane.getTabs().add(tab);
tabs.add(tableObj);
tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1);
} else {
Console.print("InvalidPersisterFile encountered! File is not a supported format.", ConsoleType.ERROR);
Dialog.showError("Invalid File!", "File selected is not a valid Persister format.");
}
}
}
void saveFile(WorldsTab tab) {
saveFile(tab, null);
}
void saveFile(WorldsTab tab, File file) {
File thisFile;
if (file == null) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save As File");
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("Gamma Avatars (*.avatars)", "*.avatars"),
new FileChooser.ExtensionFilter("Gamma WorldsMarks (*.worldsmarks)", "*.worldsmarks")
);
fileChooser.setInitialFileName("gamma");
thisFile = fileChooser.showSaveDialog(mainStage);
if (thisFile != null) {
switch (fileChooser.getSelectedExtensionFilter().getExtensions().get(0)) {
default:
case "*.avatars":
tab.worldList.classType = WorldsType.AVATAR;
break;
case "*.worldsmarks":
tab.worldList.classType = WorldsType.WORLDSMARK;
break;
}
}
} else {
thisFile = file;
}
if (thisFile != null) {
try {
Saver saver = new Saver(thisFile);
saver.save(tab.worldList);
tab.setSaved(true);
tab.update(thisFile);
Main.setStatusText("Saved file to '" + thisFile.getAbsolutePath() + "'.");
} catch (IOException e) {
Console.print("Unable to save file: " + thisFile.getAbsolutePath(), ConsoleType.ERROR);
Dialog.showException(e);
}
}
}
void quit() {
boolean askForSure = false;
for (WorldsTab t : tabs) {
if (!t.getSaved()) {
askForSure = true;
break;
}
}
if (askForSure) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.getDialogPane().setMinSize(200,200);
alert.setTitle("Quit");
alert.setHeaderText("Are you sure you want to quit?");
alert.setContentText("You have unsaved changes. Quitting now will lose your progress.");
ButtonType dontSaveButton = new ButtonType("Discard Changes");
ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
alert.getButtonTypes().setAll(dontSaveButton, buttonTypeCancel);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == dontSaveButton) {
mainStage.close();
} else {
alert.close();
}
} else {
mainStage.close();
}
}
}

View File

@@ -0,0 +1,28 @@
package org.worlio.WorldsOrganizer;
public class MarkObject implements WorldList {
private String name;
private String value;
MarkObject(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String code) {
this.value = code;
}
}

View File

@@ -0,0 +1,101 @@
package org.worlio.WorldsOrganizer;
import java.io.*;
public class Restorer {
DataInputStream dis;
File file;
public WorldListObject listObj;
private int oID;
Restorer(String path) {
new Restorer(new File(path));
}
Restorer(File file) {
Console.print("Initialized Restorer", 1, ConsoleType.INFO);
this.file = file;
try {
FileInputStream fis = new FileInputStream(file);
dis = new DataInputStream(fis);
Console.print("Restorer file set as '" + file.getAbsolutePath() + "'", 1, ConsoleType.INFO);
} catch (IOException e) {
Console.print("IOException reading file: '" + file.getAbsolutePath() + "'", ConsoleType.ERROR);
}
}
WorldListObject read() throws IOException {
if (dis == null) {
throw new InvalidPersisterException();
}
try {
if (!readString().equals("PERSISTER Worlds, Inc.")) { // Persister Header
throw new InvalidPersisterException();
} else {
int pVersion = readInt(); // Persister Version
Console.print("Persister Version detected: " + pVersion, 1, ConsoleType.INFO);
if (pVersion != 7) Console.print("Version not supported! Issues may occur!", ConsoleType.WARNING);
int count = readInt(); // Vector Count
readInt(); // Class ID
return readVector(count);
}
} catch (NullPointerException e) {
throw new InvalidPersisterException();
}
}
private WorldListObject readVector(int count) throws IOException {
Console.print("Starting read of '" + file.getPath() + "'", 1, ConsoleType.INFO);
listObj = new WorldListObject();
oID = readInt(); // Object ID
String typeText = readString(); // Class Name
listObj.classType = WorldsType.valueOfClass(typeText);
if (listObj.classType != null) {
Console.print("ClassName read as '" + typeText + "'. Setting type to '" + WorldsType.valueOfClass(typeText) + "'.", 2, ConsoleType.DEBUG);
for (int i = 0; i < count; i++) {
if (i > 0) readInt();
readInt(); // Version
WorldList newData = null;
if (listObj.classType == WorldsType.AVATAR) newData = new AvatarObject(readString(), readString());
else if (listObj.classType == WorldsType.WORLDSMARK) newData = new MarkObject(readString(), readString());
assert newData != null;
listObj.add(newData);
Console.print("Created WorldList item: { name: '" + newData.getName() + "', value: '" + newData.getValue() + "' }", 2, ConsoleType.DEBUG);
Console.print("Added new WorldList item to WorldListObject", 1, ConsoleType.DEBUG);
}
assert readString().equals("END PERSISTER");
}
return listObj;
}
String readString() throws IOException {
if (readBoolean()) {
return null;
} else {
return dis.readUTF();
}
}
int readInt() throws IOException {
return dis.readInt();
}
byte readByte() throws IOException {
return dis.readByte();
}
boolean readBoolean() throws IOException {
return dis.readBoolean();
}
}

View File

@@ -0,0 +1,86 @@
package org.worlio.WorldsOrganizer;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public class Saver {
DataOutputStream dis;
File file;
Saver(File file) throws IOException {
boolean doBackup = Main.configManager.getBooleanValue(ConfigEntry.fileBackup);
Console.print("Initialized Saver", 1, ConsoleType.INFO);
this.file = file;
File backupFile = new File(file.getAbsolutePath() + ".organizer-bkup");
try {
if (file.exists() && !doBackup) {
Console.print("File location already exists! Creating backup at " + backupFile.getAbsolutePath(), ConsoleType.WARNING);
Files.copy(Paths.get(file.getAbsolutePath()), Paths.get(backupFile.getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING);
}
} catch (IOException e) {
Console.print("IOException occurred during file backup!", ConsoleType.ERROR);
Dialog.showError("Unable to create backup!", "Saving will try and continue but might corrupt your files if it fails.");
}
try {
FileOutputStream fis = new FileOutputStream(file);
dis = new DataOutputStream(fis);
} catch (IOException e) {
Console.print("Couldn't write to file!");
Dialog.showException(e);
}
writeString("PERSISTER Worlds, Inc."); // Persister header
writeInt(7); // Persister version
}
public void save(WorldListObject objects) throws IOException {
int count = objects.size();
writeInt(count);
writeInt(459);
int objID = 8782;
writeInt(objID);
writeString(objects.classType.name);
Console.print("Saving as '" + objects.classType.name + "'", 2, ConsoleType.DEBUG);
for (int i = 0; i < count; i++) {
if (i > 0) {
writeInt(460 + i);
writeInt(objID);
}
else writeInt(1);
writeString(objects.get(i).getName());
writeString(objects.get(i).getValue());
Console.print("Saved WorldList item to file: { name: '" + objects.get(i).getName() + "', value: '" + objects.get(i).getValue() + "' }", 2, ConsoleType.DEBUG);
}
writeString("END PERSISTER");
}
void writeString(String s) throws IOException {
if (!s.isEmpty()) {
writeBoolean(false);
dis.writeUTF(s);
} else {
writeBoolean(true);
}
}
void writeInt(int i) throws IOException {
dis.writeInt(i);
}
void writeByte(byte b) throws IOException {
dis.writeByte(b);
}
void writeBoolean(boolean b) throws IOException {
dis.writeBoolean(b);
}
}

View File

@@ -0,0 +1,49 @@
package org.worlio.WorldsOrganizer;
public class Version implements Comparable<Version> {
private String version;
public final String get() {
return this.version;
}
public Version(String version) {
if (version != null) {
if (!version.matches("[0-9]+(\\.[0-9]+)*")) throw new IllegalArgumentException("Invalid version format");
version = version.replace("-dev", "");
} else throw new IllegalArgumentException("Version can not be null");
this.version = version;
}
@Override
public int compareTo(Version that) {
if(that == null) return 1;
String[] thisParts = this.get().split("\\.");
String[] thatParts = that.get().split("\\.");
int length = Math.max(thisParts.length, thatParts.length);
for(int i = 0; i < length; i++) {
int thisPart = i < thisParts.length ?
Integer.parseInt(thisParts[i]) : 0;
int thatPart = i < thatParts.length ?
Integer.parseInt(thatParts[i]) : 0;
if(thisPart < thatPart)
return -1;
if(thisPart > thatPart)
return 1;
}
return 0;
}
@Override
public boolean equals(Object that) {
if(this == that)
return true;
if(that == null)
return false;
if(this.getClass() != that.getClass())
return false;
return this.compareTo((Version) that) == 0;
}
}

View File

@@ -0,0 +1,71 @@
package org.worlio.WorldsOrganizer;
import com.fasterxml.jackson.databind.json.JsonMapper;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class VersionManager {
String url;
public Version currentVersion = new Version(Console.getVersion());
public Version newVersion;
static JsonMapper mapper = new JsonMapper();
Map<?, ?> json;
int format;
private boolean isValid() {
return format == 2;
}
VersionManager() throws IOException {
json = readJsonFromUrl(Main.configManager.getStringValue(ConfigEntry.updateURL));
format = (int)json.get("format");
if (!isValid()) throw new IOException("Invalid JSON Update format: Format Version is not 2");
url = (String) json.get("url");
Map<?, ?> updates = (Map<?, ?>) json.get("versions");
LinkedHashMap<?, ?> ver = (LinkedHashMap<?, ?>) updates.get(Main.configManager.getStringValue(ConfigEntry.channel));
newVersion = new Version((String)ver.keySet().toArray()[0]);
}
public boolean hasUpdate() {
if (!isValid()) return false;
return newVersion.compareTo(currentVersion) >= 1;
}
public void pushUpdate() {
if (hasUpdate() && isValid()) {
Dialog.showUpdate(newVersion);
} else Console.print("No new updates available.");
}
public List<String> getChangelog(Version ver) {
if (!isValid()) return new ArrayList<>();
// God is horrified, and he has every right to be.
return (List<String>)((LinkedHashMap<?, ?>) ((Map<?,?>)json.get("versions")).get(Main.configManager.getStringValue(ConfigEntry.channel))).get(ver.get());
}
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
public static Map<?,?> readJsonFromUrl(String url) throws IOException {
try (InputStream is = new URL(url).openStream()) {
BufferedReader rd = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
String jsonText = readAll(rd);
return mapper.readValue(jsonText, Map.class);
}
}
}

View File

@@ -0,0 +1,13 @@
package org.worlio.WorldsOrganizer;
public interface WorldList {
void setName(String name);
String getName();
void setValue(String value);
String getValue();
}

View File

@@ -0,0 +1,159 @@
package org.worlio.WorldsOrganizer;
import java.util.*;
enum WorldsType {
NULL(""),
AVATAR("NET.worlds.console.SavedAvMenuItem"),
WORLDSMARK("NET.worlds.console.BookmarkMenuItem"),
LIBRARY("NET.worlds.scape.Library");
public final String name;
WorldsType(String name) {
this.name = name;
}
public static WorldsType valueOfClass(String name) {
for (WorldsType e : values()) {
if (e.name.equals(name)) {
return e;
}
}
return null;
}
}
public class WorldListObject implements Cloneable {
public WorldsType classType = null;
private List<WorldList> values = new ArrayList<>();
public WorldListObject clone() {
try {
return (WorldListObject) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
WorldListObject() {
}
public void determineClassType(String className) {
switch (className) {
default:
break;
case "NET.worlds.console.SavedAvMenuItem":
classType = WorldsType.AVATAR;
break;
case "NET.worlds.console.BookmarkMenuItem":
classType = WorldsType.WORLDSMARK;
break;
case "NET.worlds.scape.Library":
classType = WorldsType.LIBRARY;
break;
}
}
public List<WorldList> getValues() {
return values;
}
public void setValues(List<WorldList> values) {
this.values = values;
}
public int size() {
return values.size();
}
public boolean isEmpty() {
return values.isEmpty();
}
public boolean contains(WorldList o) {
return values.contains(o);
}
public Iterator iterator() {
return values.iterator();
}
public WorldList[] toArray() {
return values.toArray(new WorldList[0]);
}
public boolean add(WorldList o) {
return values.add(o);
}
public boolean remove(Object o) {
return values.remove(o);
}
public boolean addAll(Collection collection) {
return values.addAll(collection);
}
public boolean addAll(int i, Collection collection) {
return values.addAll(i, collection);
}
public void clear() {
values = new ArrayList<>();
}
public WorldList get(int i) {
return values.get(i);
}
public WorldList set(int i, WorldList o) {
return values.set(i, o);
}
public void add(int i, WorldList o) {
values.add(i, o);
}
public WorldList remove(int i) {
return values.remove(i);
}
public int indexOf(WorldList o) {
return values.indexOf(o);
}
public int lastIndexOf(WorldList o) {
return values.lastIndexOf(o);
}
public ListIterator listIterator() {
return values.listIterator();
}
public ListIterator listIterator(int i) {
return values.listIterator(i);
}
public List subList(int i, int i1) {
return values.subList(i, i1);
}
public boolean retainAll(Collection collection) {
return values.retainAll(collection);
}
public boolean removeAll(Collection collection) {
return values.removeAll(collection);
}
public boolean containsAll(Collection collection) {
return values.containsAll(collection);
}
public WorldList[] toArray(WorldList[] lists) {
return values.toArray(lists);
}
}

View File

@@ -0,0 +1,53 @@
package org.worlio.WorldsOrganizer;
public class WorldTableItem implements WorldList {
private int index;
private String name;
private String value;
private String status;
WorldTableItem(int i, String n, String v) {
index = i;
name = n;
value = v;
}
WorldTableItem(int i, String n, String v, boolean s) {
index = i;
name = n;
value = v;
status = (s ? "PASS" : "FAIL");
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@@ -0,0 +1,9 @@
package org.worlio.WorldsOrganizer;
public class WorldsOrganizer {
public static void main(String[] args) {
Main.main(args);
}
}

View File

@@ -0,0 +1,930 @@
package org.worlio.WorldsOrganizer;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.concurrent.Task;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class WorldsTab {
File file;
private Tab tab = null;
Control content = null;
Pane mainPane;
private boolean showingFinder = false;
private boolean modified = false;
WorldListObject worldList = new WorldListObject();
private final CommandStack commandStack = new CommandStack();
public WorldsTab() {
}
public Tab getTab(File file) {
return getTab(WorldsType.NULL, file);
}
public Tab getTab(WorldsType type) {
return getTab(type, null);
}
public Tab getTab(WorldsType type, File file) {
if (tab != null) {
return tab;
} else {
Restorer restorer;
if (file != null) {
this.file = file;
try {
restorer = new Restorer(file);
worldList = restorer.read();
} catch (IOException e) {
return null;
}
} else {
assert type != null;
worldList.classType = type;
worldList.add(createItem(type));
}
Tab tab;
switch (worldList.classType) {
default:
tab = new Tab(); break;
case AVATAR: case WORLDSMARK:
tab = new Tab(generateTitle(), getWorldList()); break;
}
this.tab = tab;
update();
tab.setOnCloseRequest(event -> {
Console.print("Performing tab close", 1, ConsoleType.INFO);
event.consume();
quitTab();
});
return tab;
}
}
public Pane getWorldList() {
if (mainPane != null) {
return mainPane;
} else {
content = new TableView<WorldList>();
((TableView<?>)content).setEditable(true);
ToolBar toolBar = new ToolBar();
Console.print("Tab initialized", 1, ConsoleType.INFO);
Button addBtn = new Button();
addBtn.setTooltip(new Tooltip("Add Value"));
addBtn.setGraphic(new ImageView(AppIcon.add));
toolBar.getItems().add(addBtn);
addBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
int tabIndex = Main.tabs.indexOf(this);
if (tabIndex >= 0) {
this.addItem();
this.setFocus(((TableView<?>)content).getItems().size() - 1);
Main.tabs.set(tabIndex, this);
}
});
Button delBtn = new Button();
delBtn.setTooltip(new Tooltip("Delete Value"));
delBtn.setGraphic(new ImageView(AppIcon.remove));
toolBar.getItems().add(delBtn);
delBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
int tabIndex = Main.tabs.indexOf(this);
if (tabIndex >= 0) {
int index = ((TableView<?>)content).getSelectionModel().getFocusedIndex();
this.deleteItem(index);
this.setFocus(index < ((TableView<?>)content).getItems().size() ? index : index - 1);
Main.tabs.set(tabIndex, this);
}
});
Button mupBtn = new Button();
mupBtn.setTooltip(new Tooltip("Move Value Up"));
mupBtn.setGraphic(new ImageView(AppIcon.moveUp));
toolBar.getItems().add(mupBtn);
mupBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
int tabIndex = Main.tabs.indexOf(this);
if (tabIndex >= 0) {
int index = ((TableView<?>)content).getSelectionModel().getFocusedIndex();
this.moveValue(index, -1);
this.setFocus(index - 1);
Main.tabs.set(tabIndex, this);
}
});
Button mdwBtn = new Button();
mdwBtn.setTooltip(new Tooltip("Move Value Down"));
mdwBtn.setGraphic(new ImageView(AppIcon.moveDown));
toolBar.getItems().add(mdwBtn);
mdwBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
int tabIndex = Main.tabs.indexOf(this);
if (tabIndex >= 0) {
int index = ((TableView<?>)content).getSelectionModel().getFocusedIndex();
this.moveValue(index, 1);
this.setFocus(index + 1);
Main.tabs.set(tabIndex, this);
}
});
toolBar.getItems().add(new Separator());
Button findBtn = new Button();
findBtn.setTooltip(new Tooltip("Find/Replace"));
findBtn.setGraphic(new ImageView(AppIcon.findReplace));
toolBar.getItems().add(findBtn);
VBox findingBox = getFindPane();
VBox.setVgrow(findingBox, Priority.ALWAYS);
findingBox.setVisible(false);
findingBox.setManaged(false);
findBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
Console.print("Toggled Find/Replace pane", 1, ConsoleType.INFO);
findingBox.setManaged(!showingFinder);
findingBox.setVisible(!showingFinder);
showingFinder = !showingFinder;
});
Button checkBtn = new Button();
checkBtn.setTooltip(new Tooltip("Link Checker"));
checkBtn.setGraphic(new ImageView(AppIcon.linkCheck));
toolBar.getItems().add(checkBtn);
checkBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
Console.print("Beginning Link Checker", 1, ConsoleType.INFO);
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.getDialogPane().setMinWidth(600);
alert.setResizable(true);
alert.setTitle("Link Checker");
alert.setHeaderText("Checking Links...");
alert.initOwner(Main.mainStage);
TableView<WorldTableItem> checkTable = new TableView<>();
checkTable.setEditable(false);
checkTable.setMaxWidth(Double.MAX_VALUE);
checkTable.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(checkTable, Priority.ALWAYS);
GridPane.setHgrow(checkTable, Priority.ALWAYS);
TableColumn<WorldTableItem, Integer> checkIndexColumn = new TableColumn<>("#");
checkIndexColumn.prefWidthProperty().bind(content.widthProperty().multiply(0.05));
checkIndexColumn.setCellValueFactory(new PropertyValueFactory<>("index"));
TableColumn<WorldTableItem, String> checkLabelColumn = new TableColumn<>("Label");
checkLabelColumn.prefWidthProperty().bind(content.widthProperty().multiply(0.4));
checkLabelColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
TableColumn<WorldTableItem, String> checkValueColumn = new TableColumn<>("Value");
checkValueColumn.prefWidthProperty().bind(content.widthProperty().multiply(0.4));
checkValueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
TableColumn<WorldTableItem, String> checkStatusColumn = new TableColumn<>("Status");
checkStatusColumn.prefWidthProperty().bind(content.widthProperty().multiply(0.1));
checkStatusColumn.setCellValueFactory(new PropertyValueFactory<>("status"));
checkTable.getColumns().addAll(checkIndexColumn, checkLabelColumn, checkValueColumn, checkStatusColumn);
alert.getDialogPane().setContent(checkTable);
alert.initOwner(Main.mainStage.getOwner());
List<WorldTableItem> errorItems = new ArrayList<>();
AtomicBoolean haltThread = new AtomicBoolean(false);
Task<Boolean> task = new Task<Boolean>() {
@Override public Boolean call() {
for (int w = 0; w < ((TableView<?>)content).getItems().size(); w++) {
if (haltThread.get()) return true;
WorldList wl = (WorldList)((TableView<?>)content).getItems().get(w);
String value = wl.getValue();
int index = ((TableView<?>)content).getItems().indexOf(wl);
WorldTableItem tabItem;
if (value.startsWith("http")) {
Console.print("Trying '" + value + "'", 1, ConsoleType.INFO);
try {
if (!Console.testURL(value)) {
Console.print("URL '" + value + "' failed!", 1, ConsoleType.ERROR);
tabItem = new WorldTableItem(index, wl.getName(), value, false);
errorItems.add(tabItem);
} else {
Console.print("URL '" + value + "' passed!", 1, ConsoleType.SUCCESS);
tabItem = new WorldTableItem(index, wl.getName(), value, true);
}
checkTable.getItems().add(0, tabItem);
} catch (IOException ioException) {
Console.print("IOException encountered while checking URLs for Link Checker.", ConsoleType.ERROR);
ioException.printStackTrace();
Dialog.showException(ioException);
return false;
}
}
checkTable.refresh();
}
return true;
}
};
task.setOnRunning((a) -> alert.show());
task.setOnSucceeded((a) -> {
alert.close();
showLinkResults(errorItems);
});
task.setOnFailed((a) -> {
Console.print("Link Checking failed for unknown reasons.", ConsoleType.ERROR);
Dialog.showException(new Exception("Unknown"));
alert.close();
});
Thread taskTh = new Thread(task);
taskTh.start();
alert.setOnCloseRequest((a) -> {
Console.print("Closing Link Check", 1, ConsoleType.INFO);
haltThread.set(true);
alert.close();
});
});
TableColumn<WorldList, String> indexColumn = new TableColumn<>("#");
indexColumn.prefWidthProperty().bind(content.widthProperty().multiply(0.05));
indexColumn.setCellValueFactory(p -> new ReadOnlyObjectWrapper(((TableView<?>)content).getItems().indexOf(p.getValue())));
indexColumn.setSortable(false);
indexColumn.setEditable(false);
TableColumn<WorldList, String> labelColumn = new TableColumn<>("Label");
labelColumn.prefWidthProperty().bind(content.widthProperty().multiply(0.4));
labelColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
labelColumn.setCellFactory(TextFieldTableCell.forTableColumn());
labelColumn.setSortable(false);
labelColumn.setOnEditCommit(t -> {
commandStack.doCommand(new Command() {
final String oldValue = t.getOldValue();
final String newValue = t.getNewValue();
WorldList item = t.getTableView().getItems().get(t.getTablePosition().getRow());
@Override
public void execute() {
Console.print("Editing Label: '" + oldValue + "' -> '" + newValue + "'", 1, ConsoleType.DEBUG);
t.getTableView().getItems().get(t.getTablePosition().getRow()).setName(newValue);
((TableView<?>) content).refresh();
setSaved(false);
}
@Override
public void undo() {
Console.print("Undoing Label: '" + oldValue + "' <- '" + newValue + "'", 1, ConsoleType.DEBUG);
item.setName(oldValue);
((TableView<?>)content).refresh();
setSaved(false);
}
});
});
TableColumn<WorldList, String> valueColumn = new TableColumn<>("Value");
valueColumn.prefWidthProperty().bind(content.widthProperty().multiply(0.525));
valueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
valueColumn.setCellFactory(TextFieldTableCell.forTableColumn());
valueColumn.setSortable(false);
valueColumn.setOnEditCommit(t -> {
commandStack.doCommand(new Command() {
final String oldValue = t.getOldValue();
final String newValue = t.getNewValue();
WorldList item = t.getTableView().getItems().get(t.getTablePosition().getRow());
@Override
public void execute() {
Console.print("Editing Value: '" + oldValue + "' -> '" + newValue + "'", 1, ConsoleType.DEBUG);
t.getTableView().getItems().get(t.getTablePosition().getRow()).setValue(newValue);
((TableView<?>) content).refresh();
setSaved(false);
}
@Override
public void undo() {
Console.print("Undoing Value: '" + oldValue + "' <- '" + newValue + "'", 1, ConsoleType.DEBUG);
item.setValue(oldValue);
((TableView<?>)content).refresh();
setSaved(false);
}
});
});
for (WorldList list : worldList.getValues()) {
((TableView<WorldList>)content).getItems().add(list);
}
Console.print("List values added.", 1, ConsoleType.INFO);
((TableView<WorldList>)content).getColumns().addAll(indexColumn, labelColumn, valueColumn);
VBox.setVgrow(content, Priority.ALWAYS);
HBox.setHgrow(toolBar, Priority.ALWAYS);
VBox.setVgrow(toolBar, Priority.ALWAYS);
VBox endV = new VBox(content, findingBox);
HBox.setHgrow(endV, Priority.ALWAYS);
VBox.setVgrow(endV, Priority.ALWAYS);
switch (Main.configManager.getIntValue(ConfigEntry.toolbarPos)) {
case 0:
toolBar.setOrientation(Orientation.HORIZONTAL);
return new VBox(toolBar, endV);
case 1:
toolBar.setOrientation(Orientation.VERTICAL);
return new HBox(endV, toolBar);
case 2:
toolBar.setOrientation(Orientation.HORIZONTAL);
return new VBox(endV, toolBar);
default:
case 3:
toolBar.setOrientation(Orientation.VERTICAL);
return new HBox(toolBar, endV);
}
}
}
public void addItem() {
assert content instanceof TableView;
commandStack.doCommand(new Command() {
WorldList newData;
@Override
public void execute() {
Console.print("Adding new item", 1, ConsoleType.DEBUG);
newData = createItem(worldList.classType);
worldList.add(newData);
((TableView)content).getItems().add(newData);
setSaved(false);
}
@Override
public void undo() {
Console.print("Undoing new item", 1, ConsoleType.DEBUG);
worldList.remove(newData);
((TableView)content).getItems().remove(newData);
setSaved(false);
}
});
}
public void deleteItem(int i) {
assert content instanceof TableView;
if (i >= 0 && ((TableView<?>)content).getItems().size() > i) {
commandStack.doCommand(new Command() {
WorldList item = (WorldList) ((TableView<?>) content).getItems().get(i);
int index = i;
@Override
public void execute() {
Console.print("Deleting Item", 1, ConsoleType.DEBUG);
worldList.remove(i);
((TableView) content).getItems().remove(i);
setSaved(false);
}
@Override
public void undo() {
Console.print("Undoing Delete", 1, ConsoleType.DEBUG);
worldList.add(index, item);
((TableView) content).getItems().add(index, item);
setSaved(false);
}
});
} else Console.print("Unable to delete item: No item selected!", ConsoleType.WARNING);
}
public void moveValue(int i, int moveBy) {
assert content instanceof TableView;
if (i >= 0 && i + moveBy >= 0 && ((TableView<?>)content).getItems().size() > i && ((TableView<?>)content).getItems().size() > i + moveBy) {
commandStack.doCommand(new Command() {
final WorldList item = (WorldList) ((TableView) content).getItems().get(i);
final WorldList rItem = (WorldList) ((TableView) content).getItems().get(i + moveBy);
final int index = i;
final int moved = moveBy;
@Override
public void execute() {
Console.print("Moving index " + index + " by " + moveBy, 1, ConsoleType.DEBUG);
doMove(i, rItem);
doMove(i + moveBy, item);
setSaved(false);
}
@Override
public void undo() {
Console.print("Undoing move of index " + index + " by " + moveBy, 1, ConsoleType.DEBUG);
doMove(index + moved, rItem);
doMove(index, item);
setSaved(false);
}
private void doMove(int i, WorldList o) {
((TableView) content).getItems().set(i, o);
worldList.set(i, o);
}
});
} else Console.print("Cannot move item.", ConsoleType.WARNING);
}
public void setFocus(int i) {
Console.print("Forced Focus on index " + i, 1, ConsoleType.DEBUG);
((TableView)content).getSelectionModel().select(i);
((TableView)content).scrollTo(i);
}
private void quitTab() {
if (!getSaved()) {
Console.print("Displaying Quit alert", 1, ConsoleType.DEBUG);
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Close Tab");
alert.setHeaderText("Are you sure you want to close this tab?");
alert.setContentText("You have unsaved changes. Closing now will lose your progress.");
alert.initOwner(Main.mainStage);
ButtonType dontSaveButton = new ButtonType("Discard Changes");
ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
alert.getButtonTypes().setAll(dontSaveButton, buttonTypeCancel);
alert.getDialogPane().setMinSize(200,200);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == dontSaveButton) {
closeTab();
} else {
alert.close();
Main.setStatusText("Tab Alert Closed");
}
} else {
closeTab();
}
}
private void closeTab() {
Main.setStatusText("Closing Tab");
int index = tab.getTabPane().getSelectionModel().getSelectedIndex() - 1;
Main.tabs.remove(index);
EventHandler<Event> handler = tab.getOnClosed();
if (null != handler) {
handler.handle(null);
} else {
tab.getTabPane().getTabs().remove(tab);
}
Console.print("Tab closed", 1, ConsoleType.DEBUG);
}
private void setIcon(WorldsType type) {
switch (type) {
default:
tab.setGraphic(new ImageView(AppIcon.unknownFile));
break;
case AVATAR:
tab.setGraphic(new ImageView(AppIcon.avatarFile));
break;
case WORLDSMARK:
tab.setGraphic(new ImageView(AppIcon.markFile));
break;
}
}
public void update() {
Console.print("Performing tooltip and title update", 1, ConsoleType.DEBUG);
if (file != null) tab.setTooltip(new Tooltip(file.getAbsolutePath()));
else tab.setTooltip(new Tooltip(worldList.classType.name));
tab.setText(generateTitle());
setIcon(worldList.classType);
}
public void update(File newFile) {
this.file = newFile;
update();
}
private String generateTitle() {
if (file != null) {
return file.getName();
} else {
switch (worldList.classType) {
default:
return "Untitled";
case AVATAR:
return "Untitled.avatars";
case WORLDSMARK:
return "Untitled.worldsmarks";
}
}
}
public void setSaved(boolean value) {
if (!value) {
modified = true;
tab.setGraphic(new ImageView(AppIcon.saveFile));
} else{
update();
modified = false;
}
}
public boolean getSaved() {
return !modified;
}
public WorldList createItem(WorldsType type) {
switch (type) {
default:
return null;
case AVATAR:
return new AvatarObject("New Avatar", "avatar:holden.mov");
case WORLDSMARK:
return new MarkObject("New Mark", "home:GroundZero/groundzero.world");
}
}
public void doUndo() {
if (commandStack.canUndo()) {
commandStack.undo();
Main.setStatusText("Undid last operation.");
} else {
Console.print("Nothing to undo.");
Main.setStatusText("Nothing to undo.");
}
}
public void doRedo() {
if (commandStack.canRedo()) {
commandStack.redo();
Main.setStatusText("Redid last operation.");
} else {
Console.print("Nothing to redo.");
Main.setStatusText("Nothing to redo.");
}
}
public void showLinkResults(List<WorldTableItem> list) {
Console.print("Displaying Link Checker results", 1, ConsoleType.INFO);
AtomicInteger addition = new AtomicInteger();
addition.set(0);
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.getDialogPane().setMinWidth(800);
alert.setResizable(true);
alert.setTitle("Link Checker Results");
alert.setHeaderText("The followings links have been found to be dead: " + list.size() + " out of " + worldList.size());
alert.initOwner(Main.mainStage);
Button deleteBtn = new Button();
deleteBtn.setTooltip(new Tooltip("Delete"));
deleteBtn.setGraphic(new ImageView(AppIcon.remove));
Button deleteAllBtn = new Button("Delete All");
deleteAllBtn.setTooltip(new Tooltip("Delete All"));
deleteAllBtn.setGraphic(new ImageView(AppIcon.removeAll));
TableView<WorldTableItem> errorTable = new TableView<>();
errorTable.setEditable(true);
errorTable.setMaxWidth(Double.MAX_VALUE);
errorTable.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(errorTable, Priority.ALWAYS);
GridPane.setHgrow(errorTable, Priority.ALWAYS);
TableColumn<WorldTableItem, Integer> indexColumn = new TableColumn<>("#");
indexColumn.prefWidthProperty().bind(errorTable.widthProperty().multiply(0.05));
indexColumn.setCellValueFactory(new PropertyValueFactory<>("index"));
indexColumn.setEditable(false);
TableColumn<WorldTableItem, String> labelColumn = new TableColumn<>("Label");
labelColumn.prefWidthProperty().bind(errorTable.widthProperty().multiply(0.4));
labelColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
labelColumn.setCellFactory(TextFieldTableCell.<WorldTableItem>forTableColumn());
labelColumn.setEditable(true);
labelColumn.setOnEditCommit(t -> {
commandStack.doCommand(
new Command() {
String oldValue = t.getOldValue();
String newValue = t.getNewValue();
WorldList item = t.getTableView().getItems().get(t.getTablePosition().getRow());
WorldList tableItem = ((WorldList) ((TableView) content).getItems().get(t.getRowValue().getIndex() + addition.get()));
@Override
public void execute() {
item.setName(newValue);
tableItem.setName(newValue);
((TableView) content).refresh();
setSaved(false);
}
@Override
public void undo() {
item.setName(oldValue);
tableItem.setName(oldValue);
((TableView) content).refresh();
setSaved(false);
}
});
});
TableColumn<WorldTableItem, String> valueColumn = new TableColumn<>("Value");
valueColumn.prefWidthProperty().bind(errorTable.widthProperty().multiply(0.525));
valueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
valueColumn.setCellFactory(TextFieldTableCell.<WorldTableItem>forTableColumn());
valueColumn.setEditable(true);
valueColumn.setOnEditCommit(t -> {
commandStack.doCommand(
new Command() {
String oldValue = t.getOldValue();
String newValue = t.getNewValue();
WorldList item = t.getTableView().getItems().get(t.getTablePosition().getRow());
WorldList tableItem = ((WorldList) ((TableView) content).getItems().get(t.getRowValue().getIndex() + addition.get()));
@Override
public void execute() {
item.setValue(newValue);
tableItem.setValue(newValue);
((TableView) content).refresh();
setSaved(false);
}
@Override
public void undo() {
item.setValue(oldValue);
tableItem.setValue(oldValue);
((TableView) content).refresh();
setSaved(false);
}
});
});
for (WorldTableItem item : list) {
errorTable.getItems().add(item);
}
ToolBar btnBar = new ToolBar();
btnBar.getItems().addAll(deleteBtn, deleteAllBtn);
errorTable.getColumns().addAll(indexColumn, labelColumn, valueColumn);
VBox vBox = new VBox(errorTable, btnBar);
alert.getDialogPane().setContent(vBox);
deleteBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> { commandStack.doCommand(
new Command() {
int selected = errorTable.getSelectionModel().getSelectedIndex();
int tableSel = errorTable.getItems().get(selected).getIndex();
WorldTableItem item = errorTable.getItems().get(selected);
int added = tableSel + addition.get();
@Override
public void execute() {
worldList.remove(tableSel + addition.get());
((TableView)content).getItems().remove(tableSel + addition.get());
errorTable.getItems().remove(selected);
list.remove(selected);
addition.getAndDecrement();
setSaved(false);
}
@Override
public void undo() {
worldList.add(added, item);
((TableView)content).getItems().add(added, item);
errorTable.getItems().add(selected, item);
list.add(selected, item);
addition.getAndIncrement();
setSaved(false);
}
});
});
deleteAllBtn.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
Alert askSure = new Alert(Alert.AlertType.CONFIRMATION);
askSure.setTitle("Delete All?");
askSure.setHeaderText("Are you sure you want to delete all the items in this list?");
askSure.setContentText("You won't be able to undo this change!");
ButtonType delSureButton = new ButtonType("Discard Changes");
ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
askSure.getButtonTypes().setAll(delSureButton, buttonTypeCancel);
askSure.getDialogPane().setMinSize(200,200);
Optional<ButtonType> result = askSure.showAndWait();
if (result.get() == delSureButton) {
for (WorldTableItem item : list) {
errorTable.getItems().remove(0);
worldList.remove(item.getIndex() + addition.get());
((TableView) content).getItems().remove(item.getIndex() + addition.get());
addition.getAndDecrement();
}
setSaved(false);
} else {
askSure.close();
}
});
alert.showAndWait();
}
private VBox getFindPane() {
Console.print("Initializing FindPane", 1, ConsoleType.INFO);
Text findText = new Text("Find Text");
findText.setFont(Font.font("Verdana", FontWeight.NORMAL, FontPosture.REGULAR, 12));
TextField findInput = new TextField();
Text replText = new Text("Replace Text");
replText.setFont(Font.font("Verdana", FontWeight.NORMAL, FontPosture.REGULAR, 12));
TextField replInput = new TextField();
Slider selSlider = new Slider(-1,1,0);
selSlider.setMajorTickUnit(1);
selSlider.setMinorTickCount(0);
selSlider.setSnapToTicks(true);
Text labelTxt = new Text("Label");
Text valueTxt = new Text("Value");
HBox.setHgrow(selSlider, Priority.ALWAYS);
HBox.setHgrow(labelTxt, Priority.ALWAYS);
HBox.setHgrow(valueTxt, Priority.ALWAYS);
GridPane findBar = new GridPane();
Button findButton = new Button("Find");
findButton.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
Console.print("Performing find", 1, ConsoleType.INFO);
int curI = ((TableView)content).getSelectionModel().getSelectedIndex();
if (curI < 0) curI = 0;
Main.setStatusText("Searching...");
for (int a = curI+1; a < worldList.size(); a++) {
if (worldList.get(a).getName().contains(findInput.getCharacters()) || worldList.get(a).getValue().contains(findInput.getCharacters())) {
setFocus(a);
break;
}
}
});
Button replButton = new Button("Replace");
replButton.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
commandStack.doCommand(new Command() {
WorldList replaced;
final int index = ((TableView<WorldList>)content).getSelectionModel().getSelectedIndex();
final double slider = selSlider.getValue();
@Override
public void execute() {
Console.print("Performing replace", 1, ConsoleType.INFO);
WorldList item = ((TableView<WorldList>)content).getSelectionModel().getSelectedItem();
if (item.getName().contains(findInput.getCharacters()) || item.getValue().contains(findInput.getCharacters())) {
WorldTableItem tableItem = new WorldTableItem(((TableView) content).getItems().indexOf(item), item.getName(), item.getValue());
if (selSlider.getValue() >= 0)
item.setValue(item.getValue().replace(findInput.getCharacters(), replInput.getCharacters()));
if (selSlider.getValue() <= 0)
item.setName(item.getName().replace(findInput.getCharacters(), replInput.getCharacters()));
Main.setStatusText("Replaced item");
replaced = tableItem;
}
((TableView) content).refresh();
setSaved(false);
}
@Override
public void undo() {
WorldList item = (WorldList)((TableView) content).getItems().get(index);
if (slider >= 0) item.setValue(replaced.getValue());
if (slider <= 0) item.setName(replaced.getName());
((TableView) content).refresh();
setSaved(false);
}
});
});
Button replAllButton = new Button("Replace All");
replAllButton.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
commandStack.doCommand(new Command() {
final List<WorldTableItem> replaced = new ArrayList<>();
final double slider = selSlider.getValue();
@Override
public void execute() {
Console.print("Performing replace all", 1, ConsoleType.INFO);
int count = 0;
for (WorldList item : worldList.getValues()) {
if (item.getName().contains(findInput.getCharacters()) || item.getValue().contains(findInput.getCharacters())) {
count++;
WorldTableItem tableItem = new WorldTableItem(((TableView)content).getItems().indexOf(item), item.getName(), item.getValue());
if (selSlider.getValue() >= 0) item.setValue(item.getValue().replace(findInput.getCharacters(), replInput.getCharacters()));
if (selSlider.getValue() <= 0) item.setName(item.getName().replace(findInput.getCharacters(), replInput.getCharacters()));
replaced.add(tableItem);
}
}
Main.setStatusText("Replaced " + count + " items.");
((TableView)content).refresh();
setSaved(false);
}
@Override
public void undo() {
for (WorldTableItem tableItem : replaced) {
WorldList item = (WorldList)((TableView)content).getItems().get(tableItem.getIndex());
if (slider >= 0) item.setValue(tableItem.getValue());
if (slider <= 0) item.setName(tableItem.getName());
}
((TableView) content).refresh();
setSaved(false);
}
});
});
ButtonBar btns = new ButtonBar();
btns.getButtons().addAll(findButton, replButton, replAllButton);
GridPane.setColumnSpan(btns, 2);
findBar.add(findText, 0, 0);
findBar.add(findInput, 1, 0);
findBar.add(replText, 0, 1);
findBar.add(replInput, 1, 1);
findBar.add(new HBox(labelTxt, selSlider, valueTxt), 0, 2);
findBar.add(btns, 1, 2);
GridPane.setHgrow(findInput, Priority.ALWAYS);
GridPane.setHgrow(replInput, Priority.ALWAYS);
GridPane.setHgrow(btns, Priority.ALWAYS);
findBar.setHgap(5);
findBar.setVgap(5);
findBar.setPadding(new Insets(10, 10, 10, 10));
VBox.setVgrow(findBar, Priority.ALWAYS);
Console.print("Completed FindPane", 1, ConsoleType.INFO);
return new VBox(findBar);
}
}

View File

@@ -0,0 +1,8 @@
.root {
-fx-base: rgba(25, 25, 25, 255);
}
.table-view {
-fx-base: rgba(25,25,25,255);
text-color: rgba(200,200,200,255);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
src/main/resources/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -0,0 +1,3 @@
version=${project.version}
artifactId=${project.artifactId}
buildDate=${buildNumber}