Add options for configuration file location.
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 16 Aug 2011 19:28:29 +0000 (21:28 +0200)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Thu, 3 Nov 2011 07:45:19 +0000 (08:45 +0100)
This commit includes several changes: the configuration does not know
itself anymore where it was loaded from, the ConfigurationLocator is now
used for that. The preferences page does not need access to the
configuration anymore. Finally, the lock file has been removed; now, when
saving a configuration file would overwrite an existing configuration file,
the user is asked for permission.

src/de/todesbaum/jsite/gui/PreferencesPage.java
src/de/todesbaum/jsite/i18n/jSite.properties
src/de/todesbaum/jsite/i18n/jSite_de.properties
src/de/todesbaum/jsite/i18n/jSite_fr.properties
src/de/todesbaum/jsite/main/CLI.java
src/de/todesbaum/jsite/main/Configuration.java
src/de/todesbaum/jsite/main/Main.java

index 27ff163..595f769 100644 (file)
@@ -1,6 +1,5 @@
 /*
- * jSite - PreferencesPage.java -
- * Copyright © 2009 David Roden
+ * jSite - PreferencesPage.java - Copyright © 2009–2011 David Roden
  *
  * 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
@@ -38,8 +37,7 @@ import javax.swing.JTextField;
 
 import de.todesbaum.jsite.i18n.I18n;
 import de.todesbaum.jsite.i18n.I18nContainer;
-import de.todesbaum.jsite.main.Configuration;
-import de.todesbaum.jsite.main.Configuration.ConfigurationDirectory;
+import de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation;
 import de.todesbaum.util.swing.TWizard;
 import de.todesbaum.util.swing.TWizardPage;
 
@@ -65,17 +63,17 @@ public class PreferencesPage extends TWizardPage {
        /** Action when selecting “home directory.” */
        private Action homeDirectoryAction;
 
+       /** Action when selecting “custom directory.” */
+       private Action customDirectoryAction;
+
        /** The text field containing the directory. */
        private JTextField tempDirectoryTextField;
 
        /** The temp directory. */
        private String tempDirectory;
 
-       /** The configuration. */
-       private Configuration configuration;
-
-       /** The configuration directory. */
-       private ConfigurationDirectory configurationDirectory;
+       /** The configuration location. */
+       private ConfigurationLocation configurationLocation;
 
        /** The “default” button. */
        private JRadioButton defaultTempDirectory;
@@ -86,21 +84,19 @@ public class PreferencesPage extends TWizardPage {
        /** The “next to JAR file” checkbox. */
        private JRadioButton nextToJarFile;
 
-       /** The “current directory” checkbox. */
-       private JRadioButton currentDirectory;
-
        /** The “home directory” checkbox. */
        private JRadioButton homeDirectory;
 
+       /** The “custom directory” checkbox. */
+       private JRadioButton customDirectory;
+
        /**
         * Creates a new “preferences” page.
         *
         * @param wizard
         *            The wizard this page belongs to
-        * @param configuration
-        *            The configuration that is controlled
         */
-       public PreferencesPage(TWizard wizard, Configuration configuration) {
+       public PreferencesPage(TWizard wizard) {
                super(wizard);
                pageInit();
                setHeading(I18n.getMessage("jsite.preferences.heading"));
@@ -115,7 +111,6 @@ public class PreferencesPage extends TWizardPage {
                                setDescription(I18n.getMessage("jsite.preferences.description"));
                        }
                });
-               this.configuration = configuration;
        }
 
        //
@@ -151,34 +146,60 @@ public class PreferencesPage extends TWizardPage {
        }
 
        /**
-        * Returns the configuration directory.
+        * Returns the configuration location.
         *
-        * @return The configuration directory
+        * @return The configuration location
         */
-       public ConfigurationDirectory getConfigurationDirectory() {
-               return configurationDirectory;
+       public ConfigurationLocation getConfigurationLocation() {
+               return configurationLocation;
        }
 
        /**
-        * Sets the configuration directory.
+        * Sets the configuration location.
         *
-        * @param configurationDirectory
-        *            The configuration directory
+        * @param configurationLocation
+        *            The configuration location
         */
-       public void setConfigurationDirectory(ConfigurationDirectory configurationDirectory) {
-               this.configurationDirectory = configurationDirectory;
-               configuration.setConfigurationDirectory(configurationDirectory);
-               switch (configurationDirectory) {
+       public void setConfigurationLocation(ConfigurationLocation configurationLocation) {
+               this.configurationLocation = configurationLocation;
+               switch (configurationLocation) {
                case NEXT_TO_JAR_FILE:
                        nextToJarFile.setSelected(true);
                        break;
                case HOME_DIRECTORY:
                        homeDirectory.setSelected(true);
                        break;
+               case CUSTOM:
+                       customDirectory.setSelected(true);
+                       break;
                }
        }
 
        /**
+        * Sets whether it is possible to select the “next to JAR file” option for
+        * the configuration location.
+        *
+        * @param nextToJarFile
+        *            {@code true} if the configuration file can be saved next to
+        *            the JAR file, {@code false} otherwise
+        */
+       public void setHasNextToJarConfiguration(boolean nextToJarFile) {
+               this.nextToJarFile.setEnabled(nextToJarFile);
+       }
+
+       /**
+        * Sets whether it is possible to select the “custom location” option for
+        * the configuration location.
+        *
+        * @param customDirectory
+        *            {@code true} if the configuration file can be saved to a
+        *            custom location, {@code false} otherwise
+        */
+       public void setHasCustomConfiguration(boolean customDirectory) {
+               this.customDirectory.setEnabled(customDirectory);
+       }
+
+       /**
         * {@inheritDoc}
         */
        @Override
@@ -238,14 +259,21 @@ public class PreferencesPage extends TWizardPage {
 
                        @SuppressWarnings("synthetic-access")
                        public void actionPerformed(ActionEvent actionevent) {
-                               configurationDirectory = ConfigurationDirectory.NEXT_TO_JAR_FILE;
+                               configurationLocation = ConfigurationLocation.NEXT_TO_JAR_FILE;
                        }
                };
                homeDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.config-directory.home")) {
 
                        @SuppressWarnings("synthetic-access")
                        public void actionPerformed(ActionEvent actionevent) {
-                               configurationDirectory = ConfigurationDirectory.HOME_DIRECTORY;
+                               configurationLocation = ConfigurationLocation.HOME_DIRECTORY;
+                       }
+               };
+               customDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.config-directory.custom")) {
+
+                       @SuppressWarnings("synthetic-access")
+                       public void actionPerformed(ActionEvent actionEvent) {
+                               configurationLocation = ConfigurationLocation.CUSTOM;
                        }
                };
 
@@ -258,6 +286,7 @@ public class PreferencesPage extends TWizardPage {
                                chooseTempDirectoryAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.temp-directory.choose"));
                                nextToJarFileAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.config-directory.jar"));
                                homeDirectoryAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.config-directory.home"));
+                               customDirectoryAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.config-directory.custom"));
                        }
                });
        }
@@ -307,10 +336,13 @@ public class PreferencesPage extends TWizardPage {
                homeDirectory = new JRadioButton(homeDirectoryAction);
                preferencesPanel.add(homeDirectory, new GridBagConstraints(0, 5, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 18, 0, 0), 0, 0));
 
+               customDirectory = new JRadioButton(customDirectoryAction);
+               preferencesPanel.add(customDirectory, new GridBagConstraints(0, 6, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 18, 0, 0), 0, 0));
+
                ButtonGroup configurationDirectoryButtonGroup = new ButtonGroup();
                configurationDirectoryButtonGroup.add(nextToJarFile);
-               configurationDirectoryButtonGroup.add(currentDirectory);
                configurationDirectoryButtonGroup.add(homeDirectory);
+               configurationDirectoryButtonGroup.add(customDirectory);
 
                I18nContainer.getInstance().registerRunnable(new Runnable() {
 
index 29ff2da..bf5c5d1 100644 (file)
@@ -27,9 +27,6 @@
 # lines single quotes (ASCII 39) needs to be escaped by entering them twice,
 # otherwise the placeholder will not be replaced!
 
-jsite.main.already-running=<html><b>jSite is already running</b><br><br>A lock file has been found that suggests that another<br>instance of jSite is already running. Running multiple instances<br>of jSite is guaranteed to break your configuration.</html>
-jsite.main.already-running.override=Start anyway
-
 jsite.general.ok=OK
 jsite.general.cancel=Cancel
 
@@ -38,6 +35,7 @@ jsite.wizard.next=Next
 jsite.wizard.quit=Quit
 
 jsite.quit.question=Do you really want to quit?
+jsite.quite.overwrite-configuration=<html><b>Overwrite configuration?</b><br><br>A configuration file already exists.<br>Should it be overwritten?</html>
 jsite.quit.config-not-saved=<html><b>Configuration not saved</b><br><br>The configuration could not be saved.<br>Do you want to quit anyway?</html>
 
 jsite.menu.languages=Languages
@@ -76,8 +74,8 @@ jsite.preferences.temp-directory.choose=Choose
 jsite.preferences.temp-directory.choose.approve=Choose
 jsite.preferences.config-directory=Location of configuration directory
 jsite.preferences.config-directory.jar=Next to the JAR file
-jsite.preferences.config-directory.current=Current directory
 jsite.preferences.config-directory.home=Home directory
+jsite.preferences.config-directory.custom=Custom directory
 
 jsite.insert.heading=Project insert
 jsite.insert.description=Please wait while the project is being inserted.
index 6ed4544..289a70c 100644 (file)
@@ -27,9 +27,6 @@
 # lines single quotes (ASCII 39) needs to be escaped by entering them twice,
 # otherwise the placeholder will not be replaced!
 
-jsite.main.already-running=<html><b>jSite l\u00e4uft bereits!</b><br><br>Es wurde festgestellt, dass jSite bereits l\u00e4uft. Das kann<br>zu Besch\u00e4digungen an der Konfiguration f\u00fchren.</html>
-jsite.main.already-running.override=Trotzdem starten
-
 jsite.general.ok=OK
 jsite.general.cancel=Abbrechen
 
@@ -74,6 +71,10 @@ jsite.preferences.temp-directory.default=Standard (vom System bestimmt)
 jsite.preferences.temp-directory.custom=Eigenes
 jsite.preferences.temp-directory.choose=Ausw\u00e4hlen
 jsite.preferences.temp-directory.choose.approve=Ausw\u00e4hlen
+jsite.preferences.config-directory=Lage der Konfigurationsdatei
+jsite.preferences.config-directory.jar=Neben der JAR-Datei
+jsite.preferences.config-directory.home=Benutzerverzeichnis
+jsite.preferences.config-directory.custom=Angegebenes Verzeichnis
 
 jsite.insert.heading=Projekt einf\u00fcgen
 jsite.insert.description=Bitte warten Sie, w\u00e4hrend das Projekt eingef\u00fcgt wird.
index 49fcce8..14b831a 100644 (file)
@@ -27,9 +27,6 @@
 # lines single quotes (ASCII 39) needs to be escaped by entering them twice,
 # otherwise the placeholder will not be replaced!
 
-jsite.main.already-running=<html><b>jSite est d\u00e9ja lanc\u00e9!</b><br><br>Ne faites pas tourner plusieurs instances<br> sous peine de perdre vos fichiers de configuration !</html>
-jsite.main.already-running.override=D\u00e9marrer
-
 jsite.general.ok=OK
 jsite.general.cancel=Annuler
 
index 2c5edbd..0780e9f 100644 (file)
@@ -89,11 +89,11 @@ public class CLI implements InsertListener {
                        }
                }
 
-               Configuration configuration = new Configuration(configFile);
-               if (!configuration.createLockFile()) {
-                       outputWriter.println("Lock file found!");
-                       return;
+               ConfigurationLocator configurationLocator = new ConfigurationLocator();
+               if (configFile != null) {
+                       configurationLocator.setCustomLocation(configFile);
                }
+               Configuration configuration = new Configuration(configurationLocator, configurationLocator.findPreferredLocation());
 
                projectInserter.addInsertListener(this);
                projects = configuration.getProjects();
index ca5a1af..75f2204 100644 (file)
@@ -33,10 +33,13 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import de.todesbaum.jsite.application.FileOption;
 import de.todesbaum.jsite.application.Node;
 import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation;
 import de.todesbaum.util.io.Closer;
 import de.todesbaum.util.io.StreamCopier;
 import de.todesbaum.util.xml.SimpleXML;
@@ -49,152 +52,92 @@ import de.todesbaum.util.xml.XML;
  */
 public class Configuration {
 
-       /**
-        * The location of the configuration directory.
-        *
-        * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
-        */
-       public enum ConfigurationDirectory {
-
-               /** The configuration is in the same directory as the JAR file. */
-               NEXT_TO_JAR_FILE,
-
-               /**
-                * The configuration is in the user’s home directory. This is the
-                * pre-0.9.3 default.
-                */
-               HOME_DIRECTORY;
-
-       }
-
-       /** The configuration directory. */
-       private ConfigurationDirectory configurationDirectory = ConfigurationDirectory.HOME_DIRECTORY;
-
-       /** The name of the file the configuration is stored to. */
-       private String filename;
-
-       /** The name of the lock file. */
-       private String lockFilename;
-
        /** The root node of the configuration. */
        private SimpleXML rootNode;
 
-       /**
-        * Creates a new configuration with the default name of the configuration
-        * file.
-        */
-       public Configuration() {
-               this(System.getProperty("user.home") + "/.jSite/config7");
-       }
+       /** The configuration locator. */
+       private final ConfigurationLocator configurationLocator;
 
-       /**
-        * Creates a new configuration that is read from the given file.
-        *
-        * @param filename
-        *            The name of the configuration file
-        */
-       public Configuration(String filename) {
-               this(filename, filename + ".lock");
-       }
+       /** Where the configuration resides. */
+       private ConfigurationLocation configurationLocation;
 
        /**
-        * Creates a new configuration that is read from the given file and uses the
-        * given lock file.
+        * Creates a new configuration that is read from the given file.
         *
-        * @param filename
-        *            The name of the configuration file
-        * @param lockFilename
-        *            The name of the lock file
+        * @param configurationLocator
+        *            The configuration locator
+        * @param configurationLocation
+        *            The configuration directory
         */
-       public Configuration(String filename, String lockFilename) {
-               this.filename = filename;
-               this.lockFilename = lockFilename;
-               readConfiguration();
+       public Configuration(ConfigurationLocator configurationLocator, ConfigurationLocation configurationLocation) {
+               this.configurationLocator = configurationLocator;
+               this.configurationLocation = configurationLocation;
+               readConfiguration(configurationLocator.getFile(configurationLocation));
        }
 
-       /**
-        * Returns the configuration directory.
-        *
-        * @return The configuration directory
-        */
-       public ConfigurationDirectory getConfigurationDirectory() {
-               return configurationDirectory;
-       }
+       //
+       // ACCESSORS
+       //
 
        /**
-        * Sets the configuration directory.
+        * Returns the configuration locator.
         *
-        * @param configurationDirectory
-        *            The configuration directory
+        * @return The configuration locator
         */
-       public void setConfigurationDirectory(ConfigurationDirectory configurationDirectory) {
-               this.configurationDirectory = configurationDirectory;
+       public ConfigurationLocator getConfigurationLocator() {
+               return configurationLocator;
        }
 
        /**
-        * Creates the directory of the configuration file.
+        * Returns the location the configuration will be written to when calling
+        * {@link #save()}.
         *
-        * @return <code>true</code> if the directory exists, or if it could be
-        *         created, <code>false</code> otherwise
+        * @return The location the configuration will be written to
         */
-       private boolean createConfigDirectory() {
-               File configDirectory = new File(filename).getAbsoluteFile().getParentFile();
-               return (configDirectory.exists() && configDirectory.isDirectory()) || configDirectory.mkdirs();
+       public ConfigurationLocation getConfigurationDirectory() {
+               return configurationLocation;
        }
 
        /**
-        * Creates the lock file.
+        * Sets the location the configuration will be written to when calling
+        * {@link #save()}.
         *
-        * @return <code>true</code> if the lock file did not already exist and
-        *         could be created, <code>false</code> otherwise
+        * @param configurationLocation
+        *            The location to write the configuration to
         */
-       public boolean createLockFile() {
-               if (!createConfigDirectory()) {
-                       return false;
-               }
-               File lockFile = new File(lockFilename);
-               try {
-                       boolean fileLocked = lockFile.createNewFile();
-                       if (fileLocked) {
-                               lockFile.deleteOnExit();
-                       }
-                       return fileLocked;
-               } catch (IOException e) {
-                       /* ignore. */
-               }
-               return false;
-       }
-
-       /**
-        * Tells the VM to remove the lock file on program exit.
-        */
-       public void removeLockfileOnExit() {
-               new File(lockFilename).deleteOnExit();
+       public void setConfigurationLocation(ConfigurationLocation configurationLocation) {
+               this.configurationLocation = configurationLocation;
        }
 
        /**
         * Reads the configuration from the file.
+        *
+        * @param filename
+        *            The name of the file to read the configuration from
         */
-       private void readConfiguration() {
-               File configurationFile = new File(filename);
-               if (configurationFile.exists()) {
-                       ByteArrayOutputStream fileByteOutputStream = null;
-                       FileInputStream fileInputStream = null;
-                       try {
-                               fileByteOutputStream = new ByteArrayOutputStream();
-                               fileInputStream = new FileInputStream(configurationFile);
-                               StreamCopier.copy(fileInputStream, fileByteOutputStream, configurationFile.length());
-                               fileByteOutputStream.close();
-                               byte[] fileBytes = fileByteOutputStream.toByteArray();
-                               rootNode = SimpleXML.fromDocument(XML.transformToDocument(fileBytes));
-                               return;
-                       } catch (FileNotFoundException e) {
-                               /* ignore. */
-                       } catch (IOException e) {
-                               /* ignore. */
-                       } finally {
-                               Closer.close(fileInputStream);
-                               Closer.close(fileByteOutputStream);
+       private void readConfiguration(String filename) {
+               Logger.getLogger(Configuration.class.getName()).log(Level.CONFIG, "Reading configuration from: " + filename);
+               if (filename != null) {
+                       File configurationFile = new File(filename);
+                       if (configurationFile.exists()) {
+                               ByteArrayOutputStream fileByteOutputStream = null;
+                               FileInputStream fileInputStream = null;
+                               try {
+                                       fileByteOutputStream = new ByteArrayOutputStream();
+                                       fileInputStream = new FileInputStream(configurationFile);
+                                       StreamCopier.copy(fileInputStream, fileByteOutputStream, configurationFile.length());
+                                       fileByteOutputStream.close();
+                                       byte[] fileBytes = fileByteOutputStream.toByteArray();
+                                       rootNode = SimpleXML.fromDocument(XML.transformToDocument(fileBytes));
+                                       return;
+                               } catch (FileNotFoundException e) {
+                                       /* ignore. */
+                               } catch (IOException e) {
+                                       /* ignore. */
+                               } finally {
+                                       Closer.close(fileInputStream);
+                                       Closer.close(fileByteOutputStream);
+                               }
                        }
                }
                rootNode = new SimpleXML("configuration");
@@ -207,7 +150,8 @@ public class Configuration {
         *         <code>false</code> otherwise
         */
        public boolean save() {
-               File configurationFile = new File(filename);
+               Logger.getLogger(Configuration.class.getName()).log(Level.CONFIG, "Trying to save configuration to: " + configurationLocation);
+               File configurationFile = new File(configurationLocator.getFile(configurationLocation));
                if (!configurationFile.exists()) {
                        File configurationFilePath = configurationFile.getAbsoluteFile().getParentFile();
                        if (!configurationFilePath.exists() && !configurationFilePath.mkdirs()) {
index e654c91..4c7752f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006-2009 David Roden
+ * Copyright © 2006–2011 David Roden
  *
  * 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
@@ -22,7 +22,6 @@ package de.todesbaum.jsite.main;
 import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.io.File;
 import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.Date;
@@ -64,7 +63,7 @@ import de.todesbaum.jsite.gui.ProjectInsertPage;
 import de.todesbaum.jsite.gui.ProjectPage;
 import de.todesbaum.jsite.i18n.I18n;
 import de.todesbaum.jsite.i18n.I18nContainer;
-import de.todesbaum.jsite.main.Configuration.ConfigurationDirectory;
+import de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation;
 import de.todesbaum.util.image.IconLoader;
 import de.todesbaum.util.swing.TWizard;
 import de.todesbaum.util.swing.TWizardPage;
@@ -163,33 +162,18 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
         *            The name of the configuration file
         */
        private Main(String configFilename) {
+               /* collect all possible configuration file locations. */
+               ConfigurationLocator configurationLocator = new ConfigurationLocator();
                if (configFilename != null) {
-                       configuration = new Configuration(configFilename);
-               } else {
-                       /* are we executed from a JAR file? */
-                       String resource = getClass().getResource("/de/todesbaum/jsite/i18n/jSite.properties").toString();
-                       if (resource.startsWith("jar:")) {
-                               String jarFileLocation = resource.substring(9, resource.indexOf(".jar!") + 4);
-                               String jarFileDirectory = new File(jarFileLocation).getParent();
-                               File configurationFile = new File(jarFileDirectory, "jSite.conf");
-                               if (configurationFile.exists()) {
-                                       configuration = new Configuration(configurationFile.getAbsolutePath());
-                                       configuration.setConfigurationDirectory(ConfigurationDirectory.NEXT_TO_JAR_FILE);
-                               }
-                       }
-                       if (configuration == null) {
-                               configuration = new Configuration();
-                       }
+                       configurationLocator.setCustomLocation(configFilename);
                }
+
+               ConfigurationLocation preferredLocation = configurationLocator.findPreferredLocation();
+               logger.log(Level.CONFIG, "Using configuration from " + preferredLocation + ".");
+               configuration = new Configuration(configurationLocator, preferredLocation);
+
                Locale.setDefault(configuration.getLocale());
                I18n.setLocale(configuration.getLocale());
-               if (!configuration.createLockFile()) {
-                       int option = JOptionPane.showOptionDialog(null, I18n.getMessage("jsite.main.already-running"), "", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[] { I18n.getMessage("jsite.main.already-running.override"), I18n.getMessage("jsite.wizard.quit") }, I18n.getMessage("jsite.wizard.quit"));
-                       if (option != 0) {
-                               throw new IllegalStateException("Lockfile override not active, refusing start.");
-                       }
-                       configuration.removeLockfileOnExit();
-               }
                wizard = new TWizard();
                createActions();
                wizard.setJMenuBar(createMenuBar());
@@ -353,7 +337,7 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
                projectInsertPage.setFreenetInterface(freenetInterface);
                pages.put(PageType.PAGE_INSERT_PROJECT, projectInsertPage);
 
-               PreferencesPage preferencesPage = new PreferencesPage(wizard, configuration);
+               PreferencesPage preferencesPage = new PreferencesPage(wizard);
                preferencesPage.setName("page.preferences");
                preferencesPage.setTempDirectory(configuration.getTempDirectory());
                pages.put(PageType.PAGE_PREFERENCES, preferencesPage);
@@ -373,6 +357,17 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
        }
 
        /**
+        * Returns whether a configuration file would be overwritten when calling
+        * {@link #saveConfiguration()}.
+        *
+        * @return {@code true} if {@link #saveConfiguration()} would overwrite an
+        *         existing file, {@code false} otherwise
+        */
+       private boolean isOverwritingConfiguration() {
+               return configuration.getConfigurationLocator().hasFile(configuration.getConfigurationDirectory());
+       }
+
+       /**
         * Saves the configuration.
         *
         * @return <code>true</code> if the configuration could be saved,
@@ -461,7 +456,9 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
         * Shows a dialog with general preferences.
         */
        private void optionsPreferences() {
-               ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setConfigurationDirectory(configuration.getConfigurationDirectory());
+               ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setConfigurationLocation(configuration.getConfigurationDirectory());
+               ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setHasNextToJarConfiguration(configuration.getConfigurationLocator().isValidLocation(ConfigurationLocation.NEXT_TO_JAR_FILE));
+               ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setHasCustomConfiguration(configuration.getConfigurationLocator().isValidLocation(ConfigurationLocation.CUSTOM));
                showPage(PageType.PAGE_PREFERENCES);
                optionsPreferencesAction.setEnabled(false);
                wizard.setNextEnabled(true);
@@ -567,8 +564,10 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
                                optionsPreferencesAction.setEnabled(true);
                        }
                } else if ("page.preferences".equals(pageName)) {
+                       PreferencesPage preferencesPage = (PreferencesPage) pages.get(PageType.PAGE_PREFERENCES);
                        showPage(PageType.PAGE_PROJECTS);
                        optionsPreferencesAction.setEnabled(true);
+                       configuration.setConfigurationLocation(preferencesPage.getConfigurationLocation());
                }
        }
 
@@ -595,8 +594,16 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
                        JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.use-clipboard-now"));
                }
                if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
-                       if (saveConfiguration()) {
-                               System.exit(0);
+                       if (isOverwritingConfiguration()) {
+                               if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quite.overwrite-configuration"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
+                                       if (saveConfiguration()) {
+                                               System.exit(0);
+                                       }
+                               }
+                       } else {
+                               if (saveConfiguration()) {
+                                       System.exit(0);
+                               }
                        }
                        if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.config-not-saved"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
                                System.exit(0);