Factor out project validation, re-order warning and error messages.
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Fri, 22 Jan 2010 14:58:17 +0000 (15:58 +0100)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Fri, 22 Jan 2010 14:58:17 +0000 (15:58 +0100)
src/de/todesbaum/jsite/application/ProjectInserter.java
src/de/todesbaum/jsite/i18n/jSite.properties
src/de/todesbaum/jsite/i18n/jSite_de.properties
src/de/todesbaum/jsite/main/Main.java

index 569e2fe..c8c5e93 100644 (file)
@@ -27,14 +27,19 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
+import de.todesbaum.jsite.application.ProjectInserter.CheckReport.Issue;
 import de.todesbaum.jsite.gui.FileScanner;
 import de.todesbaum.jsite.gui.FileScannerListener;
 import de.todesbaum.util.freenet.fcp2.Client;
@@ -380,6 +385,60 @@ public class ProjectInserter implements FileScannerListener, Runnable {
        }
 
        /**
+        * Validates the given project. The project will be checked for any invalid
+        * conditions, such as invalid insert or request keys, missing path names,
+        * missing default file, and so on.
+        *
+        * @param project
+        *            The project to check
+        * @return The encountered warnings and errors
+        */
+       public static CheckReport validateProject(Project project) {
+               CheckReport checkReport = new CheckReport();
+               if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) {
+                       checkReport.addIssue("error.no-local-path", true);
+               }
+               if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) {
+                       checkReport.addIssue("error.no-path", true);
+               }
+               if ((project.getIndexFile() == null) || (project.getIndexFile().length() == 0)) {
+                       checkReport.addIssue("warning.empty-index", false);
+               } else {
+                       File indexFile = new File(project.getLocalPath(), project.getIndexFile());
+                       if (!indexFile.exists()) {
+                               checkReport.addIssue("error.index-missing", true);
+                       }
+               }
+               String indexFile = project.getIndexFile();
+               boolean hasIndexFile = (indexFile != null);
+               if (hasIndexFile && !project.getFileOption(indexFile).getContainer().equals("")) {
+                       checkReport.addIssue("warning.container-index", false);
+               }
+               List<String> allowedIndexContentTypes = Arrays.asList("text/html", "application/xhtml+xml");
+               if (hasIndexFile && !allowedIndexContentTypes.contains(project.getFileOption(indexFile).getMimeType())) {
+                       checkReport.addIssue("warning.index-not-html", false);
+               }
+               Map<String, FileOption> fileOptions = project.getFileOptions();
+               Set<Entry<String, FileOption>> fileOptionEntries = fileOptions.entrySet();
+               boolean insert = false;
+               for (Entry<String, FileOption> fileOptionEntry : fileOptionEntries) {
+                       String fileName = fileOptionEntry.getKey();
+                       FileOption fileOption = fileOptionEntry.getValue();
+                       insert |= fileOption.isInsert() || fileOption.isInsertRedirect();
+                       if (fileName.equals(project.getIndexFile()) && !fileOption.isInsert() && !fileOption.isInsertRedirect()) {
+                               checkReport.addIssue("error.index-not-inserted", true);
+                       }
+                       if (!fileOption.isInsert() && fileOption.isInsertRedirect() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) {
+                               checkReport.addIssue("error.no-custom-key", true, fileName);
+                       }
+               }
+               if (!insert) {
+                       checkReport.addIssue("error.no-files-to-insert", true);
+               }
+               return checkReport;
+       }
+
+       /**
         * {@inheritDoc}
         */
        public void run() {
@@ -499,4 +558,138 @@ public class ProjectInserter implements FileScannerListener, Runnable {
                fileScanner.removeFileScannerListener(this);
        }
 
+       /**
+        * Container class that collects all warnings and errors that occured during
+        * {@link ProjectInserter#validateProject(Project) project validation}.
+        *
+        * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+        */
+       public static class CheckReport implements Iterable<Issue> {
+
+               /** The issures that occured. */
+               private final List<Issue> issues = new ArrayList<Issue>();
+
+               /**
+                * Adds an issue.
+                *
+                * @param issue
+                *            The issue to add
+                */
+               public void addIssue(Issue issue) {
+                       issues.add(issue);
+               }
+
+               /**
+                * Creates an {@link Issue} from the given error key and fatality flag
+                * and {@link #addIssue(Issue) adds} it.
+                *
+                * @param errorKey
+                *            The error key
+                * @param fatal
+                *            {@code true} if the error is fatal, {@code false} if only
+                *            a warning should be generated
+                * @param parameters
+                *            Any additional parameters
+                */
+               public void addIssue(String errorKey, boolean fatal, String... parameters) {
+                       addIssue(new Issue(errorKey, fatal, parameters));
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               public Iterator<Issue> iterator() {
+                       return issues.iterator();
+               }
+
+               /**
+                * Returns whether this check report does not contain any errors.
+                *
+                * @return {@code true} if this check report does not contain any
+                *         errors, {@code false} if this check report does contain
+                *         errors
+                */
+               public boolean isEmpty() {
+                       return issues.isEmpty();
+               }
+
+               /**
+                * Returns the number of issues in this check report.
+                *
+                * @return The number of issues
+                */
+               public int size() {
+                       return issues.size();
+               }
+
+               /**
+                * Container class for a single issue. An issue contains an error key
+                * that describes the error, and a fatality flag that determines whether
+                * the insert has to be aborted (if the flag is {@code true}) or if it
+                * can still be performed and only a warning should be generated (if the
+                * flag is {@code false}).
+                *
+                * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’
+                *         Roden</a>
+                */
+               public static class Issue {
+
+                       /** The error key. */
+                       private final String errorKey;
+
+                       /** The fatality flag. */
+                       private final boolean fatal;
+
+                       /** Additional parameters. */
+                       private String[] parameters;
+
+                       /**
+                        * Creates a new issue.
+                        *
+                        * @param errorKey
+                        *            The error key
+                        * @param fatal
+                        *            The fatality flag
+                        * @param parameters
+                        *            Any additional parameters
+                        */
+                       protected Issue(String errorKey, boolean fatal, String... parameters) {
+                               this.errorKey = errorKey;
+                               this.fatal = fatal;
+                               this.parameters = parameters;
+                       }
+
+                       /**
+                        * Returns the key of the encountered error.
+                        *
+                        * @return The error key
+                        */
+                       public String getErrorKey() {
+                               return errorKey;
+                       }
+
+                       /**
+                        * Returns whether the issue is fatal and the insert has to be
+                        * aborted. Otherwise only a warning should be shown.
+                        *
+                        * @return {@code true} if the insert needs to be aborted, {@code
+                        *         false} otherwise
+                        */
+                       public boolean isFatal() {
+                               return fatal;
+                       }
+
+                       /**
+                        * Returns any additional parameters.
+                        *
+                        * @return The additional parameters
+                        */
+                       public String[] getParameters() {
+                               return parameters;
+                       }
+
+               }
+
+       }
+
 }
index cd6ac67..db78119 100644 (file)
@@ -124,8 +124,6 @@ jsite.project.project.path=Freesite Path
 jsite.project.project.edition=Edition
 jsite.project.project.uri=URI
 jsite.project.keygen.io-error=<html><b>Node communication failure</b><br><br>Communication with the node failed<br>with the following error message:<br><br><code>{0}</code><br><br>Please make sure that you have entered<br>the correct host name and port number<br>on the "Node Settings" page.</html>
-jsite.project.warning.no-local-path=<html><b>No local path</b><br><br>You did not specify a local path for the files to insert.<br>It is not possible to continue without one.</html>
-jsite.project.warning.no-path=<html><b>No freesite path</b><br><br>You did not specify a freesite path.<br>It is not possible to continue without one.</html>
 jsite.project.warning.generate-new-key=<html><b>Generate new key?</b><br><br>If you generate a new key, your site will be published<br>under that new key. Any trust that other users put<br>in the old key of your site will be gone!</html>
 jsite.project.warning.reset-edition=<html><b>Reset edition?</b><br><br>Resetting the edition can lead to insert failures<br>and lots of confusion if you have not changed<br>the path or the keys of the project!</html>
 jsite.project.warning.use-clipboard-now=<html><b>URI copied</b><br><br>Please note that it is possible that quitting jSite<br>now will empty the clipboard. Please use the<br>copied URI immediately in another window!</html>
@@ -163,15 +161,6 @@ jsite.project-files.replacement.tooltip=Activates replacements in file
 jsite.project-files.replacement.edition-range=Range
 jsite.project-files.replacement.edition-range.tooltip=Also replace $[EDITION+1], $[EDITION+2]\u2026
 jsite.project-files.scan-error=<html><b>Error scanning files</b><br><br>Either the directory of the project does not exist<br>or some files/directories in it are not accessible.<br>Please go back and select the correct directory.</html>
-jsite.project-files.empty-index=<html><b>No default file</b><br><br>You did not specify a default file for this project.<br>While it is possible to insert a project without a default<br>file you should specify one to ease browsing.</html>
-jsite.project-files.index-missing=<html>Your default file is missing</b><br><br>A default file was previously specified but it<br>does not exist anymore! Please select<br>a new default file in the list of files.</html>
-jsite.project-files.container-index=<html><b>Default file in container</b><br><br>Your default file was placed in a container!<br>This might make other people shun your page.</html>
-jsite.project-files.index-not-html=<html><b>Default file is not HTML</b><br><br>Your default file does not have the MIME type "text/html"!<br>Loading your Freesite in a browser may give unexpected results.</html>
-jsite.project-files.no-node-running=<html><b>Node is not running</b><br><br>You can not insert a project if your node is not running.<br>Please start your node and try again.</html>
-jsite.project-files.no-custom-key=<html><b>No custom key for file</b><br><br>You specified not to insert <code>{0}</code><br>but failed to enter a key to redirect to!</html>
-jsite.project-files.no-node-selected=<html><b>No node selected</b><br><br>Please select a node from the menu!</html>
-jsite.project-files.no-files-to-insert=<html><b>No files to insert</b><br><br>You do not have any files selected for insertion!<br>Please select at least one file to insert.</html>
-jsite.project-files.index-not-inserted=<html><b>Default file not inserted</b><br><br>You have chosen not to insert the default file!<br>You need to either choose to insert it or select<br>a different default file!</html>
 jsite.project-files.insert-now=Insert now
 
 jsite.update-checker.found-version.title=Found New Version
@@ -190,3 +179,16 @@ jsite.key-dialog.label.keys=<html><b>Keys</b></html>
 jsite.key-dialog.label.private-key=Private Key
 jsite.key-dialog.label.public-key=Public Key
 jsite.key-dialog.label.actions=<html><b>Actions</b></html>
+
+jsite.warning.empty-index=<html><b>No default file</b><br><br>You did not specify a default file for this project.<br>While it is possible to insert a project without a default<br>file you should specify one to ease browsing.</html>
+jsite.warning.container-index=<html><b>Default file in container</b><br><br>Your default file was placed in a container!<br>This might make other people shun your page.</html>
+jsite.warning.index-not-html=<html><b>Default file is not HTML</b><br><br>Your default file does not have the MIME type "text/html"!<br>Loading your Freesite in a browser may give unexpected results.</html>
+
+jsite.error.no-node-selected=<html><b>No node selected</b><br><br>Please select a node from the menu!</html>
+jsite.error.no-node-running=<html><b>Node is not running</b><br><br>You can not insert a project if your node is not running.<br>Please start your node and try again.</html>
+jsite.error.no-local-path=<html><b>No local path</b><br><br>You did not specify a local path for the files to insert.<br>It is not possible to continue without one.</html>
+jsite.error.no-path=<html><b>No freesite path</b><br><br>You did not specify a freesite path.<br>It is not possible to continue without one.</html>
+jsite.error.index-missing=<html>Your default file is missing</b><br><br>A default file was previously specified but it<br>does not exist anymore! Please select<br>a new default file in the list of files.</html>
+jsite.error.index-not-inserted=<html><b>Default file not inserted</b><br><br>You have chosen not to insert the default file!<br>You need to either choose to insert it or select<br>a different default file!</html>
+jsite.error.no-custom-key=<html><b>No custom key for file</b><br><br>You specified not to insert <code>{0}</code><br>but failed to enter a key to redirect to!</html>
+jsite.error.no-files-to-insert=<html><b>No files to insert</b><br><br>You do not have any files selected for insertion!<br>Please select at least one file to insert.</html>
index efa121e..6c303ff 100644 (file)
@@ -124,8 +124,6 @@ jsite.project.project.path=Seitenpfad
 jsite.project.project.edition=Edition
 jsite.project.project.uri=Anfrage-URI
 jsite.project.keygen.io-error=<html><b>Kommunikation fehlgeschlagen</b><br><br>Die Kommunikation mit dem Freenet Node<br>ergab folgende Fehlermeldung:<br><br><code>{0}</code><br><br>Bitte vergewissern Sie sich, dass der Node l\u00e4uft und dass Sie<br> den korrekten Hostnamen und die korrekte Portnummer auf der<br>\u201eNode Einstellungen\u201c Seite eingegeben haben.</html>
-jsite.project.warning.no-local-path=<html><b>Kein lokaler Pfad</b><br><br>Sie haben keinen lokalen Pfad f\u00fcr die einzuf\u00fcgenden Dateien angegeben.<br>Es ist nicht m\u00f6glich, ohne lokalen Pfad weiter zu machen.</html>
-jsite.project.warning.no-path=<html><b>Kein Freesite-Pfad</b><br><br>Sie haben keinen Pfad f\u00fcr die Freesite angegeben.<br>Es ist nicht m\u00f6glich, ohne einen Freesite-Pfad weiter zu machen.</html>
 jsite.project.warning.generate-new-key=<html><b>Neues Schl\u00fcsselpaar generieren?</b><br><br>Wenn Sie das Schl\u00fcsselpaar f\u00fcr das Projekt \u00e4ndern,<br>wird sich die URI f\u00fcr Ihr Projekt ebenfalls<br>\u00e4ndern, und jegliches Vertrauen, dass andere<br>Benutzer in das alte Schl\u00fcsselpaar hatten, wird<br>verloren gehen!</html>
 jsite.project.warning.reset-edition=<html><b>Edition zur\u00fccksetzen?</b><br><br>Das Zur\u00fccksetzen der Editionsnummer kann zum<br>Fehlschlagen des Einf\u00fcgens f\u00fchren, wenn sich nicht<br>auch die URI oder der Pfad des Projekts ge\u00e4ndert haben!</html>
 jsite.project.warning.use-clipboard-now=<html><b>Anfrage-URI kopiert</b><br><br>Bitte beachten Sie, dass die Zwischenablage nach dem<br>Beenden von jSite eventuell nicht mehr die kopierte<br>URI enth\u00e4lt. Bitte f\u00fcgen Sie sie daher schleunigst in<br>ein anderes Programm ein!</html>
@@ -163,15 +161,6 @@ jsite.project-files.replacement.tooltip=Aktiviert Ersetzungen in Datei
 jsite.project-files.replacement.edition-range=Reichweite
 jsite.project-files.replacement.edition-range.tooltip=Ersetzt auch $[EDITION+1], $[EDITION+2], usw.
 jsite.project-files.scan-error=<html><b>Fehler beim Einlesen der Dateien</b><br><br>Entweder existiert das Projektverzeichnis nicht,<br>oder einige Dateien und/oder Verzeichnisse sind nicht lesbar!<br>Bitte gehen Sie zur\u00fcck und beheben Sie den Fehler!</html>
-jsite.project-files.empty-index=<html><b>Keine Index-Datei gew\u00e4hlt</b><br><br>Sie haben keine Index-Datei f\u00fcr das Projekt angegeben.<br>Obwohl es m\u00f6glich ist, das zu machen, sollten Sie doch<br>eine Index-Datei angeben, um das Browsen zu erleichtern.</html>
-jsite.project-files.index-missing=<html><b>Index-Datei fehlt!</b><br><br>Sie haben eine Index-Datei f\u00fcr das Project gew\u00e4hlt,<br>aber diese Index-Datei existiert nicht mehr!<br>Bitte w\u00e4hlen Sie eine neue Index-Datei.</html>
-jsite.project-files.container-index=<html><b>Index-Datei in Container</b><br><br>Ihre Index-Datei befindet sich in einem Container! Das kann<br>dazu f\u00fchren, dass Ihre Freesite von anderen Leuten gemieden wird.</html>
-jsite.project-files.index-not-html=<html><b>Index-Datei ist kein HTML</b><br><br>Ihre Index-Datei hat nicht den MIME-Typ "text/html"!<br>Das kann beim Besuch Ihrer Freesite zu<br>unerwarteten Ergebnissen f\u00fchren.</html>
-jsite.project-files.no-node-running=<html><b>Der Node l\u00e4uft nicht</b><br><br>Sie k\u00f6nnen das Projekt nicht einf\u00fcgen, wenn<br>Ihr Node nicht l\u00e4uft. Bitte starten Sie Ihren Node<br>und probieren Sie es erneut.</html>
-jsite.project-files.no-custom-key=<html><b>Kein externer Schl\u00fcssel</b><br><br>Sie haben angegeben, dass die Datei <code>{0}</code><br>nicht eingef\u00fcgt werden soll. Allerdings haben Sie<br>keinen extern erstellten Schl\u00fcssel angegeben.</html>
-jsite.project-files.no-node-selected=<html><b>Kein Node ausgew\u00e4hlt</b><br><br>Bitte w\u00e4hlen Sie einen Node aus dem Men\u00fc!</html>
-jsite.project-files.no-files-to-insert=<html><b>Keine Dateien einzuf\u00fcgen</b><br><br>Es sind keine Dateien zum Einf\u00fcgen ausgew\u00e4hlt! Bitte<br>w\u00e4hlen Sie mindestens eine Datei zum Einf\u00fcgen aus!</html>
-jsite.project-files.index-not-inserted=<html><b>Index-Datei nicht eingef\u00fcgt</b><br><br>Die index-Datei ist nicht zum Einf\u00fcgen ausgew\u00e4hlt!<br>Sie m\u00fcssen entweder w\u00e4hlen, die Index-Datei einzuf\u00fcgen,<br>oder Sie m\u00fcssen eine andere Index-Datei ausw\u00e4hlen!</html>
 jsite.project-files.insert-now=Jetzt einf\u00fcgen
 
 jsite.update-checker.found-version.title=Neue Version gefunden
@@ -190,3 +179,16 @@ jsite.key-dialog.label.keys=<html><b>Schl\u00fcssel</b></html>
 jsite.key-dialog.label.private-key=Privater Schl\u00fcssel
 jsite.key-dialog.label.public-key=\u00d6ffentlicher Schl\u00fcssel
 jsite.key-dialog.label.actions=<html><b>Aktionen</b></html>
+
+jsite.warning.empty-index=<html><b>Keine Index-Datei gew\u00e4hlt</b><br><br>Sie haben keine Index-Datei f\u00fcr das Projekt angegeben.<br>Obwohl es m\u00f6glich ist, das zu machen, sollten Sie doch<br>eine Index-Datei angeben, um das Browsen zu erleichtern.</html>
+jsite.warning.container-index=<html><b>Index-Datei in Container</b><br><br>Ihre Index-Datei befindet sich in einem Container! Das kann<br>dazu f\u00fchren, dass Ihre Freesite von anderen Leuten gemieden wird.</html>
+jsite.warning.index-not-html=<html><b>Index-Datei ist kein HTML</b><br><br>Ihre Index-Datei hat nicht den MIME-Typ "text/html"!<br>Das kann beim Besuch Ihrer Freesite zu<br>unerwarteten Ergebnissen f\u00fchren.</html>
+
+jsite.error.no-node-selected=<html><b>Kein Node ausgew\u00e4hlt</b><br><br>Bitte w\u00e4hlen Sie einen Node aus dem Men\u00fc!</html>
+jsite.error.no-node-running=<html><b>Der Node l\u00e4uft nicht</b><br><br>Sie k\u00f6nnen das Projekt nicht einf\u00fcgen, wenn<br>Ihr Node nicht l\u00e4uft. Bitte starten Sie Ihren Node<br>und probieren Sie es erneut.</html>
+jsite.error.no-local-path=<html><b>Kein lokaler Pfad</b><br><br>Sie haben keinen lokalen Pfad f\u00fcr die einzuf\u00fcgenden Dateien angegeben.<br>Es ist nicht m\u00f6glich, ohne lokalen Pfad weiter zu machen.</html>
+jsite.error.no-path=<html><b>Kein Freesite-Pfad</b><br><br>Sie haben keinen Pfad f\u00fcr die Freesite angegeben.<br>Es ist nicht m\u00f6glich, ohne einen Freesite-Pfad weiter zu machen.</html>
+jsite.error.index-missing=<html><b>Index-Datei fehlt!</b><br><br>Sie haben eine Index-Datei f\u00fcr das Project gew\u00e4hlt,<br>aber diese Index-Datei existiert nicht mehr!<br>Bitte w\u00e4hlen Sie eine neue Index-Datei.</html>
+jsite.error.index-not-inserted=<html><b>Index-Datei nicht eingef\u00fcgt</b><br><br>Die index-Datei ist nicht zum Einf\u00fcgen ausgew\u00e4hlt!<br>Sie m\u00fcssen entweder w\u00e4hlen, die Index-Datei einzuf\u00fcgen,<br>oder Sie m\u00fcssen eine andere Index-Datei ausw\u00e4hlen!</html>
+jsite.error.no-custom-key=<html><b>Kein externer Schl\u00fcssel</b><br><br>Sie haben angegeben, dass die Datei <code>{0}</code><br>nicht eingef\u00fcgt werden soll. Allerdings haben Sie<br>keinen extern erstellten Schl\u00fcssel angegeben.</html>
+jsite.error.no-files-to-insert=<html><b>Keine Dateien einzuf\u00fcgen</b><br><br>Es sind keine Dateien zum Einf\u00fcgen ausgew\u00e4hlt! Bitte<br>w\u00e4hlen Sie mindestens eine Datei zum Einf\u00fcgen aus!</html>
index 517f48a..cc540ea 100644 (file)
@@ -21,17 +21,12 @@ package de.todesbaum.jsite.main;
 
 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.Arrays;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Handler;
 import java.util.logging.Level;
@@ -50,12 +45,14 @@ import javax.swing.JRadioButtonMenuItem;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
-import de.todesbaum.jsite.application.FileOption;
 import de.todesbaum.jsite.application.Freenet7Interface;
 import de.todesbaum.jsite.application.Node;
 import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.application.ProjectInserter;
 import de.todesbaum.jsite.application.UpdateChecker;
 import de.todesbaum.jsite.application.UpdateListener;
+import de.todesbaum.jsite.application.ProjectInserter.CheckReport;
+import de.todesbaum.jsite.application.ProjectInserter.CheckReport.Issue;
 import de.todesbaum.jsite.gui.NodeManagerListener;
 import de.todesbaum.jsite.gui.NodeManagerPage;
 import de.todesbaum.jsite.gui.PreferencesPage;
@@ -496,11 +493,11 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
                        ProjectPage projectPage = (ProjectPage) wizard.getPage();
                        Project project = projectPage.getSelectedProject();
                        if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) {
-                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-local-path"), null, JOptionPane.ERROR_MESSAGE);
+                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.warning.no-local-path"), null, JOptionPane.ERROR_MESSAGE);
                                return;
                        }
                        if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) {
-                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-path"), null, JOptionPane.ERROR_MESSAGE);
+                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.warning.no-path"), null, JOptionPane.ERROR_MESSAGE);
                                return;
                        }
                        ((ProjectFilesPage) pages.get(PageType.PAGE_PROJECT_FILES)).setProject(project);
@@ -510,53 +507,19 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
                        ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
                        Project project = projectPage.getSelectedProject();
                        if (selectedNode == null) {
-                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
+                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.error.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
                                return;
                        }
-                       if ((project.getIndexFile() == null) || (project.getIndexFile().length() == 0)) {
-                               if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.empty-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
+                       CheckReport checkReport = ProjectInserter.validateProject(project);
+                       for (Issue issue : checkReport) {
+                               if (issue.isFatal()) {
+                                       JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite." + issue.getErrorKey()), (Object[]) issue.getParameters()), null, JOptionPane.ERROR_MESSAGE);
                                        return;
                                }
-                       } else {
-                               File indexFile = new File(project.getLocalPath(), project.getIndexFile());
-                               if (!indexFile.exists()) {
-                                       JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.index-missing"), null, JOptionPane.ERROR_MESSAGE);
+                               if (JOptionPane.showConfirmDialog(wizard, MessageFormat.format(I18n.getMessage("jsite." + issue.getErrorKey()), (Object[]) issue.getParameters()), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
                                        return;
                                }
                        }
-                       String indexFile = project.getIndexFile();
-                       boolean hasIndexFile = (indexFile != null);
-                       if (hasIndexFile && !project.getFileOption(indexFile).getContainer().equals("")) {
-                               if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.container-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
-                                       return;
-                               }
-                       }
-                       List<String> allowedIndexContentTypes = Arrays.asList("text/html", "application/xhtml+xml");
-                       if (hasIndexFile && !allowedIndexContentTypes.contains(project.getFileOption(indexFile).getMimeType())) {
-                               if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.index-not-html"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
-                                       return;
-                               }
-                       }
-                       Map<String, FileOption> fileOptions = project.getFileOptions();
-                       Set<Entry<String, FileOption>> fileOptionEntries = fileOptions.entrySet();
-                       boolean insert = false;
-                       for (Entry<String, FileOption> fileOptionEntry : fileOptionEntries) {
-                               String fileName = fileOptionEntry.getKey();
-                               FileOption fileOption = fileOptionEntry.getValue();
-                               insert |= fileOption.isInsert() || fileOption.isInsertRedirect();
-                               if (fileName.equals(project.getIndexFile()) && !fileOption.isInsert() && !fileOption.isInsertRedirect()) {
-                                       JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.index-not-inserted"), null, JOptionPane.ERROR_MESSAGE);
-                                       return;
-                               }
-                               if (!fileOption.isInsert() && fileOption.isInsertRedirect() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) {
-                                       JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.project-files.no-custom-key"), fileOptionEntry.getKey()), null, JOptionPane.ERROR_MESSAGE);
-                                       return;
-                               }
-                       }
-                       if (!insert) {
-                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-files-to-insert"), null, JOptionPane.ERROR_MESSAGE);
-                               return;
-                       }
                        boolean nodeRunning = false;
                        try {
                                nodeRunning = freenetInterface.isNodePresent();
@@ -564,7 +527,7 @@ public class Main implements ActionListener, ListSelectionListener, WizardListen
                                /* ignore. */
                        }
                        if (!nodeRunning) {
-                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
+                               JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.error.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
                                return;
                        }
                        configuration.save();