summaryrefslogtreecommitdiffstats
path: root/logo/src/xlogo/storage
diff options
context:
space:
mode:
Diffstat (limited to 'logo/src/xlogo/storage')
-rw-r--r--logo/src/xlogo/storage/Storable.java158
-rw-r--r--logo/src/xlogo/storage/StorableDocument.java14
-rw-r--r--logo/src/xlogo/storage/StorableObject.java107
-rw-r--r--logo/src/xlogo/storage/WSManager.java6
-rw-r--r--logo/src/xlogo/storage/global/GlobalConfig.java658
-rw-r--r--logo/src/xlogo/storage/user/DrawQuality.java6
-rw-r--r--logo/src/xlogo/storage/user/LookAndFeel.java6
-rw-r--r--logo/src/xlogo/storage/user/PenShape.java6
-rw-r--r--logo/src/xlogo/storage/user/UserConfig.java8
-rw-r--r--logo/src/xlogo/storage/workspace/ContestConfig.java6
-rw-r--r--logo/src/xlogo/storage/workspace/Language.java6
-rw-r--r--logo/src/xlogo/storage/workspace/NumberOfBackups.java6
-rw-r--r--logo/src/xlogo/storage/workspace/SyntaxHighlightConfig.java6
-rw-r--r--logo/src/xlogo/storage/workspace/WorkspaceConfig.java519
14 files changed, 944 insertions, 568 deletions
diff --git a/logo/src/xlogo/storage/Storable.java b/logo/src/xlogo/storage/Storable.java
index ad5adf2..97e19a3 100644
--- a/logo/src/xlogo/storage/Storable.java
+++ b/logo/src/xlogo/storage/Storable.java
@@ -1,25 +1,24 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/*
+ * XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
- *
* Contact Information: marko88zivkovic at gmail dot com
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version. This program is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details. You should have received a copy of the
- * GNU General Public License along with this program; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version. This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details. You should have received a copy of the
+ * GNU General Public License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
- *
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
@@ -30,54 +29,49 @@ package xlogo.storage;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
-import java.util.StringTokenizer;
-public abstract class Storable implements Serializable
-{
+public abstract class Storable implements Serializable {
/**
*
*/
private static final long serialVersionUID = 3506253939129765438L;
-
+
/**
* The file's name with extension
*/
- private String fileName;
+ private String fileName;
/**
* The Directory where this is stored
*/
- private File location;
-
+ private File location;
+
/**
* Dirty : an object is dirty if it was changed since it was loaded or stored the last time.
*/
- private transient boolean dirty = true;
+ private transient boolean dirty = true;
/**
* Will not be stored if virtual.
*/
- private transient boolean isVirtual = false;
+ private transient boolean isVirtual = false;
/*
* PATH BUILDERS
*/
- public static File getFile(File dir, String fileName)
- {
+ public static File getFile(File dir, String fileName) {
return new File(dir.toString() + File.separator + fileName);
}
-
- public static File getDirectory(File prefix, String dirName)
- {
+ public static File getDirectory(File prefix, String dirName) {
return new File(prefix.toString() + File.separator + dirName);
}
/*
* Abstract
*/
-
+
/**
* Store this object to the file specified by {@link #getFilePath()} if it is dirty
* @throws IOException
@@ -99,16 +93,14 @@ public abstract class Storable implements Serializable
public abstract String getFileNameExtension();
- public String getFileName()
- {
+ public String getFileName() {
return getPlainName() + getFileNameExtension();
}
/**
* @return FileName without file extension
*/
- public String getPlainName()
- {
+ public String getPlainName() {
return fileName;
}
@@ -128,15 +120,13 @@ public abstract class Storable implements Serializable
String ext = getFileNameExtension();
String oldName = getPlainName();
- String newName = newFileName.endsWith(ext) && newFileName.length() > ext.length() ?
- newFileName.substring(0, newFileName.length() - ext.length())
- : newFileName;
+ String newName = newFileName.endsWith(ext) && newFileName.length() > ext.length() ? newFileName.substring(0,
+ newFileName.length() - ext.length()) : newFileName;
if (newName.equals(oldName) && oldName != null)
return;
- if (isVirtual || oldName == null)
- {
+ if (isVirtual || oldName == null) {
this.fileName = newFileName;
return;
}
@@ -148,51 +138,64 @@ public abstract class Storable implements Serializable
return;
File newPath = getFilePath();
- if(newPath.exists())
- newPath.delete();
-
- oldPath.renameTo(newPath);
+ if (newPath.exists())
+ newPath.delete();
+
+ oldPath.renameTo(newPath);
}
/**
* @return the directory where this should be stored to.
*/
- public File getLocation()
- {
+ public File getLocation() {
return location;
}
/**
- * If the specified location does not exist yet, it is created using mkdirs.<br>
* To set null or a file that is not a directory or a directory with no write permissions is an error, as long as this is not virtual.<br>
* Setting location has no effect if this is virtual.<br>
* @param location - the directory where this should be stored to.
* @throws IOException
* @throws IOException If the specified location is not a directory or no write permissions exist, or the chosen name is not legal.
*/
- public void setLocation(File location) throws IllegalArgumentException
- {
- if(isVirtual)
- return;
+ public void setLocation(File location) throws IllegalArgumentException {
+ if (isVirtual) { return; }
- if (location == null)
- throw new IllegalArgumentException("Location must not be null.");
+ if (location == null) { throw new IllegalArgumentException("Location must not be null."); }
- if(!location.isDirectory())
- {
- location.mkdirs();
- }
- if(!location.isDirectory() || !location.canWrite())
- throw new IllegalArgumentException("Cannot store this to specified location : " + location.toString());
this.location = location;
makeDirty();
}
/**
+ * If the specified location does not exist yet, it is created using mkdirs.
+ */
+ public void mkDirs() {
+ mkDirs(location);
+ }
+
+ public void mkDirs(File location) {
+ if (!location.isDirectory()) {
+ location.mkdirs();
+ }
+ if (!location.isDirectory() || !location.canWrite()) { throw new IllegalArgumentException(
+ "Cannot store this to specified location : " + location.toString()); }
+ }
+
+ public void mkParentDirs(File file) {
+ File parent = file.getParentFile();
+ if (!parent.exists()) {
+ parent.mkdirs();
+ }
+
+ if (!parent.isDirectory() || !parent.canWrite()) { throw new IllegalArgumentException(
+ "Cannot store this to specified location : " + location.toString()); }
+ }
+
+ /**
* @return the file where this should be stored to. Returns null if {@link getLocation()} returns null.
*/
- public File getFilePath()
- {
+ public File getFilePath() {
if (getLocation() == null)
return null;
return getFile(getLocation(), getFileName());
@@ -201,32 +204,36 @@ public abstract class Storable implements Serializable
/**
* @return whether the file specified by {@link #getFilePath()} exists.
*/
- public boolean existsPhysically()
- {
+ public boolean existsPhysically() {
if (getFilePath() == null)
return false;
return getFilePath().exists();
- }
+ }
/*
* isDirty
*/
- public boolean isDirty() { return dirty; }
+ public boolean isDirty() {
+ return dirty;
+ }
/**
* Should be called from every setter that sets a property that should be stored later
* @see StorableObject#makeClean()
*/
- protected void makeDirty() { dirty = true; }
+ protected void makeDirty() {
+ dirty = true;
+ }
/**
* Should be called whenever this was synchronized with its version on the file system (load or store)
* @see StorableObject#makeDirty()
*/
- protected void makeClean() { dirty = false; }
-
+ protected void makeClean() {
+ dirty = false;
+ }
/*
* isVirtual
@@ -235,32 +242,35 @@ public abstract class Storable implements Serializable
/**
* @see #isVirtual()
*/
- protected void makeVirtual() { isVirtual = true; }
+ protected void makeVirtual() {
+ isVirtual = true;
+ }
+
/**
* A virtual object will not be stored on the file system, even though {@link store()} was called.
* This allows to use the application without having an actual user account and without automatic saving.
* @return
*/
- public boolean isVirtual() { return isVirtual; }
+ public boolean isVirtual() {
+ return isVirtual;
+ }
// The best I found : http://stackoverflow.com/questions/893977/java-how-to-find-out-whether-a-file-name-is-valid
// some windows specific chars are not contained...
- public static final String ILLEGAL_NAME_CHARACTERS = "/\n\r\t\0\f`?*\\<>|\":";
+ public static final String ILLEGAL_NAME_CHARACTERS = "/\n\r\t\0\f`?*\\<>|\":";
- public static boolean checkLegalName(String name)
- {
+ public static boolean checkLegalName(String name) {
if (name == null || name.length() == 0)
return false;
//StringTokenizer check = new StringTokenizer(name, ILLEGAL_NAME_CHARACTERS, true);
//return (check.countTokens() == 1);
- for(char c : name.toCharArray())
- {
+ for (char c : name.toCharArray()) {
if (ILLEGAL_NAME_CHARACTERS.indexOf(c) > -1)
return false;
}
-
+
return true;
}
diff --git a/logo/src/xlogo/storage/StorableDocument.java b/logo/src/xlogo/storage/StorableDocument.java
index 104f64d..d3fe8ed 100644
--- a/logo/src/xlogo/storage/StorableDocument.java
+++ b/logo/src/xlogo/storage/StorableDocument.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
@@ -37,6 +37,9 @@ import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.util.Calendar;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
import xlogo.storage.user.UserConfig;
import xlogo.storage.workspace.WorkspaceConfig;
@@ -47,6 +50,8 @@ public abstract class StorableDocument extends Storable
*
*/
private static final long serialVersionUID = 8218323197066522297L;
+
+ private static Logger logger = LogManager.getLogger(StorableDocument.class.getSimpleName());
/**
* Contents of the file
@@ -87,6 +92,7 @@ public abstract class StorableDocument extends Storable
return;
File file = getFilePath();
+ logger.trace("Storing document: " + file.getAbsolutePath());
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
@@ -108,8 +114,10 @@ public abstract class StorableDocument extends Storable
@Override
public void storeCopyToFile(File file) throws IOException, IllegalArgumentException
{
+ logger.trace("Storing copy of " + getFileName() + " to " + file.getAbsolutePath());
try
{
+ mkParentDirs(file);
FileOutputStream f = new FileOutputStream(file);
BufferedOutputStream b = new BufferedOutputStream(f);
OutputStreamWriter osw = new OutputStreamWriter(b, "UTF8");
diff --git a/logo/src/xlogo/storage/StorableObject.java b/logo/src/xlogo/storage/StorableObject.java
index 085936a..f48665f 100644
--- a/logo/src/xlogo/storage/StorableObject.java
+++ b/logo/src/xlogo/storage/StorableObject.java
@@ -1,25 +1,24 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/*
+ * XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
- *
* Contact Information: marko88zivkovic at gmail dot com
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version. This program is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details. You should have received a copy of the
- * GNU General Public License along with this program; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version. This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details. You should have received a copy of the
+ * GNU General Public License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
- *
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
@@ -35,25 +34,29 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
/**
* The base class for anything that must be stored persistently.
* @author Marko Zivkovic
*/
public abstract class StorableObject extends Storable implements Serializable {
-
- private static final long serialVersionUID = -1738873382662156052L;
+
+ private static final long serialVersionUID = -1738873382662156052L;
+
+ private static Logger logger = LogManager.getLogger(StorableObject.class.getSimpleName());
/*
* PATH BUILDERS
*/
-
+
/**
* @param c
* @return X4S_ClassName.ser
*/
@SuppressWarnings("rawtypes")
- public static String getX4SObjectFileName(Class c)
- {
+ public static String getX4SObjectFileName(Class c) {
return "X4S_" + c.getSimpleName();
}
@@ -64,8 +67,7 @@ public abstract class StorableObject extends Storable implements Serializable {
* @return pathname for dir/X4S_ClassName.ser
*/
@SuppressWarnings("rawtypes")
- public static String getFilePath(File dir, Class c)
- {
+ public static String getFilePath(File dir, Class c) {
return dir.toString() + File.separator + getX4SObjectFileName(c);
}
@@ -75,23 +77,20 @@ public abstract class StorableObject extends Storable implements Serializable {
* @return file for pathname as defined by {@link #getFilePath(File, Class)}
*/
@SuppressWarnings("rawtypes")
- public static File getFile(File dir, Class c)
- {
+ public static File getFile(File dir, Class c) {
String path = getFilePath(dir, c) + ".ser";
return new File(path);
}
@Override
- public String getFileNameExtension()
- {
+ public String getFileNameExtension() {
return ".ser";
}
/**
* Constructor. The FileName will be equal to
*/
- public StorableObject()
- {
+ public StorableObject() {
setFileName(getX4SObjectFileName(getClass()));
}
@@ -99,24 +98,24 @@ public abstract class StorableObject extends Storable implements Serializable {
* Store & Load
*/
- public void store() throws IOException
- {
- if(isDirty() && !isVirtual())
+ public void store() throws IOException {
+ if (isDirty() && !isVirtual())
storeCopyToFile(getFilePath());
}
- public void storeCopyToFile(File file) throws IOException, IllegalArgumentException
- {
- if(file == null)
+ public void storeCopyToFile(File file) throws IOException, IllegalArgumentException {
+ if (file == null)
throw new IllegalArgumentException("file must not be null.");
- if (!isVirtual())
- {
+ logger.trace("Storing Object to " + file.getAbsolutePath());
+
+ if (!isVirtual()) {
+ mkParentDirs(file);
FileOutputStream fileOut = new FileOutputStream(file);
- ObjectOutputStream out = new ObjectOutputStream(fileOut);
- out.writeObject(this);
- out.close();
- fileOut.close();
+ ObjectOutputStream out = new ObjectOutputStream(fileOut);
+ out.writeObject(this);
+ out.close();
+ fileOut.close();
}
makeClean();
}
@@ -129,20 +128,22 @@ public abstract class StorableObject extends Storable implements Serializable {
* @throws ClassNotFoundException
* @throws ClassCastException
*/
- public static StorableObject loadObject(File file) throws IOException, ClassNotFoundException, ClassCastException
- {
+ public static StorableObject loadObject(File file) throws IOException, ClassNotFoundException, ClassCastException {
+ logger.trace("Loading Object from " + file.getAbsolutePath());
+
FileInputStream fileIn = new FileInputStream(file);
- ObjectInputStream in = new ObjectInputStream(fileIn);
- Object object = in.readObject();
- in.close();
- fileIn.close();
-
- if (!(object instanceof StorableObject))
- throw new ClassCastException("The specified file (" + file.toString() + ") does not contain an instance of Storable: " + object.getClass().toString());
-
- StorableObject storable = (StorableObject) object;
- storable.makeClean();
- return storable;
- }
+ ObjectInputStream in = new ObjectInputStream(fileIn);
+ Object object = in.readObject();
+ in.close();
+ fileIn.close();
+ if (!(object instanceof StorableObject))
+ throw new ClassCastException("The specified file (" + file.toString()
+ + ") does not contain an instance of Storable: " + object.getClass().toString());
+
+ StorableObject storable = (StorableObject) object;
+ storable.makeClean();
+ return storable;
+ }
+
}
diff --git a/logo/src/xlogo/storage/WSManager.java b/logo/src/xlogo/storage/WSManager.java
index 73ef556..e43c0f3 100644
--- a/logo/src/xlogo/storage/WSManager.java
+++ b/logo/src/xlogo/storage/WSManager.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/global/GlobalConfig.java b/logo/src/xlogo/storage/global/GlobalConfig.java
index 6cd9124..5c0a959 100644
--- a/logo/src/xlogo/storage/global/GlobalConfig.java
+++ b/logo/src/xlogo/storage/global/GlobalConfig.java
@@ -1,27 +1,22 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/*
+ * XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
- *
* Contact Information: marko88zivkovic at gmail dot com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version. This program is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details. You should have received a copy of the
- * GNU General Public License along with this program; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version. This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details. You should have received a copy of the
+ * GNU General Public License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
- *
- *
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
- *
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
- *
* Contents of this file were entirely written by Marko Zivkovic
*/
@@ -38,13 +33,24 @@ import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.TreeMap;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import net.samuelcampos.usbdrivedectector.USBDeviceDetectorManager;
+import net.samuelcampos.usbdrivedectector.USBStorageDevice;
+import net.samuelcampos.usbdrivedectector.events.IUSBDriveListener;
+import net.samuelcampos.usbdrivedectector.events.USBStorageEvent;
+import xlogo.AppSettings;
import xlogo.Logo;
import xlogo.messages.MessageKeys;
import xlogo.messages.async.dialog.DialogMessenger;
import xlogo.storage.StorableObject;
import xlogo.storage.WSManager;
+import xlogo.storage.user.UserConfig;
import xlogo.storage.workspace.WorkspaceConfig;
/**
@@ -52,91 +58,137 @@ import xlogo.storage.workspace.WorkspaceConfig;
* @author Marko Zivkovic
*/
public class GlobalConfig extends StorableObject implements Serializable {
-
- private static final long serialVersionUID = 2787615728665011813L;
- public static final String LOGO_FILE_EXTENSION = ".lgo";
- public static boolean DEBUG = true; // TODO set false
+ private static final long serialVersionUID = 2787615728665011813L;
+ private static Logger logger = LogManager.getLogger(GlobalConfig.class.getSimpleName());
+ public static final String LOGO_FILE_EXTENSION = ".lgo";
+ public static boolean DEBUG = true; // TODO set false
+
/**
* Creates the global config at default location, together with a virtual workspace
*/
- protected GlobalConfig()
- {
- try
- {
+ protected GlobalConfig() {
+ try {
setLocation(getDefaultLocation());
}
- catch (IllegalArgumentException ignore) { } // This is thrown if name illegal, but it is legal
+ catch (IllegalArgumentException ignore) {} // This is thrown if name illegal, but it is legal
workspaces = new TreeMap<String, String>();
workspaces.put(WorkspaceConfig.VIRTUAL_WORKSPACE, "");
+ workspaces.put(WorkspaceConfig.USER_DEFAULT_WORKSPACE, WorkspaceConfig.getDefaultWorkspaceDirectory().getAbsolutePath());
}
/**
* If GlobalConfig exists on the file system in default location, it is loaded, otherwise it will be created there.
* @return
*/
- public static GlobalConfig create()
- {
+ public static GlobalConfig create() {
File gcf = getFile(getDefaultLocation(), GlobalConfig.class);
GlobalConfig globalConfig = null;
-
- try
- {
- if (gcf.exists())
+ if (gcf.exists()) {
+ logger.trace("Try to read GlobalConfig from " + gcf.getAbsolutePath());
+ try {
globalConfig = (GlobalConfig) loadObject(gcf);
- else
- {
+ }
+ catch (Exception e) {
+ logger.error("GlobalConfig was corrupted.");
+ DialogMessenger.getInstance().dispatchError(
+ "Error while loading configuration files",
+ "Could not read GlobalConfig file " + e.toString()
+ + "\n Instead creating a new one.\nYou might need to import you workspaces manually.");
+ gcf.delete();
+ globalConfig = null;
+ }
+ }
+
+ if (globalConfig == null) {
+ try {
+ logger.info(gcf.getAbsolutePath() + " not found. Creating new.");
globalConfig = new GlobalConfig();
globalConfig.store();
}
- }catch(Exception e)
- {
- // Best effort : We will try to operate the program without storing anything on disk
- globalConfig = getNewVirtualInstance();
- DialogMessenger.getInstance().dispatchError("Error while setting up XLogo4Schools", "Could not create or open GlobalConfig file at default location: " + e.toString());
+ catch (Exception e) {
+ // Best effort : We will try to operate the program without storing anything on disk
+ logger.error("Cannot store global config at " + gcf.getAbsolutePath() + ". Running in virtual mode.");
+ globalConfig = getNewVirtualInstance();
+ DialogMessenger.getInstance().dispatchError("Error while setting up XLogo4Schools",
+ "Could not create or open GlobalConfig file at default location: " + e.toString());
+ }
}
- globalConfig.enterLastUsedWorkspace();// This is used to have a workspace ready at the beginning, without any user interaction.
+ globalConfig.init();
return globalConfig;
}
- public static GlobalConfig getNewVirtualInstance()
- {
+ protected void init(){
+ logger.trace("Initialize");
+ initUSBWorkspaces();
+ cleanUpWorkspaces();
+ enterInitialWorkspace();
+ }
+
+ private void cleanUpWorkspaces() {
+ logger.trace("Cleaning up workspaces.");
+ Map<String, String> existingWorkspaces = new TreeMap<String, String>();
+ Map<String, String> lostWorkspaces = new TreeMap<String, String>();
+ for (Entry<String, String> e : workspaces.entrySet()) {
+ File file = new File(e.getValue());
+ if (file.exists() || WorkspaceConfig.isSpecialWorkspace(e.getKey(), e.getValue())) {
+ logger.trace("\tConfirmed existence: " + e.getKey() + " at " + e.getValue());
+ existingWorkspaces.put(e.getKey(), e.getValue());
+ }
+ else {
+ logger.trace("\tLost workspace: " + e.getKey() + " at " + e.getValue());
+ if (e.getKey().equals(lastUsedWorkspace)){
+ lastUsedWorkspace = null;
+ currentWorkspace = null;
+ }
+ lostWorkspaces.put(e.getKey(), e.getValue());
+ }
+ }
+
+ if(!existingWorkspaces.containsKey(WorkspaceConfig.USER_DEFAULT_WORKSPACE)){
+ // This might be the case if the GlobalConfig version stored on the disk comes from a version
+ // that did not contain a default workspace
+ existingWorkspaces.put(WorkspaceConfig.USER_DEFAULT_WORKSPACE, WorkspaceConfig.getDefaultWorkspaceLocation().getAbsolutePath());
+ }
+
+ if (lostWorkspaces.size() > 0) {
+ StringBuilder msg = new StringBuilder();
+ msg.append("Some workspaces could not be found:\n"); // TODO translate
+ for (Entry<String, String> e : lostWorkspaces.entrySet()) {
+ msg.append("\t").append(e.getKey()).append(" at ").append(e.getValue()).append("\n");
+ }
+ DialogMessenger.getInstance().dispatchMessage(msg.toString());
+ }
+ workspaces = existingWorkspaces;
+ }
+
+ public static GlobalConfig getNewVirtualInstance() {
GlobalConfig gc = new GlobalConfig();
gc.makeVirtual();
return gc;
}
- /**
- * @return File from system property "user.home"
- */
- public static File getDefaultLocation()
- {
- return new File(System.getProperty("user.home"));
- }
-
- /*
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Physical Workspaces (stored on file system)
- */
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- public void createWorkspace(File dir, String workspaceName) throws IOException
- {
+ public void createWorkspace(File dir, String workspaceName) throws IOException {
+ logger.trace("Creating workspace '" + workspaceName + "' at " + dir.getAbsolutePath());
if (WorkspaceConfig.createNewWorkspace(dir, workspaceName) != null)
addWorkspace(workspaceName, dir.toString());
}
- public void importWorkspace(File workspaceDir, String wsName)
- {
- if(!WSManager.isWorkspaceDirectory(workspaceDir))
- {
- DialogMessenger.getInstance().dispatchError(
- Logo.messages.getString(MessageKeys.WS_ERROR_TITLE),
+ public void importWorkspace(File workspaceDir, String workspaceName) {
+ logger.trace("Importing workspace '" + workspaceName + "' from " + workspaceDir.getAbsolutePath());
+ if (!WSManager.isWorkspaceDirectory(workspaceDir)) {
+ DialogMessenger.getInstance().dispatchError(Logo.messages.getString(MessageKeys.WS_ERROR_TITLE),
workspaceDir + " " + Logo.messages.getString(MessageKeys.WS_NOT_A_WORKSPACE_DIRECTORY));
return;
}
- addWorkspace(wsName, workspaceDir.getParent());
+ addWorkspace(workspaceName, workspaceDir.getParent());
}
/**
@@ -145,93 +197,181 @@ public class GlobalConfig extends StorableObject implements Serializable {
* @return the specified workspace or null if it does not exist.
* @throws IOException
*/
- private WorkspaceConfig retrieveWorkspace(String workspaceName) throws IOException
- {
- if(!existsWorkspace(workspaceName))
- {
- System.out.print("Attempting to load an inexistent workspace.");
+ private WorkspaceConfig retrieveWorkspace(String workspaceName) throws IOException {
+ WorkspaceConfig wsc = getLoadedWorkspace(workspaceName);
+ if (wsc != null) {
+ logger.trace("Retrieving cached workspace: " + workspaceName);
+ return wsc;
+ }
+
+ if (!existsWorkspace(workspaceName)) {
+ logger.warn("Attempting to load an inexistent workspace: " + workspaceName);
return null;
}
- File dir = getWorkspaceLocation(workspaceName);
- WorkspaceConfig wc = WorkspaceConfig.loadWorkspace(dir, workspaceName);
- if (wc == null)
- {
+ File location = getWorkspaceLocation(workspaceName);
+
+ if (WorkspaceConfig.isDefaultWorkspace(workspaceName, location)) {
+ logger.trace("Retrieving Default workspace from: " + location.getAbsolutePath());
+ wsc = getDefaultWorkspace();
+ }
+ else if (isUSBDrive(workspaceName)) {
+ logger.trace("Retrieving USB workspace: " + workspaceName);
+ wsc = initUSBDrive(workspaceName);
+ }
+ else {
+ logger.trace("Retrieving workspace: " + workspaceName + " from " + location.getAbsolutePath());
+ wsc = WorkspaceConfig.loadWorkspace(location, workspaceName);
+ }
+
+ if (wsc == null) {
WSManager.getInstance().deleteWorkspace(workspaceName, false);
}
- return wc;
+ cacheWorkspace(workspaceName, wsc);
+
+ return wsc;
+ }
+
+ private WorkspaceConfig getDefaultWorkspace() throws IOException{
+ File wsDir = WorkspaceConfig.getDefaultWorkspaceDirectory();
+ File wsFile = getFile(wsDir, WorkspaceConfig.class);
+ File wsLocation = WorkspaceConfig.getDefaultWorkspaceLocation();
+ WorkspaceConfig wsc = null;
+ if (wsFile.exists()) {
+ wsc = WorkspaceConfig.loadWorkspace(wsLocation, WorkspaceConfig.USER_DEFAULT_WORKSPACE);
+ } else {
+ wsc = WorkspaceConfig.createNewWorkspace(wsLocation, WorkspaceConfig.USER_DEFAULT_WORKSPACE);
+ wsc.setAllowUserCreation(true);
+ wsc.createUser(UserConfig.DEFAULT_USER);
+ }
+ return wsc;
}
- /*
- * Logical Workspaces (name and location stored in Map)
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Workspace Cache
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /**
+ * Workspace Objects that have already been created or loaded from disk.
*/
+ private transient Map<String, WorkspaceConfig> cachedWorkspaces;
+
+ private WorkspaceConfig getLoadedWorkspace(String workspaceName) {
+ if (cachedWorkspaces == null) {
+ cachedWorkspaces = new TreeMap<String, WorkspaceConfig>();
+ }
+ return cachedWorkspaces.get(workspaceName);
+ }
+
+ private void cacheWorkspace(String workspaceName, WorkspaceConfig wsc) {
+ cachedWorkspaces.put(workspaceName, wsc);
+ }
- private TreeMap<String,String> workspaces;
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Workspaces
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /**
+ * Logical Workspaces (name and location stored in Map)
+ */
+ private Map<String, String> workspaces;
/**
* @param workspaceName
* @param location where the workspace is located: location/workspaceName/
*/
- public void addWorkspace(String workspaceName, String location)
- {
+ public void addWorkspace(String workspaceName, String location) {
+ logger.trace("Adding workspace: '" + workspaceName + "' at " + location);
workspaces.put(workspaceName, location);
makeDirty();
notifyWorkspaceListChanged();
+ setLastUsedWorkspace(workspaceName);
+ enterInitialWorkspace();
}
- public void removeWorkspace(String workspaceName)
- {
+ public void removeWorkspace(String workspaceName) {
+ logger.trace("Removing workspace: " + workspaceName);
workspaces.remove(workspaceName);
+ cachedWorkspaces.remove(workspaceName);
makeDirty();
notifyWorkspaceListChanged();
+ if(lastUsedWorkspace.equals(workspaceName)){
+ lastUsedWorkspace = null;
+ currentWorkspace = null;
+ enterInitialWorkspace();
+ }
+ }
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Workspace File Utility
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /**
+ * @return File from system property "user.home"
+ */
+ public static File getDefaultLocation() {
+ return new File(System.getProperty("user.home"));
}
/**
* @param wsName
- * @return the location of the workspace in the file system, or null if the workspace does not exist
+ * @return the parent directory of the workspace directory, or null if the workspace does not exist
*/
- public File getWorkspaceLocation(String wsName)
- {
+ public File getWorkspaceLocation(String wsName) {
String location = workspaces.get(wsName);
- if(location == null)
+ if (location == null)
return null;
return new File(location);
}
- public File getWorkspaceDirectory(String wsName)
- {
+ /**
+ * @param wsName
+ * @return The workspace Directory that contains a physical representation of {@link WorkspaceConfig}
+ */
+ public File getWorkspaceDirectory(String wsName) {
File wsLocation = getWorkspaceLocation(wsName);
- if(wsLocation == null)
+ if (wsLocation == null)
return null;
return new File(wsLocation.toString() + File.separator + wsName);
}
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Workspaces
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @return the names of all existing workspaces
*/
- public String[] getAllWorkspaces()
- {
+ public String[] getAllWorkspaces() {
return (String[]) workspaces.keySet().toArray(new String[workspaces.size()]);
}
-
+
/**
* A workspace exists logically, if its location is known by the GlobalConfig.
* @param workspace
* @return
*/
- public boolean existsWorkspace(String workspace)
- {
- return getWorkspaceLocation(workspace) != null;
+ public boolean existsWorkspace(String workspace) {
+ return workspaces.get(workspace) != null;
}
- /*
+
+ public String getFirstUSBWorkspace() {
+ for (String ws : workspaces.keySet()) {
+ if (isUSBDrive(ws)) { return ws; }
+ }
+ return null;
+ }
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Last used workspace
- */
- private String lastUsedWorkspace;
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- public String getLastUsedWorkspace()
- {
+ private String lastUsedWorkspace;
+
+ public String getLastUsedWorkspace() {
return lastUsedWorkspace;
}
@@ -239,46 +379,63 @@ public class GlobalConfig extends StorableObject implements Serializable {
* Succeeds if the workspace exists
* @param workspace
*/
- private void setLastUsedWorkspace(String workspace)
- {
- if(existsWorkspace(workspace))
- {
- lastUsedWorkspace = new String(workspace);
+ private void setLastUsedWorkspace(String workspace) {
+ if (existsWorkspace(workspace)) {
+ lastUsedWorkspace = workspace;
makeDirty();
}
}
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Current Workspace
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ private transient WorkspaceConfig currentWorkspace;
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Entering and Leaving Workspaces
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ public WorkspaceConfig getCurrentWorkspace() {
+ return currentWorkspace;
+ }
+
/**
* This is used to have a workspace ready at the beginning, without any user interaction.
* <p>
- * Enters the workspace that was used the last time XLogo4Schools was run on this computer.
- * If no regular workspace is available, a purely logical "virtual workspace" is entered instead.
+ * Tries to enter workspaces with the following priority.
+ * 1. Last used workspace (if any)
+ * 2. Default workspace, if there is no last used workspace
+ * 3. Virtual Workspace, if entering or creating the default workspace failed for some reason.
*/
- private void enterLastUsedWorkspace()
- {
- String last = getLastUsedWorkspace();
+ private void enterInitialWorkspace() {
+ logger.trace("Entering initial workspace.");
+
+ String initialWs = getFirstUSBWorkspace();
+
+ if (initialWs == null) {
+ initialWs = getLastUsedWorkspace();
+ }
- if(last == null || !existsWorkspace(last))
- last = WorkspaceConfig.VIRTUAL_WORKSPACE; // this exists, see constructor
+ if (initialWs == null) {
+ initialWs = WorkspaceConfig.USER_DEFAULT_WORKSPACE;
+ }
+
+ if (initialWs == null) {
+ initialWs = WorkspaceConfig.VIRTUAL_WORKSPACE; // this exists, see constructor
+ }
try {
- enterWorkspace(last);
- } catch (IOException e1) {
- try { enterWorkspace(WorkspaceConfig.VIRTUAL_WORKSPACE); } catch (IOException e2) { }
+ enterWorkspace(initialWs);
+ }
+ catch (IOException e1) {
+ try {
+ enterWorkspace(WorkspaceConfig.VIRTUAL_WORKSPACE);
+ }
+ catch (IOException e2) {}
DialogMessenger.getInstance().dispatchError("Workspace Error", "Cannot enter workspace: " + e1.toString());
}
}
-
- /*
- * Current Workspace
- */
-
- private transient WorkspaceConfig currentWorkspace;
-
- public WorkspaceConfig getCurrentWorkspace()
- {
- return currentWorkspace;
- }
/**
* Load the workspace
@@ -286,10 +443,9 @@ public class GlobalConfig extends StorableObject implements Serializable {
* @param workspaceName - the workspace to load and enter
* @throws IOException - if the workspace could not be loaded
*/
- public void enterWorkspace(String workspaceName) throws IOException
- {
- if(currentWorkspace != null)
- {
+ public void enterWorkspace(String workspaceName) throws IOException {
+ logger.trace("Entering workspace: " + workspaceName);
+ if (currentWorkspace != null) {
leaveWorkspace();
}
currentWorkspace = retrieveWorkspace(workspaceName);
@@ -299,35 +455,130 @@ public class GlobalConfig extends StorableObject implements Serializable {
setLastUsedWorkspace(workspaceName);
notifyWorkspacEntered();
+
+ currentWorkspace.enterInitialUserSpace();
+
+ AppSettings.getInstance().setLanguage(currentWorkspace.getLanguage());
}
/**
+ * Afterwards, currentWorkspace is null
* @throws IOException If workspace could not be saved.
*/
- void leaveWorkspace() throws IOException
- {
- if(currentWorkspace == null)
+ public void leaveWorkspace() throws IOException {
+ if (currentWorkspace == null)
throw new IllegalStateException("Attempt to leave workspace without being in one.");
+ logger.trace("Leaving workspace: " + currentWorkspace.getWorkspaceName());
- if(currentWorkspace.getActiveUser() != null)
- {
+ if (currentWorkspace.getActiveUser() != null) {
currentWorkspace.leaveUserSpace();
}
- if(currentWorkspace.isDirty())
+ if (currentWorkspace.isDirty())
currentWorkspace.store();
currentWorkspace = null;
}
-
- /*
- * Password protection
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * USB Detection & Handling
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ private transient USBDeviceDetectorManager driveDetector;
+
+ /**
+ * Detect External Drives
*/
+ protected void initUSBWorkspaces() {
+ driveDetector = new USBDeviceDetectorManager(800);
+
+ for (USBStorageDevice rmDevice : driveDetector.getRemovableDevices()) {
+ if (rmDevice.canRead() && rmDevice.canWrite()) {
+ addUSBDrive(rmDevice);
+ }
+ }
+
+ driveDetector.addDriveListener(new IUSBDriveListener(){
+
+ @Override
+ public void usbDriveEvent(USBStorageEvent event) {
+ USBStorageDevice rmDevice = event.getStorageDevice();
+ switch (event.getEventType()) {
+ case CONNECTED:
+ addUSBDrive(rmDevice);
+ break;
+ case REMOVED:
+ removeUSBDrive(rmDevice);
+ break;
+ }
+ }
+ });
+ }
+
+ protected void addUSBDrive(USBStorageDevice rmDevice) {
+ if (getWorkspaceDirectory(rmDevice.getSystemDisplayName()) == null) {
+ logger.trace("USB Drive attached: " + rmDevice);
+ String deviceName = rmDevice.getSystemDisplayName();
+ File location = rmDevice.getRootDirectory();
+ addWorkspace(deviceName, location.getAbsolutePath());
+ }
+ }
+
+ protected void removeUSBDrive(USBStorageDevice rmDevice) {
+ logger.trace("USB Drive removed: " + rmDevice);
+ String deviceName = rmDevice.getSystemDisplayName();
+ removeWorkspace(deviceName);
+ }
+
+ protected WorkspaceConfig initUSBDrive(String deviceName) throws IOException {
+ logger.trace("Initializing USB Drive: " + deviceName);
+ File usbRoot = null;
+ for (USBStorageDevice device : driveDetector.getRemovableDevices()) {
+ if (deviceName.equals(device.getSystemDisplayName())) {
+ usbRoot = device.getRootDirectory();
+ break;
+ }
+ }
+ if (usbRoot == null) { return null; }
+
+ File wsDir = WorkspaceConfig.getDirectory(usbRoot, WorkspaceConfig.USB_DEFAULT_WORKSPACE);
+ File wsConfigFile = WorkspaceConfig.getFile(wsDir, WorkspaceConfig.class);
+
+ WorkspaceConfig wsc = null;
+ if (wsConfigFile.exists()) {
+ logger.trace("Loading USB workspace from " + wsDir.getAbsolutePath());
+ wsc = WorkspaceConfig.loadWorkspace(usbRoot, WorkspaceConfig.USB_DEFAULT_WORKSPACE);
+ for (String user : wsc.getUserList()) {
+ logger.trace("\t Having user " + user);
+ }
+ }
+ else {
+ logger.trace("Creating new temporary USB workspace at " + usbRoot);
+ wsc = WorkspaceConfig.createDeferredWorkspace(usbRoot, WorkspaceConfig.USB_DEFAULT_WORKSPACE);
+ wsc.setAllowUserCreation(true);
+ }
+ return wsc;
+ }
+
+ /* *
+ * Workspace Types
+ * */
+
+ public boolean isUSBDrive(String workspaceName) {
+ for (USBStorageDevice device : driveDetector.getRemovableDevices()) {
+ if (workspaceName.equals(device.getSystemDisplayName())) { return true; }
+ }
+ return false;
+ }
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Password protection
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* if null, no password is requested
*/
- private byte[] masterPassword = null;
+ private byte[] masterPassword = null;
/**
* Need old password to authenticate
@@ -335,28 +586,25 @@ public class GlobalConfig extends StorableObject implements Serializable {
* @param newPw
* @return success
*/
- public boolean setNewPassword(String oldPw, String newPw)
- {
- if(masterPassword == null || authenticate(oldPw))
- {
+ public boolean setNewPassword(String oldPw, String newPw) {
+ if (masterPassword == null || authenticate(oldPw)) {
if (newPw == null)
masterPassword = null;
else
masterPassword = hash(newPw);
makeDirty();
return true;
- }else
- {
+ }
+ else {
return false;
}
}
- public boolean isPasswordRequired()
- {
+ public boolean isPasswordRequired() {
return masterPassword != null;
}
- public boolean authenticate(String password){
+ public boolean authenticate(String password) {
if (masterPassword == null)
return true;
String entered = null;
@@ -373,69 +621,79 @@ public class GlobalConfig extends StorableObject implements Serializable {
* @param text
* @return hashed bytes
*/
- private byte[] hash(String text)
- {
+ private byte[] hash(String text) {
if (text == null)
return null;
byte[] bytesOfMessage;
try {
bytesOfMessage = text.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e1) {
+ }
+ catch (UnsupportedEncodingException e1) {
bytesOfMessage = text.getBytes(); // this should not happen anyway
}
-
+
try {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(bytesOfMessage);
- } catch (NoSuchAlgorithmException e) {
+ }
+ catch (NoSuchAlgorithmException e) {
return bytesOfMessage; // this should not happen anyway
}
}
- /*
- * PATH
- */
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Path variable
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
- * This Stack contains all startup files
+ * Path to the current directory for the Logo environment
*/
- private ArrayList<String> path = new ArrayList<String>();
+ private ArrayList<String> path = new ArrayList<String>();
public ArrayList<String> getPath() {
return path;
}
-
-
+
public void setPath(ArrayList<String> path) {
this.path = path;
makeDirty();
}
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Application Meta Data
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /**
+ * This is not really used. Artifact from the past.
+ * @return
+ */
public static String getVersion() {
return "XLogo4Schools 0.0.1";
}
-
- /**
+
+ /* *
* Note : should be equal as in {@link Lanceur}
*/
//private static String PROPERTIES_PREFIX = "ch.ethz.abz.xlogo4schools";
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * JRE Memory allocation parameters
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
/**
* Note : should be equal as in {@link Lanceur}
*/
- private static int DEFAULT_MEMORY_ALLOC = 128;
+ private static int DEFAULT_MEMORY_ALLOC = 128;
- private static int maximumMemory;
+ private static int maximumMemory;
/**
* The Maximum amount of memory that this application is allowed to consume by the JVM
* @return
*/
- public static int getMaximumMemory()
- {
- if (maximumMemory < 64)
- {
+ public static int getMaximumMemory() {
+ if (maximumMemory < 64) {
// This doesn't work as expected :-(
//Preferences prefs = Preferences.systemRoot().node(PROPERTIES_PREFIX);
//maximumMemory = prefs.getInt("appMemory", DEFAULT_MEMORY_ALLOC);
@@ -444,51 +702,51 @@ public class GlobalConfig extends StorableObject implements Serializable {
return maximumMemory;
}
- private transient int maxMemoryAtNextStart = getMaximumMemory();
-
- public static final Font[] fonts = GraphicsEnvironment
- .getLocalGraphicsEnvironment().getAllFonts();// Toolkit.getDefaultToolkit().getFontList();
-
+ private transient int maxMemoryAtNextStart = getMaximumMemory();
+
/**
* @return The amount of memory in MB that Lanceur will cause JVM to allocate to XLogo4Schools the next time this application is started.
*/
- public int getMaxMemoryAtNextStart()
- {
+ public int getMaxMemoryAtNextStart() {
if (maxMemoryAtNextStart < 64)
maxMemoryAtNextStart = getMaximumMemory();
return maxMemoryAtNextStart;
}
+
/**
* @see #getMaxMemoryAtNextStart()
* cannot set this below 64MB
* @param maxMemory
*/
- public void setMaxMemoryAtNextStart(int maxMemory)
- {
+ public void setMaxMemoryAtNextStart(int maxMemory) {
if (maxMemory < 64)
return;
// This doesn't work as well :-(
//Preferences prefs = Preferences.systemRoot().node(PROPERTIES_PREFIX);
//prefs.putInt("appMemory", maxMemory);
}
-
- static public int police_id(Font font) {
- for (int i = 0; i < fonts.length; i++) {
- if (fonts[i].getFontName().equals(font.getFontName()))
- return i;
- }
- return 0;
- }
/**
* The amount of memory that the memory checker allows the application to consume.
* It's 0.9*{@link #getMaximumMemory()}} in bytes.
*/
- public static long getMemoryThreshold()
- {
+ public static long getMemoryThreshold() {
return (long) (0.9 * ((long) GlobalConfig.getMaximumMemory() * 1024L * 1024L));
}
-
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Fonts
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ public static final Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getAllFonts(); // Toolkit.getDefaultToolkit().getFontList();
+ static public int getFontId(Font font) {
+ for (int i = 0; i < fonts.length; i++) {
+ if (fonts[i].getFontName().equals(font.getFontName()))
+ return i;
+ }
+ return 0;
+ }
/* * * * * * *
* Event Handling
@@ -496,50 +754,46 @@ public class GlobalConfig extends StorableObject implements Serializable {
// workspace list change
- private transient ArrayList<ActionListener> workspaceListChangeListeners;
+ private transient ArrayList<ActionListener> workspaceListChangeListeners;
- public void addWorkspaceListChangeListener(ActionListener listener)
- {
+ public void addWorkspaceListChangeListener(ActionListener listener) {
if (workspaceListChangeListeners == null)
workspaceListChangeListeners = new ArrayList<ActionListener>();
workspaceListChangeListeners.add(listener);
}
- public void removeWorkspaceListChangeListener(ActionListener listener)
- {
+ public void removeWorkspaceListChangeListener(ActionListener listener) {
workspaceListChangeListeners.remove(listener);
}
- private void notifyWorkspaceListChanged()
- {
+ private void notifyWorkspaceListChanged() {
+ if (workspaceListChangeListeners == null)
+ workspaceListChangeListeners = new ArrayList<ActionListener>();
ActionEvent event = new ActionEvent(this, 0, "workspaceListChanged");
for (ActionListener listener : workspaceListChangeListeners)
listener.actionPerformed(event);
}
-
+
// enter workspace event
- private transient ArrayList<ActionListener> enterWorkspaceListeners;
+ private transient ArrayList<ActionListener> enterWorkspaceListeners;
- public void addEnterWorkspaceListener(ActionListener listener)
- {
+ public void addEnterWorkspaceListener(ActionListener listener) {
if (enterWorkspaceListeners == null)
enterWorkspaceListeners = new ArrayList<ActionListener>();
enterWorkspaceListeners.add(listener);
}
- public void removeEnterWorkspaceListener(ActionListener listener)
- {
+ public void removeEnterWorkspaceListener(ActionListener listener) {
enterWorkspaceListeners.remove(listener);
}
- private void notifyWorkspacEntered()
- {
+ private void notifyWorkspacEntered() {
if (enterWorkspaceListeners == null)
return;
ActionEvent event = new ActionEvent(this, 0, "workspaceEntered");
for (ActionListener listener : enterWorkspaceListeners)
listener.actionPerformed(event);
}
-
+
}
diff --git a/logo/src/xlogo/storage/user/DrawQuality.java b/logo/src/xlogo/storage/user/DrawQuality.java
index 565bb53..5d14360 100644
--- a/logo/src/xlogo/storage/user/DrawQuality.java
+++ b/logo/src/xlogo/storage/user/DrawQuality.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/user/LookAndFeel.java b/logo/src/xlogo/storage/user/LookAndFeel.java
index b4a2187..13d07c1 100644
--- a/logo/src/xlogo/storage/user/LookAndFeel.java
+++ b/logo/src/xlogo/storage/user/LookAndFeel.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/user/PenShape.java b/logo/src/xlogo/storage/user/PenShape.java
index cce19ee..52fee5b 100644
--- a/logo/src/xlogo/storage/user/PenShape.java
+++ b/logo/src/xlogo/storage/user/PenShape.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/user/UserConfig.java b/logo/src/xlogo/storage/user/UserConfig.java
index c2f85c5..2d6b1c0 100644
--- a/logo/src/xlogo/storage/user/UserConfig.java
+++ b/logo/src/xlogo/storage/user/UserConfig.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
@@ -57,6 +57,8 @@ public class UserConfig extends StorableObject implements Serializable
{
private static final long serialVersionUID = 8897730869795295485L;
+ public static final String DEFAULT_USER = "Default User";
+
// This was initially in Panel_Font, which is not used anymore.
public static final Font[] fontes = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
diff --git a/logo/src/xlogo/storage/workspace/ContestConfig.java b/logo/src/xlogo/storage/workspace/ContestConfig.java
index 197e4d5..87584f0 100644
--- a/logo/src/xlogo/storage/workspace/ContestConfig.java
+++ b/logo/src/xlogo/storage/workspace/ContestConfig.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/workspace/Language.java b/logo/src/xlogo/storage/workspace/Language.java
index f19b3ac..df32f70 100644
--- a/logo/src/xlogo/storage/workspace/Language.java
+++ b/logo/src/xlogo/storage/workspace/Language.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/workspace/NumberOfBackups.java b/logo/src/xlogo/storage/workspace/NumberOfBackups.java
index 1c8d4b2..3aa3534 100644
--- a/logo/src/xlogo/storage/workspace/NumberOfBackups.java
+++ b/logo/src/xlogo/storage/workspace/NumberOfBackups.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/workspace/SyntaxHighlightConfig.java b/logo/src/xlogo/storage/workspace/SyntaxHighlightConfig.java
index ac89e64..b4fcf10 100644
--- a/logo/src/xlogo/storage/workspace/SyntaxHighlightConfig.java
+++ b/logo/src/xlogo/storage/workspace/SyntaxHighlightConfig.java
@@ -1,4 +1,4 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
@@ -16,10 +16,10 @@
*
*
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
diff --git a/logo/src/xlogo/storage/workspace/WorkspaceConfig.java b/logo/src/xlogo/storage/workspace/WorkspaceConfig.java
index 9a3b60a..3a09e41 100644
--- a/logo/src/xlogo/storage/workspace/WorkspaceConfig.java
+++ b/logo/src/xlogo/storage/workspace/WorkspaceConfig.java
@@ -1,25 +1,25 @@
-/* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Lo�c Le Coq
+/*
+ * XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
*
* Contact Information: marko88zivkovic at gmail dot com
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version. This program is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details. You should have received a copy of the
- * GNU General Public License along with this program; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version. This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details. You should have received a copy of the
+ * GNU General Public License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
- *
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
- * during his Bachelor thesis at the computer science department of ETH Z�rich,
+ * during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
*
- * It is a reengineered version of XLogo written by Lo�c Le Coq, published
+ * It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
*
* Contents of this file were entirely written by Marko Zivkovic
@@ -32,6 +32,11 @@ import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import xlogo.AppSettings;
import xlogo.Logo;
@@ -40,6 +45,7 @@ import xlogo.messages.async.dialog.DialogMessenger;
import xlogo.storage.Storable;
import xlogo.storage.StorableObject;
import xlogo.storage.WSManager;
+import xlogo.storage.global.GlobalConfig;
import xlogo.storage.user.UserConfig;
/**
@@ -58,31 +64,63 @@ import xlogo.storage.user.UserConfig;
* @author Marko Zivkovic
*/
public class WorkspaceConfig extends StorableObject implements Serializable {
-
- private static final long serialVersionUID = -3554871695113998509L;
-
+
+ private static final long serialVersionUID = -3554871695113998509L;
+
/**
* Name of the virtual workspace
*/
- public static final String VIRTUAL_WORKSPACE = "Guest Workspace (no automatic save)";
-
- protected WorkspaceConfig()
- {
+ public static final String VIRTUAL_WORKSPACE = "Guest Workspace (no automatic save)";
+ public static final String USB_DEFAULT_WORKSPACE = "XLogo4Schools";
+ public static final String USER_DEFAULT_WORKSPACE = "XLogo4Schools-Workspace";
+
+ private static Logger logger = LogManager.getLogger(WorkspaceConfig.class.getSimpleName());
+
+ public static File getDefaultWorkspaceDirectory(){
+ File location = GlobalConfig.getDefaultLocation();
+ return getDirectory(location, USER_DEFAULT_WORKSPACE);
+ }
+
+ public static File getDefaultWorkspaceLocation(){
+ return GlobalConfig.getDefaultLocation();
+ }
+
+ public static boolean isSpecialWorkspace(String workspaceName, String location) {
+ return isVirtualWorkspace(workspaceName) || isDefaultWorkspace(workspaceName, location);
+ }
+
+ public static boolean isSpecialWorkspace(String workspaceName, File location) {
+ return isVirtualWorkspace(workspaceName) || isDefaultWorkspace(workspaceName, location);
+ }
+
+ public static boolean isVirtualWorkspace(String workspaceName) {
+ return VIRTUAL_WORKSPACE.equals(workspaceName);
+ }
+
+ public static boolean isDefaultWorkspace(String workspaceName, String location) {
+ return isDefaultWorkspace(workspaceName, new File(location));
+ }
+
+ public static boolean isDefaultWorkspace(String workspaceName, File location) {
+ return workspaceName.equals(USER_DEFAULT_WORKSPACE) &&
+ location.equals(getDefaultWorkspaceLocation());
+ }
+
+ protected WorkspaceConfig() {
super();
userList = new ArrayList<String>();
language = Language.LANGUAGE_ENGLISH;
- font = new Font("dialog",Font.PLAIN,14); // TODO on access check if it is null.
+ font = new Font("dialog", Font.PLAIN, 14); // TODO on access check if it is null.
// TODO what if incompatible?
- syntaxHighlightingStyles = new SyntaxHighlightConfig();
AppSettings.getInstance().setFont(font);
+ syntaxHighlightingStyles = new SyntaxHighlightConfig();
}
/**
* @return
* @throws IllegalStateException if this is not virtual and {@link #getLocation()} returns null
*/
- public String getWorkspaceName() throws IllegalStateException
- {
+ public String getWorkspaceName() throws IllegalStateException {
if (isVirtual())
return VIRTUAL_WORKSPACE;
@@ -95,20 +133,19 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
/*
* Static constructors
*/
- private static WorkspaceConfig virtualWS;
+ private static WorkspaceConfig virtualWS;
/**
* A virtual user can enter the application in a virtual workspace without having an actual user account on the file system. Hence nothing will be stored.
* A regular user (not virtual) will have his own folder in a regular workspace on the file system and all his preferences and files are stored there.
* To create a regular workspace, use {@link #createNewWorkspace(File, String)},
- * to load a regular workspace from the file system, user {@link #loadWorkspace(File)}}.
+ * to load a regular workspace from the file system, use {@link #loadWorkspace(File)}}.
* @see #isVirtual()
* @return a virtual workspace
*/
- public static WorkspaceConfig createVirtualWorkspace()
- {
- if (virtualWS == null)
- {
+ public static WorkspaceConfig createVirtualWorkspace() {
+ logger.trace("Creating virtual workspace.");
+ if (virtualWS == null) {
virtualWS = new WorkspaceConfig();
virtualWS.makeVirtual();
}
@@ -116,46 +153,79 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
}
@Override
- protected void makeVirtual()
- {
+ protected void makeVirtual() {
super.makeVirtual();
userList = new ArrayList<String>();
userList.add(UserConfig.VIRTUAL_USER);
lastActiveUser = UserConfig.VIRTUAL_USER;
- try { enterUserSpace(UserConfig.VIRTUAL_USER); } catch (IOException e) { /* Does not happen */ }
+ try {
+ enterUserSpace(UserConfig.VIRTUAL_USER);
+ }
+ catch (IOException e) { /* Does not happen */}
}
- /**
- * @param dir
- * @param workspaceName
- * @return
- * @throws IOException
- */
- public static WorkspaceConfig createNewWorkspace(File dir, String workspaceName) throws IOException
- {
- if (!Storable.checkLegalName(workspaceName))
- {
- DialogMessenger.getInstance().dispatchError(
- Logo.messages.getString(MessageKeys.NAME_ERROR_TITLE),
+ private static WorkspaceConfig createWorkspace(File dir, String workspaceName) throws IOException {
+ if (!Storable.checkLegalName(workspaceName)) {
+ DialogMessenger.getInstance().dispatchError(Logo.messages.getString(MessageKeys.NAME_ERROR_TITLE),
Logo.messages.getString(MessageKeys.ILLEGAL_NAME));
return null;
}
File wsd = getDirectory(dir, workspaceName);
- boolean existed = wsd.exists();
- if (!existed)
- {
- wsd.mkdirs();
- }
- // wsd exists and it is empty
WorkspaceConfig wsc = new WorkspaceConfig();
wsc.setLocation(wsd);
- //if(existed && WSManager.isUserDirectory(wsd))
- // wsc.refreshUserList();
+ return wsc;
+ }
+
+ /**
+ * @param dir
+ * @param workspaceName
+ * @return
+ * @throws IOException
+ */
+ public static WorkspaceConfig createNewWorkspace(File dir, String workspaceName) throws IOException {
+ logger.trace("Creating workspace " + workspaceName + " at " + dir.getAbsolutePath());
+ WorkspaceConfig wsc = createWorkspace(dir, workspaceName);
wsc.store();
return wsc;
}
-
+
+ /**
+ * Physically storing this workspace is deferred until explicitly disabled.
+ * This is used to temporarily make the USB Workspace and the Default Workspace available, but only store it when {@link #store()} is called the next time.
+ * @param dir
+ * @return
+ * @throws IOException
+ */
+ public static WorkspaceConfig createDeferredWorkspace(File dir, String workspaceName) throws IOException {
+ logger.trace("Creating deferred workspace " + workspaceName + " at " + dir.getAbsolutePath());
+ WorkspaceConfig wsc = createWorkspace(dir, workspaceName);
+ wsc.setStoringDeferred(true);
+ return wsc;
+ }
+
+ private transient boolean isStoringDeferred = false;
+
+ public void setStoringDeferred(boolean val) {
+ this.isStoringDeferred = val;
+ }
+
+ @Override
+ protected void makeDirty(){
+ super.makeDirty();
+ setStoringDeferred(false);
+ }
+
+ @Override
+ public void store() throws IOException {
+ if (!isStoringDeferred) {
+ super.store();
+ }
+ else {
+ isStoringDeferred = false;
+ }
+ }
+
/**
* @see #loadWorkspace(File)
* @param dir - location of the workspace
@@ -163,8 +233,7 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* @return
* @throws IOException
*/
- public static WorkspaceConfig loadWorkspace(File dir, String workspaceName) throws IOException
- {
+ public static WorkspaceConfig loadWorkspace(File dir, String workspaceName) throws IOException {
File wsc = getDirectory(dir, workspaceName);
return loadWorkspace(wsc);
}
@@ -175,12 +244,9 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* If workspaceDir specifies a {@link WorkspaceConfig#VIRTUAL_WORKSPACE}, the virtual workspace is returned instead.
* @throws IOException
*/
- public static WorkspaceConfig loadWorkspace(File workspaceDir) throws IOException
- {
- if(workspaceDir.getName().equals(WorkspaceConfig.VIRTUAL_WORKSPACE))
- {
- return createVirtualWorkspace();
- }
+ public static WorkspaceConfig loadWorkspace(File workspaceDir) throws IOException {
+ logger.trace("Loading workspace from " + workspaceDir.getAbsolutePath());
+ if (workspaceDir.getName().equals(WorkspaceConfig.VIRTUAL_WORKSPACE)) { return createVirtualWorkspace(); }
File wsf = getFile(workspaceDir, WorkspaceConfig.class);
@@ -189,8 +255,9 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
wsc = (WorkspaceConfig) WorkspaceConfig.loadObject(wsf);
wsc.setLocation(workspaceDir);
return wsc;
- } catch (ClassNotFoundException e) {
- return null; // this won't happen
+ }
+ catch (ClassNotFoundException e) {
+ return null;
}
}
@@ -201,20 +268,18 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
/**
* @see #getUserList()
*/
- private ArrayList<String> userList;
+ private ArrayList<String> userList;
/**
* The names of the logical users in the workspace
* @return
*/
- public String[] getUserList()
- {
+ public String[] getUserList() {
String[] users = new String[userList.size()];
return userList.toArray(users);
}
- public File getUserDirectroy(String username)
- {
+ public File getUserDirectroy(String username) {
if (!existsUserLogically(username) || isVirtual())
return null;
@@ -228,42 +293,45 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* <p> Has no effect if this is virtual.
* @param username
*/
- public void createUser(String username)
- {
- if (!Storable.checkLegalName(username))
- {
- DialogMessenger.getInstance().dispatchError(
- Logo.messages.getString(MessageKeys.NAME_ERROR_TITLE),
+ public void createUser(String username) {
+ logger.trace("Creating user: " + username);
+ if (!Storable.checkLegalName(username)) {
+ DialogMessenger.getInstance().dispatchError(Logo.messages.getString(MessageKeys.NAME_ERROR_TITLE),
Logo.messages.getString(MessageKeys.ILLEGAL_NAME));
return;
}
- if(isVirtual())
- {
- DialogMessenger.getInstance().dispatchError("Workspace Error", "Attempt to create new user to virtual workspace.");
+ if (isVirtual()) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error",
+ "Attempt to create new user to virtual workspace.");
return;
}
File userDir = getDirectory(getLocation(), username);
- if(!userDir.mkdirs())
- {
- DialogMessenger.getInstance().dispatchError("Workspace Error","Could not make required directories: " + userDir.toString());
+ if (!userDir.mkdirs() && !userDir.isDirectory()) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error",
+ "Could not make required directories: " + userDir.toString());
return;
}
- if (!existsUserLogically(username))
- {
+ if (!existsUserLogically(username)) {
userList.add(username);
makeDirty();
}
-
+
// Make new user logically existent in workspace config file
- try { store(); } catch (IOException e) {
- DialogMessenger.getInstance().dispatchError("Workspace Error","Could not store workspace.");
+ try {
+ store();
}
- if(!existsUserPhysically(username))
+ catch (IOException e) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error", "Could not store workspace."); // TODO translate
+ }
+ if (!existsUserPhysically(username)){
UserConfig.createNewUser(this, username);
+ }
+
+ lastActiveUser = username;
}
/**
@@ -276,8 +344,9 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* @throws IOException
* @see WSManager#isUserDirectory(File)
*/
- public void importUser(File srcUserDir, String destUsername) throws IllegalArgumentException, IOException
- {
+ public void importUser(File srcUserDir, String destUsername) throws IllegalArgumentException, IOException {
+ logger.trace("Importing user '" + destUsername + "' from " + srcUserDir.getAbsolutePath());
+
if (isVirtual())
return;
@@ -288,50 +357,62 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
File targetUserDir = getDirectory(getLocation(), destUsername);
WSManager.copyFullyRecursive(srcUserDir, targetUserDir);
+
+ lastActiveUser = destUsername;
}
/**
* @param userName will be removed logically only
+ * @throws IOException
*/
- public void removeUser(String userName)
- {
- if(existsUserLogically(userName))
+ public void removeUser(String username){
+ logger.trace("Removing user: " + username);
+ if (existsUserLogically(username)){
makeDirty();
+ }
- userList.remove(userName);
+ userList.remove(username);
+ cachedUserSpaces.remove(username);
+
+ if (activeUser != null && activeUser.getUserName().equals(username)){
+ activeUser = null;
+ lastActiveUser = null;
+ makeDirty();
+ }
}
/**
- * @param username - if this exists not logically in the workspace, null is returned.
+ * @param username - if this does not exists logically in the workspace, null is returned.
* @return a {@link UserConfig} generated from the file system. If this is a virtual workspace, a virtual user is created instead.
* @throws IOException if the UserConfig could not be loaded
* @see UserConfig#loadUser(File, String)
*/
- public UserConfig loadUser(String username) throws IOException
- {
- if(!existsUserLogically(username))
- {
- DialogMessenger.getInstance().dispatchError("Workspace Error","Attempt to load inexistent user: " + username + ". Try to import this user.");
+ public UserConfig loadUser(String username) throws IOException {
+ logger.trace("Loading user: " + username);
+ if (!existsUserLogically(username)) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error",
+ "Attempt to load inexistent user: " + username + ". Try to import this user.");
return null;
}
- if(isVirtual())
+ if (isVirtual())
return UserConfig.createVirtualUser();
// exists logically and is not virtual
- if(!existsUserPhysically(username))
- {
+ if (!existsUserPhysically(username)) {
// but it does exist logically => it must have been corrupted externally.
// => restore it.
- if(!getLocation().mkdirs())
- {
- DialogMessenger.getInstance().dispatchError("Workspace Error","Could not make required directories.");
+ if (!getLocation().mkdirs()) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error", "Could not make required directories.");
return null;
}
// user creation requires existence of the workspace on file system
- try { store(); } catch (IOException e) {
- DialogMessenger.getInstance().dispatchError("Workspace Error","Could not store workspace.");
+ try {
+ store();
+ }
+ catch (IOException e) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error", "Could not store workspace.");
}
return UserConfig.createNewUser(this, username);
}
@@ -344,27 +425,27 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* The users in this list may contain users that have been deleted logically before.
* @return
*/
- public ArrayList<String> getPhysicalUserList()
- {
- if(isVirtual())
+ public ArrayList<String> getPhysicalUserList() {
+ if (isVirtual())
return new ArrayList<String>();
-
+
ArrayList<String> users = new ArrayList<String>();
- if (WSManager.isWorkspaceDirectory(getLocation()))
- {
- DialogMessenger.getInstance().dispatchError("Workspace Error", "Current workspace was probably deleted. I will recreate it.");
- try { store(); } catch (IOException e) {
- DialogMessenger.getInstance().dispatchError("Workspace Error", "I could not recreate the Workspace. Try to delete the Workspace and recreate it manually.");
+ if (WSManager.isWorkspaceDirectory(getLocation())) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error",
+ "Current workspace was probably deleted. I will recreate it.");
+ try {
+ store();
+ }
+ catch (IOException e) {
+ DialogMessenger.getInstance().dispatchError("Workspace Error",
+ "I could not recreate the Workspace. Try to delete the Workspace and recreate it manually.");
return users;
}
}
-
- for(File dir : WSManager.listDirectories(getLocation()))
- {
- if(WSManager.isUserDirectory(dir))
- {
+ for (File dir : WSManager.listDirectories(getLocation())) {
+ if (WSManager.isUserDirectory(dir)) {
users.add(dir.getName());
}
}
@@ -376,8 +457,7 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* @param userName
* @return
*/
- public boolean existsUserLogically(String username)
- {
+ public boolean existsUserLogically(String username) {
return userList.contains(username);
}
@@ -387,8 +467,7 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* @return
* @see WSManager#isUserDirectory(File)
*/
- public boolean existsUserPhysically(String username)
- {
+ public boolean existsUserPhysically(String username) {
File userDir = getDirectory(getLocation(), username);
return WSManager.isUserDirectory(userDir);
}
@@ -397,13 +476,18 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* last active user
*/
- private String lastActiveUser;
+ private String lastActiveUser;
/**
* @return name of the last active user
*/
- public String getLastActiveUser()
- {
+ public String getLastActiveUser() {
+ if (lastActiveUser == null){
+ if (userList.size() > 0){
+ lastActiveUser = userList.get(0);
+ }
+ }
+
return lastActiveUser;
}
@@ -411,54 +495,86 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* Succeeds if the user exists
* @param workspace
*/
- public void setLastActiveUser(String username)
- {
- if(existsUserLogically(username) && !username.equals(lastActiveUser))
- {
+ public void setLastActiveUser(String username) {
+ if (existsUserLogically(username) && !username.equals(lastActiveUser)) {
lastActiveUser = new String(username);
makeDirty();
}
}
-
+
/*
* active user
*/
- private transient UserConfig activeUser;
+ private transient UserConfig activeUser;
- public UserConfig getActiveUser()
- {
+ public UserConfig getActiveUser() {
return activeUser;
}
+ public void enterInitialUserSpace() throws IOException{
+ String user = getLastActiveUser();
+ if (user != null){
+ enterUserSpace(user);
+ }
+ }
+
/**
* @throws IOException If the old userConfig could not be stored.
*/
- public void enterUserSpace(String username) throws IOException
- {
- if(activeUser != null)
- {
+ public void enterUserSpace(String username) throws IOException {
+ if (activeUser != null) {
leaveUserSpace();
}
+ logger.trace("Entering user space: " + username);
+
+ activeUser = retrieveUserSpace(username);
- if (isVirtual())
- activeUser = UserConfig.createVirtualUser();
- else
- activeUser = UserConfig.loadUser(this, username);
-
setLastActiveUser(username);
}
/**
* @throws IOException If userConfig could not be stored.
*/
- public void leaveUserSpace() throws IOException
- {
+ public void leaveUserSpace() throws IOException {
+ logger.trace("Leaving user space: " + activeUser.getUserName());
if (activeUser.isDirty())
activeUser.store();
activeUser = null;
- }
-
+ }
+
+ protected UserConfig retrieveUserSpace(String username){
+ UserConfig uc = getCachedUserSpace(username);
+ if (uc != null){
+ return uc;
+ }
+
+ if (isVirtual()){
+ uc = UserConfig.createVirtualUser();
+ } else {
+ uc = UserConfig.loadUser(this, username);
+ }
+
+ cacheUserSpace(username, uc);
+ return uc;
+ }
+
+ /**
+ * UserConfigs that have already been created or loaded from disk.
+ */
+ private transient Map<String, UserConfig> cachedUserSpaces;
+
+ private UserConfig getCachedUserSpace(String username) {
+ if (cachedUserSpaces == null){
+ cachedUserSpaces= new TreeMap<String, UserConfig>();
+ }
+ return cachedUserSpaces.get(username);
+ }
+
+ private void cacheUserSpace(String username, UserConfig wsc){
+ cachedUserSpaces.put(username, wsc);
+ }
+
/*
* Version control
*/
@@ -467,21 +583,19 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* How many old versions of a file should be kept, in addition to the most recent one?
* Default is infinite.
*/
- private NumberOfBackups numberOfBackups = NumberOfBackups.INFINITE;
+ private NumberOfBackups numberOfBackups = NumberOfBackups.INFINITE;
/**
* @see #numberOfBackups
*/
- public NumberOfBackups getNumberOfBackups()
- {
+ public NumberOfBackups getNumberOfBackups() {
return numberOfBackups;
}
/**
* @see #numberOfBackups
*/
- public void setNumberOfBackups(NumberOfBackups n)
- {
+ public void setNumberOfBackups(NumberOfBackups n) {
numberOfBackups = n;
makeDirty();
}
@@ -489,21 +603,19 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
/*
* Workspace language
*/
-
+
/**
* The language to be used within this workspace
*/
- public Language language;
+ public Language language;
- public void setLanguage(Language language)
- {
+ public void setLanguage(Language language) {
this.language = language;
AppSettings.getInstance().setLanguage(language);
makeDirty();
}
- public Language getLanguage()
- {
+ public Language getLanguage() {
return language;
}
@@ -511,74 +623,64 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
* Allow users (children) to create new user accounts in workspaces?
*/
- private boolean allowUserCreation = true;
+ private boolean allowUserCreation = true;
- public void setAllowUserCreation(boolean allowed)
- {
+ public void setAllowUserCreation(boolean allowed) {
this.allowUserCreation = allowed;
makeDirty();
}
- public boolean isUserCreationAllowed()
- {
+ public boolean isUserCreationAllowed() {
return allowUserCreation && !isVirtual();
}
-
+
/*
* Contest //TODO create options in workspace settings
*/
- private ContestConfig contestConfig;
+ private ContestConfig contestConfig;
- protected ContestConfig getContestSettings()
- {
+ protected ContestConfig getContestSettings() {
return contestConfig;
}
- public int getNOfContestFiles()
- {
+ public int getNOfContestFiles() {
if (contestConfig == null)
contestConfig = new ContestConfig();
return getContestSettings().getNOfContestFiles();
}
-
- public void setNOfContestFiles(int nOfContestFiles)
- {
+
+ public void setNOfContestFiles(int nOfContestFiles) {
getContestSettings().setNOfContestFiles(nOfContestFiles);
}
-
- public int getNOfContestBonusFiles()
- {
+
+ public int getNOfContestBonusFiles() {
return getContestSettings().getNOfContestBonusFiles();
}
-
- public void setNOfContestBonusFiles(int nOfContestBonusFiles)
- {
+
+ public void setNOfContestBonusFiles(int nOfContestBonusFiles) {
getContestSettings().setNOfContestBonusFiles(nOfContestBonusFiles);
}
/*
* Syntax Highlighting
*/
- private SyntaxHighlightConfig syntaxHighlightingStyles; // TODO = new SyntaxHighlightStyles();
-
+ private SyntaxHighlightConfig syntaxHighlightingStyles; // TODO = new SyntaxHighlightStyles();
+
/**
* This font is the default font for all menus ... in XLogo Application
*/
- private Font font;// TODO =new Font("dialog",Font.PLAIN,14);
-
- public SyntaxHighlightConfig getSyntaxHighlightStyles()
- {
- if (syntaxHighlightingStyles == null)
- {
+ private Font font; // TODO =new Font("dialog",Font.PLAIN,14);
+
+ public SyntaxHighlightConfig getSyntaxHighlightStyles() {
+ if (syntaxHighlightingStyles == null) {
syntaxHighlightingStyles = new SyntaxHighlightConfig();
makeDirty();
}
return syntaxHighlightingStyles;
}
- public void setSyntaxHighlightConfig(SyntaxHighlightConfig syntaxHighlightingStyles)
- {
+ public void setSyntaxHighlightConfig(SyntaxHighlightConfig syntaxHighlightingStyles) {
this.syntaxHighlightingStyles = syntaxHighlightingStyles;
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(syntaxHighlightingStyles);
@@ -587,88 +689,87 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
public int getPrimitiveColor() {
return getSyntaxHighlightStyles().getPrimitiveColor();
}
-
-
+
public void setPrimitiveColor(int primitiveColor) {
getSyntaxHighlightStyles().setPrimitiveColor(primitiveColor);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public int getPrimitiveStyle() {
return getSyntaxHighlightStyles().getPrimitiveStyle();
}
-
+
public void setPrimitiveStyle(int primitiveStyle) {
getSyntaxHighlightStyles().setPrimitiveStyle(primitiveStyle);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public int getOperatorColor() {
return getSyntaxHighlightStyles().getOperatorColor();
}
-
+
public void setOperandColor(int operatorColor) {
getSyntaxHighlightStyles().setOperatorColor(operatorColor);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public int getOperatorStyle() {
return getSyntaxHighlightStyles().getOperatorStyle();
}
-
+
public void setOperandStyle(int operatorStyle) {
getSyntaxHighlightStyles().setOperatorStyle(operatorStyle);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public int getCommentColor() {
return getSyntaxHighlightStyles().getCommentColor();
}
-
+
public void setCommentColor(int commentColor) {
getSyntaxHighlightStyles().setCommentColor(commentColor);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public int getCommentStyle() {
return getSyntaxHighlightStyles().getCommentStyle();
}
-
+
public void setCommentStyle(int commentStyle) {
getSyntaxHighlightStyles().setCommentStyle(commentStyle);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public int getBraceColor() {
return getSyntaxHighlightStyles().getBraceColor();
}
-
+
public void setBraceColor(int braceColor) {
getSyntaxHighlightStyles().setBraceColor(braceColor);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public int getBraceStyle() {
return getSyntaxHighlightStyles().getBraceStyle();
}
-
+
public void setBraceStyle(int braceStyle) {
getSyntaxHighlightStyles().setBraceStyle(braceStyle);
makeDirty();
AppSettings.getInstance().setSyntaxHighlightingStyles(getSyntaxHighlightStyles());
}
-
+
public boolean isSyntaxHighlightingEnabled() {
return getSyntaxHighlightStyles().isColorEnabled();
}
-
+
public void setSyntaxHighlightingEnabled(boolean colorEnabled) {
getSyntaxHighlightStyles().setColorEnabled(colorEnabled);
makeDirty();
@@ -678,7 +779,7 @@ public class WorkspaceConfig extends StorableObject implements Serializable {
public Font getFont() {
return font;
}
-
+
public void setFont(Font font) {
this.font = font;
makeDirty();