<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="images"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="output" path="bin"/>
+ <classpathentry kind="src" output="target/classes" path="src/main/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes"/>
</classpath>
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>net.pterodactylus</groupId>
+ <artifactId>jSite</artifactId>
+ <version>0.11-SNAPSHOT</version>
+ <repositories>
+ <repository>
+ <id>pterodactylus</id>
+ <url>http://maven.pterodactylus.net/</url>
+ </repository>
+ </repositories>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>de.todesbaum.jsite.main.Main</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2-beta-5</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ <archiverConfig>
+ <duplicateBehavior>skip</duplicateBehavior>
+ </archiverConfig>
+ <archive>
+ <manifest>
+ <mainClass>de.todesbaum.jsite.main.Main</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <links>
+ <link>http://download.oracle.com/javase/6/docs/api/</link>
+ <link>http://java.pterodactylus.net/utils/apidocs/</link>
+ <link>http://java.pterodactylus.net/utils.json/apidocs/</link>
+ </links>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
+++ /dev/null
-/*
- * jSite - AbortedException.java - Copyright © 2010–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-/**
- * Marker exception that signals that the user aborted an insert.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class AbortedException extends Exception {
-
- /* nothing here. */
-
-}
+++ /dev/null
-/*
- * jSite - FileOption.java - Copyright © 2006–2012 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 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-/**
- * Container for various file options.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class FileOption {
-
- /** The default for the insert state. */
- private static final boolean DEFAULT_INSERT = true;
-
- /** The default for the insert redirect state. */
- private static final boolean DEFAULT_INSERT_REDIRECT = true;
-
- /** The default for the custom key. */
- private static final String DEFAULT_CUSTOM_KEY = "CHK@";
-
- /** The default changed name. */
- private static final String DEFAULT_CHANGED_NAME = null;
-
- /** The insert state. */
- private boolean insert;
-
- /** Whether to force an insert. */
- private boolean forceInsert;
-
- /** Whether to insert a redirect. */
- private boolean insertRedirect;
-
- /** The hash of the last insert. */
- private String lastInsertHash;
-
- /** The edition of the last insert. */
- private int lastInsertEdition;
-
- /** The filename of the last insert. */
- private String lastInsertFilename;
-
- /** The current hash of the file. */
- private String currentHash;
-
- /** The custom key. */
- private String customKey;
-
- /** The changed name. */
- private String changedName;
-
- /** The default MIME type. */
- private final String defaultMimeType;
-
- /** The current MIME type. */
- private String mimeType;
-
- /**
- * Creates new file options.
- *
- * @param defaultMimeType
- * The default MIME type of the file
- */
- public FileOption(String defaultMimeType) {
- insert = DEFAULT_INSERT;
- insertRedirect = DEFAULT_INSERT_REDIRECT;
- customKey = DEFAULT_CUSTOM_KEY;
- changedName = DEFAULT_CHANGED_NAME;
- this.defaultMimeType = defaultMimeType;
- mimeType = defaultMimeType;
- }
-
- /**
- * Returns the custom key. The custom key is only used when
- * {@link #isInsert()} and {@link #isInsertRedirect()} both return {@code
- * true}.
- *
- * @return The custom key
- */
- public String getCustomKey() {
- return customKey;
- }
-
- /**
- * Sets the custom key. The custom key is only used when {@link #isInsert()}
- * and {@link #isInsertRedirect()} both return {@code true}.
- *
- * @param customKey
- * The custom key
- */
- public void setCustomKey(String customKey) {
- if (customKey == null) {
- this.customKey = "";
- } else {
- this.customKey = customKey;
- }
- }
-
- /**
- * Returns whether the file should be inserted. If a file is not inserted
- * and {@link #isInsertRedirect()} is also {@code false}, the file will not
- * be inserted at all.
- *
- * @see #setCustomKey(String)
- * @return <code>true</code> if the file should be inserted,
- * <code>false</code> otherwise
- */
- public boolean isInsert() {
- return insert;
- }
-
- /**
- * Sets whether the file should be inserted. If a file is not inserted and
- * {@link #isInsertRedirect()} is also {@code false}, the file will not be
- * inserted at all.
- *
- * @param insert
- * <code>true</code> if the file should be inserted,
- * <code>false</code> otherwise
- */
- public void setInsert(boolean insert) {
- this.insert = insert;
- }
-
- /**
- * Returns whether the insert of this file should be forced, even if its
- * current hash matches the last insert hash.
- *
- * @return {@code true} to force the insert of this file, {@code false}
- * otherwise
- */
- public boolean isForceInsert() {
- return forceInsert;
- }
-
- /**
- * Sets whether to force the insert of this file, even if its current hash
- * matches the last insert hash.
- *
- * @param forceInsert
- * {@code true} to force the insert of this file, {@code false}
- * otherwise
- * @return These file options
- */
- public FileOption setForceInsert(boolean forceInsert) {
- this.forceInsert = forceInsert;
- return this;
- }
-
- /**
- * Returns whether a redirect to a different key should be inserted. This
- * will only matter if {@link #isInsert()} returns {@code false}. The key
- * that should be redirected to still needs to be specified via
- * {@link #setCustomKey(String)}.
- *
- * @return {@code true} if a redirect should be inserted, {@code false}
- * otherwise
- */
- public boolean isInsertRedirect() {
- return insertRedirect;
- }
-
- /**
- * Sets whether a redirect should be inserted. This will only matter if
- * {@link #isInsert()} returns {@code false}, i.e. it has been
- * {@link #setInsert(boolean)} to {@code false}. The key that should be
- * redirected to still needs to be specified via
- * {@link #setCustomKey(String)}.
- *
- * @param insertRedirect
- * {@code true} if a redirect should be inserted, {@code false}
- * otherwise
- */
- public void setInsertRedirect(boolean insertRedirect) {
- this.insertRedirect = insertRedirect;
- }
-
- /**
- * Returns the hash of the file when it was last inserted
- *
- * @return The last hash of the file
- */
- public String getLastInsertHash() {
- return lastInsertHash;
- }
-
- /**
- * Sets the hash of the file when it was last inserted.
- *
- * @param lastInsertHash
- * The last hash of the file
- * @return These file options
- */
- public FileOption setLastInsertHash(String lastInsertHash) {
- this.lastInsertHash = lastInsertHash;
- return this;
- }
-
- /**
- * Returns the last edition at which this file was inserted.
- *
- * @return The last insert edition of this file
- */
- public int getLastInsertEdition() {
- return lastInsertEdition;
- }
-
- /**
- * Sets the last insert edition of this file.
- *
- * @param lastInsertEdition
- * The last insert edition of this file
- * @return These file options
- */
- public FileOption setLastInsertEdition(int lastInsertEdition) {
- this.lastInsertEdition = lastInsertEdition;
- return this;
- }
-
- /**
- * Returns the name of the file when it was last inserted.
- *
- * @return The name of the file at the last insert
- */
- public String getLastInsertFilename() {
- return lastInsertFilename;
- }
-
- /**
- * Sets the name of the file when it was last inserted.
- *
- * @param lastInsertFilename
- * The name of the file at the last insert.
- * @return These file options
- */
- public FileOption setLastInsertFilename(String lastInsertFilename) {
- this.lastInsertFilename = lastInsertFilename;
- return this;
- }
-
- /**
- * Returns the current hash of the file. This value is ony a temporary value
- * that is copied to {@link #getLastInsertHash()} when a project has
- * finished inserting.
- *
- * @see Project#onSuccessfulInsert()
- * @return The current hash of the file
- */
- public String getCurrentHash() {
- return currentHash;
- }
-
- /**
- * Sets the current hash of the file.
- *
- * @param currentHash
- * The current hash of the file
- * @return These file options
- */
- public FileOption setCurrentHash(String currentHash) {
- this.currentHash = currentHash;
- return this;
- }
-
- /**
- * Returns whether this file has a changed name. Use
- * {@link #getChangedName()} is this method returns {@code true}.
- *
- * @return {@code true} if this file has a changed name, {@code false}
- * otherwise
- */
- public boolean hasChangedName() {
- return (changedName != null) && (changedName.length() > 0);
- }
-
- /**
- * Returns the changed name for this file. This method will return {@code
- * null} or an empty {@link String} if this file should not be renamed.
- *
- * @return The changed name, or {@code null} if this file should not be
- * renamed
- */
- public String getChangedName() {
- return changedName;
- }
-
- /**
- * Sets the changed name for this file. Setting the changed file to {@code
- * null} or an empty {@link String} will disable renaming.
- *
- * @param changedName
- * The new changed name for this file
- */
- public void setChangedName(String changedName) {
- this.changedName = changedName;
- }
-
- /**
- * Sets the MIME type of the file. Setting the MIME type to
- * <code>null</code> will set the MIME type to the default MIME type.
- *
- * @param mimeType
- * The MIME type of the file
- */
- public void setMimeType(String mimeType) {
- if (mimeType == null) {
- this.mimeType = defaultMimeType;
- } else {
- this.mimeType = mimeType;
- }
- }
-
- /**
- * Returns the MIME type of the file. If no custom MIME type has been set,
- * the default MIME type is returned.
- *
- * @return The MIME type of the file
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Returns whether the options for this file have been modified, i.e. are
- * not at their default values.
- *
- * @return <code>true</code> if the options have been modified,
- * <code>false</code> if they are at default values
- */
- public boolean isCustom() {
- if (insert != DEFAULT_INSERT) {
- return true;
- }
- if (!customKey.equals(DEFAULT_CUSTOM_KEY)) {
- return true;
- }
- if (((changedName != null) && !changedName.equals(DEFAULT_CHANGED_NAME)) || ((DEFAULT_CHANGED_NAME != null) && !DEFAULT_CHANGED_NAME.equals(changedName))) {
- return true;
- }
- if (!defaultMimeType.equals(mimeType)) {
- return true;
- }
- if (insertRedirect != DEFAULT_INSERT_REDIRECT) {
- return true;
- }
- return false;
- }
-
-}
+++ /dev/null
-/*
- * jSite - Freenet7Interface.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-import java.io.IOException;
-
-import de.todesbaum.util.freenet.fcp2.Client;
-import de.todesbaum.util.freenet.fcp2.Connection;
-import de.todesbaum.util.freenet.fcp2.GenerateSSK;
-import de.todesbaum.util.freenet.fcp2.Message;
-import de.todesbaum.util.freenet.fcp2.Node;
-
-/**
- * Interface for freenet-related operations.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class Freenet7Interface {
-
- /** Random number to differentiate several jSites. */
- private static final int number = (int) (Math.random() * Integer.MAX_VALUE);
-
- /** Counter. */
- private static int counter = 0;
-
- /** The node to connect to. */
- private Node node;
-
- /** The connection to the node. */
- private Connection connection;
-
- /**
- * Sets the hostname of the node. The default port for FCP2 connections ({@link Node#DEFAULT_PORT})
- * is used.
- *
- * @param hostname
- * The hostname of the node
- */
- public void setNodeAddress(String hostname) {
- node = new Node(hostname);
- connection = new Connection(node, "jSite-" + number + "-connection-" + counter++);
- }
-
- /**
- * Sets the hostname and the port of the node.
- *
- * @param hostname
- * The hostname of the node
- * @param port
- * The port number of the node
- */
- public void setNodeAddress(String hostname, int port) {
- node = new Node(hostname, port);
- connection = new Connection(node, "jSite-" + number + "-connection-" + counter++);
- }
-
- /**
- * Sets hostname and port from the given node.
- *
- * @param node
- * The node to get the hostname and port from
- */
- public void setNode(de.todesbaum.jsite.application.Node node) {
- if (node != null) {
- this.node = new Node(node.getHostname(), node.getPort());
- connection = new Connection(node, "jSite-" + number + "-connection-" + counter++);
- } else {
- this.node = null;
- connection = null;
- }
- }
-
- /**
- * Removes the current node from the interface.
- */
- public void removeNode() {
- node = null;
- connection = null;
- }
-
- /**
- * Returns the node this interface is connecting to.
- *
- * @return The node
- */
- public Node getNode() {
- return node;
- }
-
- /**
- * Creates a new connection to the current node with the given identifier.
- *
- * @param identifier
- * The identifier of the connection
- * @return The connection to the node
- */
- public Connection getConnection(String identifier) {
- return new Connection(node, identifier);
- }
-
- /**
- * Checks whether the current node is connected. If the node is not
- * connected, a connection will be tried.
- *
- * @return <code>true</code> if the node is connected, <code>false</code>
- * otherwise
- * @throws IOException
- * if an I/O error occurs communicating with the node
- */
- public boolean isNodePresent() throws IOException {
- if (!connection.isConnected()) {
- return connection.connect();
- }
- return true;
- }
-
- /**
- * Generates an SSK key pair.
- *
- * @return An array of strings, the first one being the generated private
- * (insert) URI and the second one being the generated public
- * (request) URI
- * @throws IOException
- * if an I/O error occurs communicating with the node
- */
- public String[] generateKeyPair() throws IOException {
- if (!isNodePresent()) {
- throw new IOException("Node is offline.");
- }
- GenerateSSK generateSSK = new GenerateSSK();
- Client client = new Client(connection, generateSSK);
- Message keypairMessage = client.readMessage();
- return new String[] { keypairMessage.get("InsertURI"), keypairMessage.get("RequestURI") };
- }
-
- /**
- * Checks whether the interface has already been configured with a node.
- *
- * @return <code>true</code> if this interface already has a node set,
- * <code>false</code> otherwise
- */
- public boolean hasNode() {
- return (node != null) && (connection != null);
- }
-
-}
+++ /dev/null
-/*
- * jSite - InsertListener.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-import java.util.EventListener;
-
-/**
- * Interface for objects that want to be notified abount insert events.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public interface InsertListener extends EventListener {
-
- /**
- * Enumeration for the different error situations.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
- public static enum ErrorType {
-
- /** The key does already exist. */
- KEY_COLLISION,
-
- /** The route to the key was not found. */
- ROUTE_NOT_FOUND,
-
- /** The data was not found. */
- DATA_NOT_FOUND,
-
- /** Error in the FCP communication. */
- FCP_ERROR,
-
- /** General error in the communication. */
- IO_ERROR
- }
-
- /**
- * Notifies a listener that an insert has started.
- *
- * @param project
- * The project that is now being inserted
- */
- public void projectInsertStarted(Project project);
-
- /**
- * Notifies a listener that the upload of a project has finished and the
- * inserting will start now.
- *
- * @param project
- * The project that has been uploaded
- */
- public void projectUploadFinished(Project project);
-
- /**
- * Notifies a listener that a project insert has generated a URI.
- *
- * @param project
- * The project being inserted
- * @param uri
- * The generated URI
- */
- public void projectURIGenerated(Project project, String uri);
-
- /**
- * Notifies a listener that an insert has made some progress.
- *
- * @param project
- * The project being inserted
- * @param succeeded
- * The number of succeeded blocks
- * @param failed
- * The number of failed blocks
- * @param fatal
- * The number of fatally failed blocks
- * @param total
- * The total number of blocks
- * @param finalized
- * <code>true</code> if the total number of blocks has been
- * finalized, <code>false</code> otherwise
- */
- public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized);
-
- /**
- * Notifies a listener that a project insert has finished.
- *
- * @param project
- * The project being inserted
- * @param success
- * <code>true</code> if the insert succeeded, <code>false</code>
- * otherwise
- * @param cause
- * The cause of a failure, if any (may be <code>null</code>)
- */
- public void projectInsertFinished(Project project, boolean success, Throwable cause);
-
-}
+++ /dev/null
-/*
- * jSite - KeyDialog.java - Copyright © 2010–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.IOException;
-import java.text.MessageFormat;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JSeparator;
-import javax.swing.JTextField;
-import javax.swing.KeyStroke;
-import javax.swing.SwingConstants;
-
-import de.todesbaum.jsite.i18n.I18n;
-import de.todesbaum.jsite.i18n.I18nContainer;
-
-/**
- * A dialog that lets the user edit the private and public key for a project.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class KeyDialog extends JDialog {
-
- /** Interface to the freenet node. */
- private final Freenet7Interface freenetInterface;
-
- /** The public key. */
- private String publicKey;
-
- /** The private key. */
- private String privateKey;
-
- /** The “OK” button’s action. */
- private Action okAction;
-
- /** The “Cancel” button’s action. */
- private Action cancelAction;
-
- /** The “Regenerate” button’s action. */
- private Action generateAction;
-
- /** The text field for the private key. */
- private JTextField privateKeyTextField;
-
- /** The text field for the public key. */
- private JTextField publicKeyTextField;
-
- /** Whether the dialog was cancelled. */
- private boolean cancelled;
-
- /**
- * Creates a new key dialog.
- *
- * @param freenetInterface
- * Interface to the freenet node
- * @param parent
- * The parent frame
- */
- public KeyDialog(Freenet7Interface freenetInterface, JFrame parent) {
- super(parent, I18n.getMessage("jsite.key-dialog.title"), true);
- this.freenetInterface = freenetInterface;
- addWindowListener(new WindowAdapter() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void windowClosing(WindowEvent windowEvent) {
- actionCancel();
- }
- });
- initDialog();
- }
-
- //
- // ACCESSORS
- //
-
- /**
- * Returns whether the dialog was cancelled.
- *
- * @return {@code true} if the dialog was cancelled, {@code false} otherwise
- */
- public boolean wasCancelled() {
- return cancelled;
- }
-
- /**
- * Returns the public key.
- *
- * @return The public key
- */
- public String getPublicKey() {
- return publicKey;
- }
-
- /**
- * Sets the public key.
- *
- * @param publicKey
- * The public key
- */
- public void setPublicKey(String publicKey) {
- this.publicKey = publicKey;
- publicKeyTextField.setText(publicKey);
- pack();
- }
-
- /**
- * Returns the private key.
- *
- * @return The private key
- */
- public String getPrivateKey() {
- return privateKey;
- }
-
- /**
- * Sets the private key.
- *
- * @param privateKey
- * The private key
- */
- public void setPrivateKey(String privateKey) {
- this.privateKey = privateKey;
- privateKeyTextField.setText(privateKey);
- pack();
- }
-
- //
- // ACTIONS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void pack() {
- super.pack();
- Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
- setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2);
- }
-
- //
- // PRIVATE METHODS
- //
-
- /**
- * Creates all necessary actions.
- */
- private void createActions() {
- okAction = new AbstractAction(I18n.getMessage("jsite.general.ok")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionOk();
- }
- };
- okAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.ok.tooltip"));
- okAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_ENTER);
-
- cancelAction = new AbstractAction(I18n.getMessage("jsite.general.cancel")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionCancel();
- }
- };
- cancelAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.cancel.tooltip"));
- cancelAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_ESCAPE);
-
- generateAction = new AbstractAction(I18n.getMessage("jsite.key-dialog.button.generate")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionGenerate();
- }
- };
- generateAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.generate.tooltip"));
- generateAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
- }
-
- /**
- * Initializes the dialog and all its components.
- */
- private void initDialog() {
- createActions();
- JPanel dialogPanel = new JPanel(new BorderLayout(12, 12));
- dialogPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
-
- JPanel contentPanel = new JPanel(new GridBagLayout());
- dialogPanel.add(contentPanel, BorderLayout.CENTER);
-
- final JLabel keysLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.keys"));
- contentPanel.add(keysLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
-
- final JLabel privateKeyLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.private-key"));
- contentPanel.add(privateKeyLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0));
-
- privateKeyTextField = new JTextField();
- contentPanel.add(privateKeyTextField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0));
-
- final JLabel publicKeyLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.public-key"));
- contentPanel.add(publicKeyLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
-
- publicKeyTextField = new JTextField();
- contentPanel.add(publicKeyTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0));
-
- final JLabel actionsLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.actions"));
- contentPanel.add(actionsLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
-
- JPanel actionButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
- actionButtonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
- contentPanel.add(actionButtonPanel, new GridBagConstraints(0, 4, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0));
-
- actionButtonPanel.add(new JButton(generateAction));
-
- JPanel separatorPanel = new JPanel(new BorderLayout(12, 12));
- dialogPanel.add(separatorPanel, BorderLayout.PAGE_END);
- separatorPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.PAGE_START);
-
- JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
- buttonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
- separatorPanel.add(buttonPanel, BorderLayout.CENTER);
- buttonPanel.add(new JButton(okAction));
- buttonPanel.add(new JButton(cancelAction));
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- keysLabel.setText(I18n.getMessage("jsite.key-dialog.label.keys"));
- privateKeyLabel.setText(I18n.getMessage("jsite.key-dialog.label.private-key"));
- publicKeyLabel.setText(I18n.getMessage("jsite.key-dialog.label.public-key"));
- actionsLabel.setText(I18n.getMessage("jsite.key-dialog.label.actions"));
- }
- });
-
- getContentPane().add(dialogPanel, BorderLayout.CENTER);
- pack();
- setResizable(false);
- }
-
- //
- // PRIVATE ACTIONS
- //
-
- /**
- * Quits the dialog, accepting all changes.
- */
- private void actionOk() {
- publicKey = publicKeyTextField.getText();
- privateKey = privateKeyTextField.getText();
- cancelled = false;
- setVisible(false);
- }
-
- /**
- * Quits the dialog, discarding all changes.
- */
- private void actionCancel() {
- cancelled = true;
- setVisible(false);
- }
-
- /**
- * Generates a new key pair.
- */
- private void actionGenerate() {
- if (JOptionPane.showConfirmDialog(this, I18n.getMessage("jsite.project.warning.generate-new-key"), null, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
- return;
- }
- String[] keyPair = null;
- try {
- keyPair = freenetInterface.generateKeyPair();
- } catch (IOException ioe1) {
- JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE);
- return;
- }
- publicKeyTextField.setText(keyPair[1].substring(keyPair[1].indexOf('@') + 1, keyPair[1].lastIndexOf('/')));
- privateKeyTextField.setText(keyPair[0].substring(keyPair[0].indexOf('@') + 1, keyPair[0].lastIndexOf('/')));
- pack();
- }
-
-}
+++ /dev/null
-/*
- * jSite - Node.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-/**
- * Container for node information.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class Node extends de.todesbaum.util.freenet.fcp2.Node {
-
- /** The name of the node. */
- protected String name;
-
- /**
- * Creates a new node with the given hostname and the default port.
- *
- * @see de.todesbaum.util.freenet.fcp2.Node#DEFAULT_PORT
- * @param hostname
- * The hostname of the new node
- */
- public Node(String hostname) {
- this(hostname, DEFAULT_PORT);
- }
-
- /**
- * Creates a new node with the given hostname and port.
- *
- * @param hostname
- * The hostname of the new node
- * @param port
- * The port of the new node
- */
- public Node(String hostname, int port) {
- this(hostname, port, "");
- }
-
- /**
- * Creates a new node with the given hostname, port, and name.
- *
- * @param hostname
- * The hostname of the new node
- * @param port
- * The port of the new node
- * @param name
- * The name of the node
- */
- public Node(String hostname, int port, String name) {
- super(hostname, port);
- this.name = name;
- }
-
- /**
- * Creates a new node that gets its settings from the given node.
- *
- * @param node
- * The node to copy
- */
- public Node(Node node) {
- this(node.getHostname(), node.getPort());
- }
-
- /**
- * Creates a new node from the given node, overwriting the name.
- *
- * @param node
- * The node to copy from
- * @param name
- * The new name of the node
- */
- public Node(Node node, String name) {
- this(node.getHostname(), node.getPort(), name);
- }
-
- /**
- * Sets the name of the node.
- *
- * @param name
- * The name of the node
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Returns the name of the node.
- *
- * @return The name of the node
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the hostname of the node.
- *
- * @param hostname
- * The hostname of the node
- */
- public void setHostname(String hostname) {
- this.hostname = hostname;
- }
-
- /**
- * Sets the port of the node.
- *
- * @param port
- * The port of the node
- */
- public void setPort(int port) {
- this.port = port;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * A node is considered as being equal to this node its name, hostname, and
- * port equal their counterparts in this node.
- */
- @Override
- public boolean equals(Object o) {
- if ((o == null) || !(o instanceof Node)) {
- return false;
- }
- Node node = (Node) o;
- return name.equals(node.name) && hostname.equals(node.hostname) && (port == node.port);
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * The hashcode for a node is created from its name, its hostname, and its
- * port.
- */
- @Override
- public int hashCode() {
- return name.hashCode() ^ hostname.hashCode() ^ port;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Creates a textual representation of this node.
- */
- @Override
- public String toString() {
- return name + " (" + hostname + ":" + port + ")";
- }
-
-}
+++ /dev/null
-/*
- * jSite - Project.java - Copyright © 2006–2012 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 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import de.todesbaum.util.mime.DefaultMIMETypes;
-
-/**
- * Container for project information.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class Project implements Comparable<Project> {
-
- /** The name of the project. */
- protected String name;
-
- /** The description of the project. */
- protected String description;
-
- /** The insert URI of the project. */
- protected String insertURI;
-
- /** The request URI of the project. */
- protected String requestURI;
-
- /** The index file of the project. */
- protected String indexFile;
-
- /** The local path of the project. */
- protected String localPath;
-
- /** The remote path of the URI. */
- protected String path;
-
- /** The time of the last insertion. */
- protected long lastInsertionTime;
-
- /** The edition to insert to. */
- protected int edition;
-
- /** Whether to ignore hidden directory. */
- private boolean ignoreHiddenFiles;
-
- /** Options for files. */
- protected Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
-
- /**
- * Empty constructor.
- */
- public Project() {
- /* do nothing. */
- }
-
- /**
- * Creates a new project from an existing one.
- *
- * @param project
- * The project to clone
- */
- public Project(Project project) {
- name = project.name;
- description = project.description;
- insertURI = project.insertURI;
- requestURI = project.requestURI;
- path = project.path;
- edition = project.edition;
- localPath = project.localPath;
- indexFile = project.indexFile;
- lastInsertionTime = project.lastInsertionTime;
- ignoreHiddenFiles = project.ignoreHiddenFiles;
- fileOptions = new HashMap<String, FileOption>(project.fileOptions);
- }
-
- /**
- * Returns the name of the project.
- *
- * @return The name of the project
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the name of the project.
- *
- * @param name
- * The name of the project
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Returns the description of the project.
- *
- * @return The description of the project
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * Sets the description of the project.
- *
- * @param description
- * The description of the project
- */
- public void setDescription(String description) {
- this.description = description;
- }
-
- /**
- * Returns the local path of the project.
- *
- * @return The local path of the project
- */
- public String getLocalPath() {
- return localPath;
- }
-
- /**
- * Sets the local path of the project.
- *
- * @param localPath
- * The local path of the project
- */
- public void setLocalPath(String localPath) {
- this.localPath = localPath;
- }
-
- /**
- * Returns the name of the index file of the project, relative to the
- * project’s local path.
- *
- * @return The name of the index file of the project
- */
- public String getIndexFile() {
- return indexFile;
- }
-
- /**
- * Sets the name of the index file of the project, relative to the project’s
- * local path.
- *
- * @param indexFile
- * The name of the index file of the project
- */
- public void setIndexFile(String indexFile) {
- this.indexFile = indexFile;
- }
-
- /**
- * Returns the time the project was last inserted, in milliseconds since the
- * epoch.
- *
- * @return The time of the last insertion
- */
- public long getLastInsertionTime() {
- return lastInsertionTime;
- }
-
- /**
- * Sets the time the project was last inserted, in milliseconds since the
- * last epoch.
- *
- * @param lastInserted
- * The time of the last insertion
- */
- public void setLastInsertionTime(long lastInserted) {
- lastInsertionTime = lastInserted;
- }
-
- /**
- * Returns the remote path of the project. The remote path is the path that
- * directly follows the request URI of the project.
- *
- * @return The remote path of the project
- */
- public String getPath() {
- return path;
- }
-
- /**
- * Sets the remote path of the project. The remote path is the path that
- * directly follows the request URI of the project.
- *
- * @param path
- * The remote path of the project
- */
- public void setPath(String path) {
- this.path = path;
- }
-
- /**
- * Returns the insert URI of the project.
- *
- * @return The insert URI of the project
- */
- public String getInsertURI() {
- return insertURI;
- }
-
- /**
- * Sets the insert URI of the project.
- *
- * @param insertURI
- * The insert URI of the project
- */
- public void setInsertURI(String insertURI) {
- this.insertURI = shortenURI(insertURI);
- }
-
- /**
- * Returns the request URI of the project.
- *
- * @return The request URI of the project
- */
- public String getRequestURI() {
- return requestURI;
- }
-
- /**
- * Sets the request URI of the project.
- *
- * @param requestURI
- * The request URI of the project
- */
- public void setRequestURI(String requestURI) {
- this.requestURI = shortenURI(requestURI);
- }
-
- /**
- * Returns whether hidden files are ignored, i.e. not inserted.
- *
- * @return {@code true} if hidden files are not inserted, {@code false}
- * otherwise
- */
- public boolean isIgnoreHiddenFiles() {
- return ignoreHiddenFiles;
- }
-
- /**
- * Sets whether hidden files are ignored, i.e. not inserted.
- *
- * @param ignoreHiddenFiles
- * {@code true} if hidden files are not inserted, {@code false}
- * otherwise
- */
- public void setIgnoreHiddenFiles(boolean ignoreHiddenFiles) {
- this.ignoreHiddenFiles = ignoreHiddenFiles;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * This method returns the name of the project.
- */
- @Override
- public String toString() {
- return name;
- }
-
- /**
- * Shortens the given URI by removing scheme and key-type prefixes.
- *
- * @param uri
- * The URI to shorten
- * @return The shortened URI
- */
- private String shortenURI(String uri) {
- String shortUri = uri;
- if (shortUri.startsWith("freenet:")) {
- shortUri = shortUri.substring("freenet:".length());
- }
- if (shortUri.startsWith("SSK@")) {
- shortUri = shortUri.substring("SSK@".length());
- }
- if (shortUri.startsWith("USK@")) {
- shortUri = shortUri.substring("USK@".length());
- }
- if (shortUri.endsWith("/")) {
- shortUri = shortUri.substring(0, shortUri.length() - 1);
- }
- return shortUri;
- }
-
- /**
- * Shortens the name of the given file by removing the local path of the
- * project and leading file separators.
- *
- * @param file
- * The file whose name should be shortened
- * @return The shortened name of the file
- */
- public String shortenFilename(File file) {
- String filename = file.getPath();
- if (filename.startsWith(localPath)) {
- filename = filename.substring(localPath.length());
- if (filename.startsWith(File.separator)) {
- filename = filename.substring(1);
- }
- }
- return filename;
- }
-
- /**
- * Returns the options for the file with the given name. If the file does
- * not yet have any options, a new set of default options is created and
- * returned.
- *
- * @param filename
- * The name of the file, relative to the project root
- * @return The options for the file
- */
- public FileOption getFileOption(String filename) {
- FileOption fileOption = fileOptions.get(filename);
- if (fileOption == null) {
- fileOption = new FileOption(DefaultMIMETypes.guessMIMEType(filename));
- fileOptions.put(filename, fileOption);
- }
- return fileOption;
- }
-
- /**
- * Sets options for a file.
- *
- * @param filename
- * The filename to set the options for, relative to the project
- * root
- * @param fileOption
- * The options to set for the file, or <code>null</code> to
- * remove the options for the file
- */
- public void setFileOption(String filename, FileOption fileOption) {
- if (fileOption != null) {
- fileOptions.put(filename, fileOption);
- } else {
- fileOptions.remove(filename);
- }
- }
-
- /**
- * Returns all file options.
- *
- * @return All file options
- */
- public Map<String, FileOption> getFileOptions() {
- return Collections.unmodifiableMap(fileOptions);
- }
-
- /**
- * Sets all file options.
- *
- * @param fileOptions
- * The file options
- */
- public void setFileOptions(Map<String, FileOption> fileOptions) {
- this.fileOptions.clear();
- this.fileOptions.putAll(fileOptions);
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Projects are compared by their name only.
- */
- public int compareTo(Project project) {
- return name.compareToIgnoreCase(project.name);
- }
-
- /**
- * Returns the edition of the project.
- *
- * @return The edition of the project
- */
- public int getEdition() {
- return edition;
- }
-
- /**
- * Sets the edition of the project.
- *
- * @param edition
- * The edition to set
- */
- public void setEdition(int edition) {
- this.edition = edition;
- }
-
- /**
- * Constructs the final request URI including the edition number.
- *
- * @param offset
- * The offset for the edition number
- * @return The final request URI
- */
- public String getFinalRequestURI(int offset) {
- return "USK@" + requestURI + "/" + path + "/" + (edition + offset) + "/";
- }
-
- /**
- * Performs some post-processing on the project after it was inserted
- * successfully. At the moment it copies the current hashes of all file
- * options to the last insert hashes, updating the hashes for the next
- * insert.
- */
- public void onSuccessfulInsert() {
- for (Entry<String, FileOption> fileOptionEntry : fileOptions.entrySet()) {
- FileOption fileOption = fileOptionEntry.getValue();
- if ((fileOption.getCurrentHash() != null) && (fileOption.getCurrentHash().length() > 0) && (!fileOption.getCurrentHash().equals(fileOption.getLastInsertHash()) || fileOption.isForceInsert())) {
- fileOption.setLastInsertEdition(edition);
- fileOption.setLastInsertHash(fileOption.getCurrentHash());
- fileOption.setLastInsertFilename(fileOption.hasChangedName() ? fileOption.getChangedName() : fileOptionEntry.getKey());
- }
- fileOption.setForceInsert(false);
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - ProjectInserter.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import de.todesbaum.jsite.gui.FileScanner;
-import de.todesbaum.jsite.gui.FileScanner.ScannedFile;
-import de.todesbaum.jsite.gui.FileScannerListener;
-import de.todesbaum.util.freenet.fcp2.Client;
-import de.todesbaum.util.freenet.fcp2.ClientPutComplexDir;
-import de.todesbaum.util.freenet.fcp2.ClientPutDir.ManifestPutter;
-import de.todesbaum.util.freenet.fcp2.Connection;
-import de.todesbaum.util.freenet.fcp2.DirectFileEntry;
-import de.todesbaum.util.freenet.fcp2.FileEntry;
-import de.todesbaum.util.freenet.fcp2.Message;
-import de.todesbaum.util.freenet.fcp2.PriorityClass;
-import de.todesbaum.util.freenet.fcp2.RedirectFileEntry;
-import de.todesbaum.util.freenet.fcp2.Verbosity;
-import de.todesbaum.util.io.StreamCopier.ProgressListener;
-
-/**
- * Manages project inserts.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class ProjectInserter implements FileScannerListener, Runnable {
-
- /** The logger. */
- private static final Logger logger = Logger.getLogger(ProjectInserter.class.getName());
-
- /** Random number for FCP instances. */
- private static final int random = (int) (Math.random() * Integer.MAX_VALUE);
-
- /** Counter for FCP connection identifier. */
- private static int counter = 0;
-
- /** The list of insert listeners. */
- private List<InsertListener> insertListeners = new ArrayList<InsertListener>();
-
- /** The freenet interface. */
- protected Freenet7Interface freenetInterface;
-
- /** The project to insert. */
- protected Project project;
-
- /** The file scanner. */
- private FileScanner fileScanner;
-
- /** Object used for synchronization. */
- protected final Object lockObject = new Object();
-
- /** The temp directory. */
- private String tempDirectory;
-
- /** The current connection. */
- private Connection connection;
-
- /** Whether the insert is cancelled. */
- private volatile boolean cancelled = false;
-
- /** Progress listener for payload transfers. */
- private ProgressListener progressListener;
-
- /** Whether to use “early encode.” */
- private boolean useEarlyEncode;
-
- /** The insert priority. */
- private PriorityClass priority;
-
- /** The manifest putter. */
- private ManifestPutter manifestPutter;
-
- /**
- * Adds a listener to the list of registered listeners.
- *
- * @param insertListener
- * The listener to add
- */
- public void addInsertListener(InsertListener insertListener) {
- insertListeners.add(insertListener);
- }
-
- /**
- * Removes a listener from the list of registered listeners.
- *
- * @param insertListener
- * The listener to remove
- */
- public void removeInsertListener(InsertListener insertListener) {
- insertListeners.remove(insertListener);
- }
-
- /**
- * Notifies all listeners that the project insert has started.
- *
- * @see InsertListener#projectInsertStarted(Project)
- */
- protected void fireProjectInsertStarted() {
- for (InsertListener insertListener : insertListeners) {
- insertListener.projectInsertStarted(project);
- }
- }
-
- /**
- * Notifies all listeners that the insert has generated a URI.
- *
- * @see InsertListener#projectURIGenerated(Project, String)
- * @param uri
- * The generated URI
- */
- protected void fireProjectURIGenerated(String uri) {
- for (InsertListener insertListener : insertListeners) {
- insertListener.projectURIGenerated(project, uri);
- }
- }
-
- /**
- * Notifies all listeners that the insert has made some progress.
- *
- * @see InsertListener#projectUploadFinished(Project)
- */
- protected void fireProjectUploadFinished() {
- for (InsertListener insertListener : insertListeners) {
- insertListener.projectUploadFinished(project);
- }
- }
-
- /**
- * Notifies all listeners that the insert has made some progress.
- *
- * @see InsertListener#projectInsertProgress(Project, int, int, int, int,
- * boolean)
- * @param succeeded
- * The number of succeeded blocks
- * @param failed
- * The number of failed blocks
- * @param fatal
- * The number of fatally failed blocks
- * @param total
- * The total number of blocks
- * @param finalized
- * <code>true</code> if the total number of blocks has already
- * been finalized, <code>false</code> otherwise
- */
- protected void fireProjectInsertProgress(int succeeded, int failed, int fatal, int total, boolean finalized) {
- for (InsertListener insertListener : insertListeners) {
- insertListener.projectInsertProgress(project, succeeded, failed, fatal, total, finalized);
- }
- }
-
- /**
- * Notifies all listeners the project insert has finished.
- *
- * @see InsertListener#projectInsertFinished(Project, boolean, Throwable)
- * @param success
- * <code>true</code> if the project was inserted successfully,
- * <code>false</code> if it failed
- * @param cause
- * The cause of the failure, if any
- */
- protected void fireProjectInsertFinished(boolean success, Throwable cause) {
- for (InsertListener insertListener : insertListeners) {
- insertListener.projectInsertFinished(project, success, cause);
- }
- }
-
- /**
- * Sets the project to insert.
- *
- * @param project
- * The project to insert
- */
- public void setProject(Project project) {
- this.project = project;
- }
-
- /**
- * Sets the freenet interface to use.
- *
- * @param freenetInterface
- * The freenet interface to use
- */
- public void setFreenetInterface(Freenet7Interface freenetInterface) {
- this.freenetInterface = freenetInterface;
- }
-
- /**
- * Sets the temp directory to use.
- *
- * @param tempDirectory
- * The temp directory to use, or {@code null} to use the system
- * default
- */
- public void setTempDirectory(String tempDirectory) {
- this.tempDirectory = tempDirectory;
- }
-
- /**
- * Sets whether to use the “early encode“ flag for the insert.
- *
- * @param useEarlyEncode
- * {@code true} to set the “early encode” flag for the insert,
- * {@code false} otherwise
- */
- public void setUseEarlyEncode(boolean useEarlyEncode) {
- this.useEarlyEncode = useEarlyEncode;
- }
-
- /**
- * Sets the insert priority.
- *
- * @param priority
- * The insert priority
- */
- public void setPriority(PriorityClass priority) {
- this.priority = priority;
- }
-
- /**
- * Sets the manifest putter to use for inserts.
- *
- * @param manifestPutter
- * The manifest putter to use
- */
- public void setManifestPutter(ManifestPutter manifestPutter) {
- this.manifestPutter = manifestPutter;
- }
-
- /**
- * Starts the insert.
- *
- * @param progressListener
- * Listener to notify on progress events
- */
- public void start(ProgressListener progressListener) {
- cancelled = false;
- this.progressListener = progressListener;
- fileScanner = new FileScanner(project);
- fileScanner.addFileScannerListener(this);
- new Thread(fileScanner).start();
- }
-
- /**
- * Stops the current insert.
- */
- public void stop() {
- cancelled = true;
- synchronized (lockObject) {
- if (connection != null) {
- connection.disconnect();
- }
- }
- }
-
- /**
- * Creates an input stream that delivers the given file, replacing edition
- * tokens in the file’s content, if necessary.
- *
- * @param filename
- * The name of the file
- * @param fileOption
- * The file options
- * @param edition
- * The current edition
- * @param length
- * An array containing a single long which is used to
- * <em>return</em> the final length of the file, after all
- * replacements
- * @return The input stream for the file
- * @throws IOException
- * if an I/O error occurs
- */
- private InputStream createFileInputStream(String filename, FileOption fileOption, int edition, long[] length) throws IOException {
- File file = new File(project.getLocalPath(), filename);
- length[0] = file.length();
- return new FileInputStream(file);
- }
-
- /**
- * Creates a file entry suitable for handing in to
- * {@link ClientPutComplexDir#addFileEntry(FileEntry)}.
- *
- * @param file
- * The name and hash of the file to insert
- * @param edition
- * The current edition
- * @return A file entry for the given file
- */
- private FileEntry createFileEntry(ScannedFile file, int edition) {
- FileEntry fileEntry = null;
- String filename = file.getFilename();
- FileOption fileOption = project.getFileOption(filename);
- if (fileOption.isInsert()) {
- fileOption.setCurrentHash(file.getHash());
- /* check if file was modified. */
- if (!fileOption.isForceInsert() && file.getHash().equals(fileOption.getLastInsertHash())) {
- /* only insert a redirect. */
- logger.log(Level.FINE, String.format("Inserting redirect to edition %d for %s.", fileOption.getLastInsertEdition(), filename));
- return new RedirectFileEntry(fileOption.hasChangedName() ? fileOption.getChangedName() : filename, fileOption.getMimeType(), "SSK@" + project.getRequestURI() + "/" + project.getPath() + "-" + fileOption.getLastInsertEdition() + "/" + fileOption.getLastInsertFilename());
- }
- try {
- long[] fileLength = new long[1];
- InputStream fileEntryInputStream = createFileInputStream(filename, fileOption, edition, fileLength);
- fileEntry = new DirectFileEntry(fileOption.hasChangedName() ? fileOption.getChangedName() : filename, fileOption.getMimeType(), fileEntryInputStream, fileLength[0]);
- } catch (IOException ioe1) {
- /* ignore, null is returned. */
- }
- } else {
- if (fileOption.isInsertRedirect()) {
- fileEntry = new RedirectFileEntry(fileOption.hasChangedName() ? fileOption.getChangedName() : filename, fileOption.getMimeType(), fileOption.getCustomKey());
- }
- }
- return fileEntry;
- }
-
- /**
- * 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) && (indexFile.length() > 0);
- 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 = fileOptionEntries.isEmpty();
- 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);
- }
- Set<String> fileNames = new HashSet<String>();
- for (Entry<String, FileOption> fileOptionEntry : fileOptionEntries) {
- FileOption fileOption = fileOptionEntry.getValue();
- if (!fileOption.isInsert() && !fileOption.isInsertRedirect()) {
- logger.log(Level.FINEST, "Ignoring {0}.", fileOptionEntry.getKey());
- continue;
- }
- String fileName = fileOptionEntry.getKey();
- if (fileOption.hasChangedName()) {
- fileName = fileOption.getChangedName();
- }
- logger.log(Level.FINEST, "Adding “{0}” for {1}.", new Object[] { fileName, fileOptionEntry.getKey() });
- if (!fileNames.add(fileName)) {
- checkReport.addIssue("error.duplicate-file", true, fileName);
- }
- }
- long totalSize = 0;
- FileScanner fileScanner = new FileScanner(project);
- final CountDownLatch completionLatch = new CountDownLatch(1);
- fileScanner.addFileScannerListener(new FileScannerListener() {
-
- @Override
- public void fileScannerFinished(FileScanner fileScanner) {
- completionLatch.countDown();
- }
- });
- new Thread(fileScanner).start();
- while (completionLatch.getCount() > 0) {
- try {
- completionLatch.await();
- } catch (InterruptedException ie1) {
- /* TODO: logging */
- }
- }
- for (ScannedFile scannedFile : fileScanner.getFiles()) {
- String fileName = scannedFile.getFilename();
- FileOption fileOption = project.getFileOption(fileName);
- if ((fileOption != null) && !fileOption.isInsert()) {
- continue;
- }
- totalSize += new File(project.getLocalPath(), fileName).length();
- }
- if (totalSize > 2 * 1024 * 1024) {
- checkReport.addIssue("warning.site-larger-than-2-mib", false);
- }
- return checkReport;
- }
-
- /**
- * {@inheritDoc}
- */
- public void run() {
- fireProjectInsertStarted();
- List<ScannedFile> files = fileScanner.getFiles();
-
- /* create connection to node */
- synchronized (lockObject) {
- connection = freenetInterface.getConnection("project-insert-" + random + counter++);
- }
- connection.setTempDirectory(tempDirectory);
- boolean connected = false;
- Throwable cause = null;
- try {
- connected = connection.connect();
- } catch (IOException e1) {
- cause = e1;
- }
-
- if (!connected || cancelled) {
- fireProjectInsertFinished(false, cancelled ? new AbortedException() : cause);
- return;
- }
-
- Client client = new Client(connection);
-
- /* collect files */
- int edition = project.getEdition();
- String dirURI = "USK@" + project.getInsertURI() + "/" + project.getPath() + "/" + edition + "/";
- ClientPutComplexDir putDir = new ClientPutComplexDir("dir-" + counter++, dirURI, tempDirectory);
- if ((project.getIndexFile() != null) && (project.getIndexFile().length() > 0)) {
- putDir.setDefaultName(project.getIndexFile());
- }
- putDir.setVerbosity(Verbosity.ALL);
- putDir.setMaxRetries(-1);
- putDir.setEarlyEncode(useEarlyEncode);
- putDir.setPriorityClass(priority);
- putDir.setManifestPutter(manifestPutter);
- for (ScannedFile file : files) {
- FileEntry fileEntry = createFileEntry(file, edition);
- if (fileEntry != null) {
- try {
- putDir.addFileEntry(fileEntry);
- } catch (IOException ioe1) {
- fireProjectInsertFinished(false, ioe1);
- return;
- }
- }
- }
-
- /* start request */
- try {
- client.execute(putDir, progressListener);
- fireProjectUploadFinished();
- } catch (IOException ioe1) {
- fireProjectInsertFinished(false, ioe1);
- return;
- }
-
- /* parse progress and success messages */
- String finalURI = null;
- boolean success = false;
- boolean finished = false;
- boolean disconnected = false;
- while (!finished && !cancelled) {
- Message message = client.readMessage();
- finished = (message == null) || (disconnected = client.isDisconnected());
- logger.log(Level.FINE, "Received message: " + message);
- if (!finished) {
- @SuppressWarnings("null")
- String messageName = message.getName();
- if ("URIGenerated".equals(messageName)) {
- finalURI = message.get("URI");
- fireProjectURIGenerated(finalURI);
- }
- if ("SimpleProgress".equals(messageName)) {
- int total = Integer.parseInt(message.get("Total"));
- int succeeded = Integer.parseInt(message.get("Succeeded"));
- int fatal = Integer.parseInt(message.get("FatallyFailed"));
- int failed = Integer.parseInt(message.get("Failed"));
- boolean finalized = Boolean.parseBoolean(message.get("FinalizedTotal"));
- fireProjectInsertProgress(succeeded, failed, fatal, total, finalized);
- }
- success |= "PutSuccessful".equals(messageName);
- finished = (success && (finalURI != null)) || "PutFailed".equals(messageName) || messageName.endsWith("Error");
- }
- }
-
- /* post-insert work */
- if (success) {
- @SuppressWarnings("null")
- String editionPart = finalURI.substring(finalURI.lastIndexOf('/') + 1);
- int newEdition = Integer.parseInt(editionPart);
- project.setEdition(newEdition);
- project.setLastInsertionTime(System.currentTimeMillis());
- project.onSuccessfulInsert();
- }
- fireProjectInsertFinished(success, cancelled ? new AbortedException() : (disconnected ? new IOException("Connection terminated") : null));
- }
-
- //
- // INTERFACE FileScannerListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void fileScannerFinished(FileScanner fileScanner) {
- if (!fileScanner.isError()) {
- new Thread(this).start();
- } else {
- fireProjectInsertFinished(false, null);
- }
- 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;
- }
-
- }
-
-}
+++ /dev/null
-/*
- * jSite - UpdateChecker.java - Copyright © 2008–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import de.todesbaum.jsite.main.Main;
-import de.todesbaum.jsite.main.Version;
-import de.todesbaum.util.freenet.fcp2.Client;
-import de.todesbaum.util.freenet.fcp2.ClientGet;
-import de.todesbaum.util.freenet.fcp2.Connection;
-import de.todesbaum.util.freenet.fcp2.Message;
-import de.todesbaum.util.freenet.fcp2.Persistence;
-import de.todesbaum.util.freenet.fcp2.ReturnType;
-import de.todesbaum.util.freenet.fcp2.Verbosity;
-import de.todesbaum.util.io.Closer;
-
-/**
- * Checks for newer versions of jSite.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class UpdateChecker implements Runnable {
-
- /** The logger. */
- private static final Logger logger = Logger.getLogger(UpdateChecker.class.getName());
-
- /** Counter for connection names. */
- private static int counter = 0;
-
- /** The edition for the update check URL. */
- private static final int UPDATE_EDITION = 17;
-
- /** The URL for update checks. */
- private static final String UPDATE_KEY = "USK@e3myoFyp5avg6WYN16ImHri6J7Nj8980Fm~aQe4EX1U,QvbWT0ImE0TwLODTl7EoJx2NBnwDxTbLTE6zkB-eGPs,AQACAAE";
-
- /** Object used for synchronization. */
- private final Object syncObject = new Object();
-
- /** Update listeners. */
- private final List<UpdateListener> updateListeners = new ArrayList<UpdateListener>();
-
- /** Whether the main thread should stop. */
- private boolean shouldStop = false;
-
- /** Current last found edition of update key. */
- private int lastUpdateEdition = UPDATE_EDITION;
-
- /** Last found version. */
- private Version lastVersion = Main.getVersion();
-
- /** The freenet interface. */
- private final Freenet7Interface freenetInterface;
-
- /**
- * Creates a new update checker that uses the given frame as its parent and
- * communications via the given freenet interface.
- *
- * @param freenetInterface
- * The freenet interface
- */
- public UpdateChecker(Freenet7Interface freenetInterface) {
- this.freenetInterface = freenetInterface;
- }
-
- //
- // EVENT LISTENER MANAGEMENT
- //
-
- /**
- * Adds an update listener to the list of registered listeners.
- *
- * @param updateListener
- * The update listener to add
- */
- public void addUpdateListener(UpdateListener updateListener) {
- updateListeners.add(updateListener);
- }
-
- /**
- * Removes the given listener from the list of registered listeners.
- *
- * @param updateListener
- * The update listener to remove
- */
- public void removeUpdateListener(UpdateListener updateListener) {
- updateListeners.remove(updateListener);
- }
-
- /**
- * Notifies all listeners that a version was found.
- *
- * @param foundVersion
- * The version that was found
- * @param versionTimestamp
- * The timestamp of the version
- */
- protected void fireUpdateFound(Version foundVersion, long versionTimestamp) {
- for (UpdateListener updateListener : updateListeners) {
- updateListener.foundUpdateData(foundVersion, versionTimestamp);
- }
- }
-
- //
- // ACCESSORS
- //
-
- /**
- * Returns the latest version that was found.
- *
- * @return The latest found version
- */
- public Version getLatestVersion() {
- return lastVersion;
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Starts the update checker.
- */
- public void start() {
- new Thread(this).start();
- }
-
- /**
- * Stops the update checker.
- */
- public void stop() {
- synchronized (syncObject) {
- shouldStop = true;
- syncObject.notifyAll();
- }
- }
-
- //
- // PRIVATE METHODS
- //
-
- /**
- * Returns whether the update checker should stop.
- *
- * @return <code>true</code> if the update checker should stop,
- * <code>false</code> otherwise
- */
- private boolean shouldStop() {
- synchronized (syncObject) {
- return shouldStop;
- }
- }
-
- /**
- * Creates the URI of the update file for the given edition.
- *
- * @param edition
- * The edition number
- * @return The URI for the update file for the given edition
- */
- private String constructUpdateKey(int edition) {
- return UPDATE_KEY + "/jSite/" + edition + "/jSite.properties";
- }
-
- //
- // INTERFACE Runnable
- //
-
- /**
- * {@inheritDoc}
- */
- public void run() {
- Connection connection = freenetInterface.getConnection("jSite-" + ++counter + "-UpdateChecker");
- try {
- connection.connect();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- Client client = new Client(connection);
- boolean checkNow = false;
- int currentEdition = lastUpdateEdition;
- while (!shouldStop()) {
- checkNow = false;
- logger.log(Level.FINE, "Trying " + constructUpdateKey(currentEdition));
- ClientGet clientGet = new ClientGet("get-update-key");
- clientGet.setUri(constructUpdateKey(currentEdition));
- clientGet.setPersistence(Persistence.CONNECTION);
- clientGet.setReturnType(ReturnType.direct);
- clientGet.setVerbosity(Verbosity.ALL);
- try {
- client.execute(clientGet);
- boolean stop = false;
- while (!stop) {
- Message message = client.readMessage();
- logger.log(Level.FINEST, "Received message: " + message);
- if (message == null) {
- break;
- }
- if ("GetFailed".equals(message.getName())) {
- if ("27".equals(message.get("code"))) {
- String editionString = message.get("redirecturi").split("/")[2];
- int editionNumber = -1;
- try {
- editionNumber = Integer.parseInt(editionString);
- } catch (NumberFormatException nfe1) {
- /* ignore. */
- }
- if (editionNumber != -1) {
- logger.log(Level.INFO, "Found new edition " + editionNumber);
- currentEdition = editionNumber;
- lastUpdateEdition = editionNumber;
- checkNow = true;
- break;
- }
- }
- }
- if ("AllData".equals(message.getName())) {
- logger.log(Level.FINE, "Update data found.");
- InputStream dataInputStream = null;
- Properties properties = new Properties();
- try {
- dataInputStream = message.getPayloadInputStream();
- properties.load(dataInputStream);
- } finally {
- Closer.close(dataInputStream);
- }
-
- String foundVersionString = properties.getProperty("jSite.Version");
- if (foundVersionString != null) {
- Version foundVersion = Version.parse(foundVersionString);
- if (foundVersion != null) {
- lastVersion = foundVersion;
- String versionTimestampString = properties.getProperty("jSite.Date");
- logger.log(Level.FINEST, "Version timestamp: " + versionTimestampString);
- long versionTimestamp = -1;
- try {
- versionTimestamp = Long.parseLong(versionTimestampString);
- } catch (NumberFormatException nfe1) {
- /* ignore. */
- }
- fireUpdateFound(foundVersion, versionTimestamp);
- stop = true;
- checkNow = true;
- ++currentEdition;
- }
- }
- }
- }
- } catch (IOException e) {
- logger.log(Level.INFO, "Got IOException: " + e.getMessage());
- e.printStackTrace();
- }
- if (!checkNow && !shouldStop()) {
- synchronized (syncObject) {
- try {
- syncObject.wait(15 * 60 * 1000);
- } catch (InterruptedException ie1) {
- /* ignore. */
- }
- }
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - UpdateListener.java - Copyright © 2008–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.application;
-
-import java.util.EventListener;
-
-import de.todesbaum.jsite.main.Version;
-
-/**
- * Listener interface for objects that want to be notified when update data was
- * found.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public interface UpdateListener extends EventListener {
-
- /**
- * Notifies a listener that data for the given version was found.
- *
- * @param foundVersion
- * The version that was found
- * @param versionTimestamp
- * The timestamp of the version, or <code>-1</code> if the
- * timestamp is unknown
- */
- public void foundUpdateData(Version foundVersion, long versionTimestamp);
-
-}
+++ /dev/null
-/*
- * jSite - FileScanner.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.DigestOutputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import de.todesbaum.jsite.application.Project;
-import de.todesbaum.jsite.i18n.I18n;
-import de.todesbaum.util.io.Closer;
-import de.todesbaum.util.io.StreamCopier;
-
-/**
- * Scans the local path of a project anychronously and returns the list of found
- * files as an event.
- *
- * @see Project#getLocalPath()
- * @see FileScannerListener#fileScannerFinished(FileScanner)
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class FileScanner implements Runnable {
-
- /** The logger. */
- private final static Logger logger = Logger.getLogger(FileScanner.class.getName());
-
- /** The list of listeners. */
- private final List<FileScannerListener> fileScannerListeners = new ArrayList<FileScannerListener>();
-
- /** The project to scan. */
- private final Project project;
-
- /** The list of found files. */
- private List<ScannedFile> files;
-
- /** Wether there was an error. */
- private boolean error = false;
-
- /**
- * Creates a new file scanner for the given project.
- *
- * @param project
- * The project whose files to scan
- */
- public FileScanner(Project project) {
- this.project = project;
- }
-
- /**
- * Adds the given listener to the list of listeners.
- *
- * @param fileScannerListener
- * The listener to add
- */
- public void addFileScannerListener(FileScannerListener fileScannerListener) {
- fileScannerListeners.add(fileScannerListener);
- }
-
- /**
- * Removes the given listener from the list of listeners.
- *
- * @param fileScannerListener
- * The listener to remove
- */
- public void removeFileScannerListener(FileScannerListener fileScannerListener) {
- fileScannerListeners.remove(fileScannerListener);
- }
-
- /**
- * Notifies all listeners that the file scan finished.
- */
- protected void fireFileScannerFinished() {
- for (FileScannerListener fileScannerListener : new ArrayList<FileScannerListener>(fileScannerListeners)) {
- fileScannerListener.fileScannerFinished(this);
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Scans all available files in the project’s local path and emits an event
- * when finished.
- *
- * @see FileScannerListener#fileScannerFinished(FileScanner)
- */
- public void run() {
- files = new ArrayList<ScannedFile>();
- error = false;
- try {
- scanFiles(new File(project.getLocalPath()), files);
- Collections.sort(files);
- } catch (IOException ioe1) {
- error = true;
- }
- fireFileScannerFinished();
- }
-
- /**
- * Returns whether there was an error scanning for files.
- *
- * @return <code>true</code> if there was an error, <code>false</code>
- * otherwise
- */
- public boolean isError() {
- return error;
- }
-
- /**
- * Returns the list of found files.
- *
- * @return The list of found files
- */
- public List<ScannedFile> getFiles() {
- return files;
- }
-
- /**
- * Recursively scans a directory and adds all found files to the given list.
- *
- * @param rootDir
- * The directory to scan
- * @param fileList
- * The list to which to add the found files
- * @throws IOException
- * if an I/O error occurs
- */
- private void scanFiles(File rootDir, List<ScannedFile> fileList) throws IOException {
- File[] files = rootDir.listFiles(new FileFilter() {
-
- @SuppressWarnings("synthetic-access")
- public boolean accept(File file) {
- return !project.isIgnoreHiddenFiles() || !file.isHidden();
- }
- });
- if (files == null) {
- throw new IOException(I18n.getMessage("jsite.file-scanner.can-not-read-directory"));
- }
- for (File file : files) {
- if (file.isDirectory()) {
- scanFiles(file, fileList);
- continue;
- }
- String filename = project.shortenFilename(file).replace('\\', '/');
- String hash = hashFile(project.getLocalPath(), filename);
- fileList.add(new ScannedFile(filename, hash));
- }
- }
-
- /**
- * Hashes the given file.
- *
- * @param path
- * The path of the project
- * @param filename
- * The name of the file, relative to the project path
- * @return The hash of the file
- */
- @SuppressWarnings("synthetic-access")
- private static String hashFile(String path, String filename) {
- InputStream fileInputStream = null;
- DigestOutputStream digestOutputStream = null;
- File file = new File(path, filename);
- try {
- fileInputStream = new FileInputStream(file);
- digestOutputStream = new DigestOutputStream(new NullOutputStream(), MessageDigest.getInstance("SHA-256"));
- StreamCopier.copy(fileInputStream, digestOutputStream, file.length());
- return toHex(digestOutputStream.getMessageDigest().digest());
- } catch (NoSuchAlgorithmException nsae1) {
- logger.log(Level.WARNING, "Could not get SHA-256 digest!", nsae1);
- } catch (IOException ioe1) {
- logger.log(Level.WARNING, "Could not read file!", ioe1);
- } finally {
- Closer.close(digestOutputStream);
- Closer.close(fileInputStream);
- }
- return toHex(new byte[32]);
- }
-
- /**
- * Converts the given byte array into a hexadecimal string.
- *
- * @param array
- * The array to convert
- * @return The hexadecimal string
- */
- private static String toHex(byte[] array) {
- StringBuilder hexString = new StringBuilder(array.length * 2);
- for (byte b : array) {
- hexString.append("0123456789abcdef".charAt((b >>> 4) & 0x0f)).append("0123456789abcdef".charAt(b & 0xf));
- }
- return hexString.toString();
- }
-
- /**
- * {@link OutputStream} that discards all written bytes.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
- private static class NullOutputStream extends OutputStream {
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(int b) {
- /* do nothing. */
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(byte[] b) {
- /* do nothing. */
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(byte[] b, int off, int len) {
- /* do nothing. */
- }
-
- }
-
- /**
- * Container for a scanned file, consisting of the name of the file and its
- * hash.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
- public static class ScannedFile implements Comparable<ScannedFile> {
-
- /** The name of the file. */
- private final String filename;
-
- /** The hash of the file. */
- private final String hash;
-
- /**
- * Creates a new scanned file.
- *
- * @param filename
- * The name of the file
- * @param hash
- * The hash of the file
- */
- public ScannedFile(String filename, String hash) {
- this.filename = filename;
- this.hash = hash;
- }
-
- //
- // ACCESSORS
- //
-
- /**
- * Returns the name of the file.
- *
- * @return The name of the file
- */
- public String getFilename() {
- return filename;
- }
-
- /**
- * Returns the hash of the file.
- *
- * @return The hash of the file
- */
- public String getHash() {
- return hash;
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return filename.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object obj) {
- return filename.equals(obj);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return filename;
- }
-
- //
- // COMPARABLE METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- public int compareTo(ScannedFile scannedFile) {
- return filename.compareTo(scannedFile.filename);
- }
-
- }
-
-}
+++ /dev/null
-/*
- * jSite - FileScannerListener.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.util.EventListener;
-
-/**
- * Listener interface for objects that want to be notified when scanning a
- * project’s local path has finished.
- *
- * @see FileScanner
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public interface FileScannerListener extends EventListener {
-
- /**
- * Notifies a listener that scanning a project’s local path has finished.
- *
- * @param fileScanner
- * The file scanner that finished
- */
- public void fileScannerFinished(FileScanner fileScanner);
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * jSite - NodeManagerListener.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.util.EventListener;
-
-import de.todesbaum.jsite.application.Node;
-
-/**
- * Listener interface for objects that want to be notified if the node
- * configuration changes.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public interface NodeManagerListener extends EventListener {
-
- /**
- * Notifies a listener that the node configuration was changed.
- *
- * @param nodes
- * The new list of nodes
- */
- public void nodesUpdated(Node[] nodes);
-
- /**
- * Notifies a listener that the selected node has changed.
- *
- * @param node
- * The new selected node
- */
- public void nodeSelected(Node node);
-
-}
+++ /dev/null
-/*
- * jSite - NodeManagerPage.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSpinner;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.SpinnerNumberModel;
-import javax.swing.border.EmptyBorder;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-
-import de.todesbaum.jsite.application.Node;
-import de.todesbaum.jsite.i18n.I18n;
-import de.todesbaum.jsite.i18n.I18nContainer;
-import de.todesbaum.util.swing.TLabel;
-import de.todesbaum.util.swing.TWizard;
-import de.todesbaum.util.swing.TWizardPage;
-
-/**
- * Wizard page that lets the user edit his nodes.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class NodeManagerPage extends TWizardPage implements ListSelectionListener, DocumentListener, ChangeListener {
-
- /** List of node manager listeners. */
- private List<NodeManagerListener> nodeManagerListeners = new ArrayList<NodeManagerListener>();
-
- /** The “add node” action. */
- protected Action addNodeAction;
-
- /** The “delete node” action. */
- protected Action deleteNodeAction;
-
- /** The node list model. */
- private DefaultListModel nodeListModel;
-
- /** The node list. */
- private JList nodeList;
-
- /** The node name textfield. */
- private JTextField nodeNameTextField;
-
- /** The node hostname textfield. */
- private JTextField nodeHostnameTextField;
-
- /** The spinner for the node port. */
- private JSpinner nodePortSpinner;
-
- /**
- * Creates a new node manager wizard page.
- *
- * @param wizard
- * The wizard this page belongs to
- */
- public NodeManagerPage(final TWizard wizard) {
- super(wizard);
- pageInit();
- setHeading(I18n.getMessage("jsite.node-manager.heading"));
- setDescription(I18n.getMessage("jsite.node-manager.description"));
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- setHeading(I18n.getMessage("jsite.node-manager.heading"));
- setDescription(I18n.getMessage("jsite.node-manager.description"));
- }
- });
- }
-
- /**
- * Adds a listener for node manager events.
- *
- * @param nodeManagerListener
- * The listener to add
- */
- public void addNodeManagerListener(NodeManagerListener nodeManagerListener) {
- nodeManagerListeners.add(nodeManagerListener);
- }
-
- /**
- * Removes a listener for node manager events.
- *
- * @param nodeManagerListener
- * The listener to remove
- */
- public void removeNodeManagerListener(NodeManagerListener nodeManagerListener) {
- nodeManagerListeners.remove(nodeManagerListener);
- }
-
- /**
- * Notifies all listeners that the node configuration has changed.
- *
- * @param nodes
- * The new list of nodes
- */
- protected void fireNodesUpdated(Node[] nodes) {
- for (NodeManagerListener nodeManagerListener : nodeManagerListeners) {
- nodeManagerListener.nodesUpdated(nodes);
- }
- }
-
- /**
- * Notifies all listeners that a new node was selected.
- *
- * @param node
- * The newly selected node
- */
- protected void fireNodeSelected(Node node) {
- for (NodeManagerListener nodeManagerListener : nodeManagerListeners) {
- nodeManagerListener.nodeSelected(node);
- }
- }
-
- /**
- * Creates all actions.
- */
- private void createActions() {
- addNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.add-node")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- addNode();
- }
- };
-
- deleteNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.delete-node")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- deleteNode();
- }
- };
- deleteNodeAction.setEnabled(false);
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- addNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.node-manager.add-node"));
- deleteNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.node-manager.delete-node"));
- }
- });
- }
-
- /**
- * Initializes the page and all components in it.
- */
- private void pageInit() {
- createActions();
- nodeListModel = new DefaultListModel();
- nodeList = new JList(nodeListModel);
- nodeList.setName("node-list");
- nodeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- nodeList.addListSelectionListener(this);
- nodeList.setPreferredSize(new Dimension(250, -1));
-
- nodeNameTextField = new JTextField("");
- nodeNameTextField.getDocument().putProperty("Name", "node-name");
- nodeNameTextField.getDocument().addDocumentListener(this);
- nodeNameTextField.setEnabled(false);
-
- nodeHostnameTextField = new JTextField("localhost");
- nodeHostnameTextField.getDocument().putProperty("Name", "node-hostname");
- nodeHostnameTextField.getDocument().addDocumentListener(this);
- nodeHostnameTextField.setEnabled(false);
-
- nodePortSpinner = new JSpinner(new SpinnerNumberModel(9481, 1, 65535, 1));
- nodePortSpinner.setName("node-port");
- nodePortSpinner.addChangeListener(this);
- nodePortSpinner.setEnabled(false);
-
- JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
- buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12));
- buttonPanel.add(new JButton(addNodeAction));
- buttonPanel.add(new JButton(deleteNodeAction));
-
- JPanel centerPanel = new JPanel(new BorderLayout());
- JPanel nodeInformationPanel = new JPanel(new GridBagLayout());
- centerPanel.add(nodeInformationPanel, BorderLayout.PAGE_START);
- nodeInformationPanel.add(buttonPanel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
- final JLabel nodeInformationLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.node-manager.node-information") + "</b></html>");
- nodeInformationPanel.add(nodeInformationLabel, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
- final TLabel nodeNameLabel = new TLabel(I18n.getMessage("jsite.node-manager.name") + ":", KeyEvent.VK_N, nodeNameTextField);
- nodeInformationPanel.add(nodeNameLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- nodeInformationPanel.add(nodeNameTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- final TLabel nodeHostnameLabel = new TLabel(I18n.getMessage("jsite.node-manager.hostname") + ":", KeyEvent.VK_H, nodeHostnameTextField);
- nodeInformationPanel.add(nodeHostnameLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- nodeInformationPanel.add(nodeHostnameTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- final TLabel nodePortLabel = new TLabel(I18n.getMessage("jsite.node-manager.port") + ":", KeyEvent.VK_P, nodePortSpinner);
- nodeInformationPanel.add(nodePortLabel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- nodeInformationPanel.add(nodePortSpinner, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0));
-
- setLayout(new BorderLayout(12, 12));
- add(new JScrollPane(nodeList), BorderLayout.LINE_START);
- add(centerPanel, BorderLayout.CENTER);
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- nodeInformationLabel.setText("<html><b>" + I18n.getMessage("jsite.node-manager.node-information") + "</b></html>");
- nodeNameLabel.setText(I18n.getMessage("jsite.node-manager.name") + ":");
- nodeHostnameLabel.setText(I18n.getMessage("jsite.node-manager.hostname") + ":");
- nodePortLabel.setText(I18n.getMessage("jsite.node-manager.port") + ":");
- }
- });
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void pageAdded(TWizard wizard) {
- this.wizard.setNextEnabled(nodeListModel.getSize() > 0);
- this.wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
- this.wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
- this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
- }
-
- /**
- * Sets the node list.
- *
- * @param nodes
- * The list of nodes
- */
- public void setNodes(Node[] nodes) {
- nodeListModel.clear();
- for (Node node : nodes) {
- nodeListModel.addElement(node);
- }
- nodeList.repaint();
- fireNodesUpdated(nodes);
- }
-
- /**
- * Returns the node list.
- *
- * @return The list of nodes
- */
- public Node[] getNodes() {
- Node[] returnNodes = new Node[nodeListModel.getSize()];
- for (int nodeIndex = 0, nodeCount = nodeListModel.getSize(); nodeIndex < nodeCount; nodeIndex++) {
- returnNodes[nodeIndex] = (Node) nodeListModel.get(nodeIndex);
- }
- return returnNodes;
- }
-
- /**
- * Returns the currently selected node.
- *
- * @return The selected node, or <code>null</code> if no node is selected
- */
- private Node getSelectedNode() {
- return (Node) nodeList.getSelectedValue();
- }
-
- /**
- * Updates node name or hostname when the user types into the textfields.
- *
- * @see #insertUpdate(DocumentEvent)
- * @see #removeUpdate(DocumentEvent)
- * @see #changedUpdate(DocumentEvent)
- * @see DocumentListener
- * @param documentEvent
- * The document event
- */
- private void updateTextField(DocumentEvent documentEvent) {
- Node node = getSelectedNode();
- if (node == null) {
- return;
- }
- Document document = documentEvent.getDocument();
- String documentText = null;
- try {
- documentText = document.getText(0, document.getLength());
- } catch (BadLocationException ble1) {
- /* ignore. */
- }
- if (documentText == null) {
- return;
- }
- String documentName = (String) document.getProperty("Name");
- if ("node-name".equals(documentName)) {
- node.setName(documentText);
- nodeList.repaint();
- fireNodesUpdated(getNodes());
- } else if ("node-hostname".equals(documentName)) {
- node.setHostname(documentText);
- nodeList.repaint();
- fireNodesUpdated(getNodes());
- }
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Adds a new node to the list of nodes.
- */
- private void addNode() {
- Node node = new Node("localhost", 9481, I18n.getMessage("jsite.node-manager.new-node"));
- nodeListModel.addElement(node);
- deleteNodeAction.setEnabled(nodeListModel.size() > 1);
- wizard.setNextEnabled(true);
- fireNodesUpdated(getNodes());
- }
-
- /**
- * Deletes the currently selected node from the list of nodes.
- */
- private void deleteNode() {
- Node node = getSelectedNode();
- if (node == null) {
- return;
- }
- if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.node-manager.delete-node.warning"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) {
- return;
- }
- int nodeIndex = nodeListModel.indexOf(node);
- nodeListModel.removeElement(node);
- nodeList.repaint();
- fireNodeSelected((Node) nodeListModel.get(Math.min(nodeIndex, nodeListModel.size() - 1)));
- fireNodesUpdated(getNodes());
- deleteNodeAction.setEnabled(nodeListModel.size() > 1);
- wizard.setNextEnabled(nodeListModel.size() > 0);
- }
-
- //
- // INTERFACE ListSelectionListener
- //
-
- /**
- * {@inheritDoc}
- */
- @SuppressWarnings("null")
- public void valueChanged(ListSelectionEvent e) {
- Object source = e.getSource();
- if (source instanceof JList) {
- JList sourceList = (JList) source;
- if ("node-list".equals(sourceList.getName())) {
- Node node = (Node) sourceList.getSelectedValue();
- boolean enabled = (node != null);
- nodeNameTextField.setEnabled(enabled);
- nodeHostnameTextField.setEnabled(enabled);
- nodePortSpinner.setEnabled(enabled);
- deleteNodeAction.setEnabled(enabled && (nodeListModel.size() > 1));
- if (enabled) {
- nodeNameTextField.setText(node.getName());
- nodeHostnameTextField.setText(node.getHostname());
- nodePortSpinner.setValue(node.getPort());
- } else {
- nodeNameTextField.setText("");
- nodeHostnameTextField.setText("localhost");
- nodePortSpinner.setValue(9481);
- }
- }
- }
- }
-
- //
- // INTERFACE DocumentListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void insertUpdate(DocumentEvent e) {
- updateTextField(e);
- }
-
- /**
- * {@inheritDoc}
- */
- public void removeUpdate(DocumentEvent e) {
- updateTextField(e);
- }
-
- /**
- * {@inheritDoc}
- */
- public void changedUpdate(DocumentEvent e) {
- updateTextField(e);
- }
-
- //
- // INTERFACE ChangeListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void stateChanged(ChangeEvent e) {
- Object source = e.getSource();
- Node selectedNode = getSelectedNode();
- if (selectedNode == null) {
- return;
- }
- if (source instanceof JSpinner) {
- JSpinner sourceSpinner = (JSpinner) source;
- if ("node-port".equals(sourceSpinner.getName())) {
- selectedNode.setPort((Integer) sourceSpinner.getValue());
- fireNodeSelected(selectedNode);
- nodeList.repaint();
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - PreferencesPage.java - Copyright © 2009–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.awt.BorderLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JTextField;
-
-import de.todesbaum.jsite.i18n.I18n;
-import de.todesbaum.jsite.i18n.I18nContainer;
-import de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation;
-import de.todesbaum.util.freenet.fcp2.ClientPutDir.ManifestPutter;
-import de.todesbaum.util.freenet.fcp2.PriorityClass;
-import de.todesbaum.util.swing.TWizard;
-import de.todesbaum.util.swing.TWizardPage;
-
-/**
- * Page that shows some preferences that are valid for the complete application.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class PreferencesPage extends TWizardPage {
-
- /** Select default temp directory action. */
- private Action selectDefaultTempDirectoryAction;
-
- /** Select custom temp directory action. */
- private Action selectCustomTempDirectoryAction;
-
- /** Action that chooses a new temp directory. */
- private Action chooseTempDirectoryAction;
-
- /** Action when selecting “next to JAR file.” */
- private Action nextToJarFileAction;
-
- /** Action when selecting “home directory.” */
- private Action homeDirectoryAction;
-
- /** Action when selecting “custom directory.” */
- private Action customDirectoryAction;
-
- /** Action when selecting “use early encode.” */
- private Action useEarlyEncodeAction;
-
- /** Action when a priority was selected. */
- private Action priorityAction;
-
- /** The text field containing the directory. */
- private JTextField tempDirectoryTextField;
-
- /** The temp directory. */
- private String tempDirectory;
-
- /** The configuration location. */
- private ConfigurationLocation configurationLocation;
-
- /** Whether to use “early encode.” */
- private boolean useEarlyEncode;
-
- /** The prioriy for inserts. */
- private PriorityClass priority;
-
- /** The “default” button. */
- private JRadioButton defaultTempDirectory;
-
- /** The “custom” button. */
- private JRadioButton customTempDirectory;
-
- /** The “next to JAR file” checkbox. */
- private JRadioButton nextToJarFile;
-
- /** The “home directory” checkbox. */
- private JRadioButton homeDirectory;
-
- /** The “custom directory” checkbox. */
- private JRadioButton customDirectory;
-
- /** The “use early encode” checkbox. */
- private JCheckBox useEarlyEncodeCheckBox;
-
- /** The insert priority select box. */
- private JComboBox insertPriorityComboBox;
-
- /** The manifest putter select box. */
- private JComboBox manifestPutterComboBox;
-
- /**
- * Creates a new “preferences” page.
- *
- * @param wizard
- * The wizard this page belongs to
- */
- public PreferencesPage(TWizard wizard) {
- super(wizard);
- pageInit();
- setHeading(I18n.getMessage("jsite.preferences.heading"));
- setDescription(I18n.getMessage("jsite.preferences.description"));
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- /**
- * {@inheritDoc}
- */
- public void run() {
- setHeading(I18n.getMessage("jsite.preferences.heading"));
- setDescription(I18n.getMessage("jsite.preferences.description"));
- }
- });
- }
-
- //
- // ACCESSORS
- //
-
- /**
- * Returns the temp directory.
- *
- * @return The temp directory, or {@code null} to use the default temp
- * directory
- */
- public String getTempDirectory() {
- return tempDirectory;
- }
-
- /**
- * Sets the temp directory.
- *
- * @param tempDirectory
- * The temp directory, or {@code null} to use the default temp
- * directory
- */
- public void setTempDirectory(String tempDirectory) {
- this.tempDirectory = tempDirectory;
- tempDirectoryTextField.setText((tempDirectory != null) ? tempDirectory : "");
- if (tempDirectory != null) {
- customTempDirectory.setSelected(true);
- chooseTempDirectoryAction.setEnabled(true);
- } else {
- defaultTempDirectory.setSelected(true);
- }
- }
-
- /**
- * Returns the configuration location.
- *
- * @return The configuration location
- */
- public ConfigurationLocation getConfigurationLocation() {
- return configurationLocation;
- }
-
- /**
- * Sets the configuration location.
- *
- * @param configurationLocation
- * The configuration location
- */
- 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);
- }
-
- /**
- * Returns whether to use the “early encode“ flag for the insert.
- *
- * @return {@code true} to set the “early encode” flag for the insert,
- * {@code false} otherwise
- */
- public boolean useEarlyEncode() {
- return useEarlyEncode;
- }
-
- /**
- * Sets whether to use the “early encode“ flag for the insert.
- *
- * @param useEarlyEncode
- * {@code true} to set the “early encode” flag for the insert,
- * {@code false} otherwise
- */
- public void setUseEarlyEncode(boolean useEarlyEncode) {
- useEarlyEncodeCheckBox.setSelected(useEarlyEncode);
- }
-
- /**
- * Returns the configured insert priority.
- *
- * @return The insert priority
- */
- public PriorityClass getPriority() {
- return priority;
- }
-
- /**
- * Sets the insert priority.
- *
- * @param priority
- * The insert priority
- */
- public void setPriority(PriorityClass priority) {
- insertPriorityComboBox.setSelectedItem(priority);
- }
-
- /**
- * Returns the selected manifest putter.
- *
- * @return The selected manifest putter
- */
- public ManifestPutter getManifestPutter() {
- return (ManifestPutter) manifestPutterComboBox.getSelectedItem();
- }
-
- /**
- * Sets the manifest putter.
- *
- * @param manifestPutter
- * The manifest putter
- */
- public void setManifestPutter(ManifestPutter manifestPutter) {
- manifestPutterComboBox.setSelectedItem(manifestPutter);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void pageAdded(TWizard wizard) {
- super.pageAdded(wizard);
- this.wizard.setPreviousName(I18n.getMessage("jsite.menu.nodes.manage-nodes"));
- this.wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
- this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
- this.wizard.setNextEnabled(false);
- }
-
- //
- // PRIVATE METHODS
- //
-
- /**
- * Initializes this page.
- */
- private void pageInit() {
- createActions();
- setLayout(new BorderLayout(12, 12));
- add(createPreferencesPanel(), BorderLayout.CENTER);
- }
-
- /**
- * Creates all actions.
- */
- private void createActions() {
- selectDefaultTempDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.temp-directory.default")) {
-
- /**
- * {@inheritDoc}
- */
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- selectDefaultTempDirectory();
- }
- };
- selectCustomTempDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.temp-directory.custom")) {
-
- /**
- * {@inheritDoc}
- */
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- selectCustomTempDirectory();
- }
- };
- chooseTempDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.temp-directory.choose")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent e) {
- chooseTempDirectory();
- }
- };
- nextToJarFileAction = new AbstractAction(I18n.getMessage("jsite.preferences.config-directory.jar")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionevent) {
- configurationLocation = ConfigurationLocation.NEXT_TO_JAR_FILE;
- }
- };
- homeDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.config-directory.home")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionevent) {
- 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;
- }
- };
- useEarlyEncodeAction = new AbstractAction(I18n.getMessage("jsite.preferences.insert-options.use-early-encode")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- useEarlyEncode = useEarlyEncodeCheckBox.isSelected();
- }
- };
- priorityAction = new AbstractAction(I18n.getMessage("jsite.preferences.insert-options.priority")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- priority = (PriorityClass) insertPriorityComboBox.getSelectedItem();
- }
- };
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- selectDefaultTempDirectoryAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.temp-directory.default"));
- selectCustomTempDirectoryAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.temp-directory.custom"));
- 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"));
- useEarlyEncodeAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.insert-options.use-early-encode"));
- }
- });
- }
-
- /**
- * Creates the panel containing all preferences.
- *
- * @return The preferences panel
- */
- private JPanel createPreferencesPanel() {
- JPanel preferencesPanel = new JPanel(new GridBagLayout());
- preferencesPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
-
- final JLabel tempDirectoryLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.preferences.temp-directory") + "</b></html>");
- preferencesPanel.add(tempDirectoryLabel, new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
-
- defaultTempDirectory = new JRadioButton(selectDefaultTempDirectoryAction);
- preferencesPanel.add(defaultTempDirectory, new GridBagConstraints(0, 1, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 18, 0, 0), 0, 0));
-
- customTempDirectory = new JRadioButton(selectCustomTempDirectoryAction);
- preferencesPanel.add(customTempDirectory, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 18, 0, 0), 0, 0));
-
- ButtonGroup tempDirectoryButtonGroup = new ButtonGroup();
- defaultTempDirectory.getModel().setGroup(tempDirectoryButtonGroup);
- customTempDirectory.getModel().setGroup(tempDirectoryButtonGroup);
-
- tempDirectoryTextField = new JTextField();
- tempDirectoryTextField.setEditable(false);
- if (tempDirectory != null) {
- tempDirectoryTextField.setText(tempDirectory);
- customTempDirectory.setSelected(true);
- } else {
- defaultTempDirectory.setSelected(true);
- }
- chooseTempDirectoryAction.setEnabled(tempDirectory != null);
- preferencesPanel.add(tempDirectoryTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 6, 0, 0), 0, 0));
-
- JButton chooseButton = new JButton(chooseTempDirectoryAction);
- preferencesPanel.add(chooseButton, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.BOTH, new Insets(0, 6, 0, 0), 0, 0));
-
- final JLabel configurationDirectoryLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.preferences.config-directory") + "</b></html>");
- preferencesPanel.add(configurationDirectoryLabel, new GridBagConstraints(0, 3, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 0, 0, 0), 0, 0));
-
- nextToJarFile = new JRadioButton(nextToJarFileAction);
- preferencesPanel.add(nextToJarFile, new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 18, 0, 0), 0, 0));
-
- 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(homeDirectory);
- configurationDirectoryButtonGroup.add(customDirectory);
-
- final JLabel insertOptionsLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.preferences.insert-options") + "</b></html>");
- preferencesPanel.add(insertOptionsLabel, new GridBagConstraints(0, 7, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
-
- useEarlyEncodeCheckBox = new JCheckBox(useEarlyEncodeAction);
- preferencesPanel.add(useEarlyEncodeCheckBox, new GridBagConstraints(0, 8, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
-
- final JLabel insertPriorityLabel = new JLabel(I18n.getMessage("jsite.preferences.insert-options.priority"));
- preferencesPanel.add(insertPriorityLabel, new GridBagConstraints(0, 9, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
-
- insertPriorityComboBox = new JComboBox(new PriorityClass[] { PriorityClass.MINIMUM, PriorityClass.PREFETCH, PriorityClass.BULK, PriorityClass.UPDATABLE, PriorityClass.SEMI_INTERACTIVE, PriorityClass.INTERACTIVE, PriorityClass.MAXIMUM });
- insertPriorityComboBox.setAction(priorityAction);
- preferencesPanel.add(insertPriorityComboBox, new GridBagConstraints(1, 9, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 18, 0, 0), 0, 0));
-
- final JLabel manifestPutterLabel = new JLabel(I18n.getMessage("jsite.preferences.insert-options.manifest-putter"));
- preferencesPanel.add(manifestPutterLabel, new GridBagConstraints(0, 10, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
-
- manifestPutterComboBox = new JComboBox(ManifestPutter.values());
- preferencesPanel.add(manifestPutterComboBox, new GridBagConstraints(1, 10, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 18, 0, 0), 0, 0));
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- /**
- * {@inheritDoc}
- */
- public void run() {
- tempDirectoryLabel.setText("<html><b>" + I18n.getMessage("jsite.preferences.temp-directory") + "</b></html>");
- configurationDirectoryLabel.setText("<html><b>" + I18n.getMessage("jsite.preferences.config-directory") + "</b></html>");
- insertOptionsLabel.setText("<html><b>" + I18n.getMessage("jsite.preferences.insert-options") + "</b></html>");
- insertPriorityLabel.setText(I18n.getMessage("jsite.preferences.insert-options.priority"));
- manifestPutterLabel.setText(I18n.getMessage("jsite.preferences.insert-options.manifest-putter"));
- }
- });
-
- return preferencesPanel;
- }
-
- /**
- * Activates the default temp directory radio button.
- */
- private void selectDefaultTempDirectory() {
- tempDirectoryTextField.setEnabled(false);
- chooseTempDirectoryAction.setEnabled(false);
- tempDirectory = null;
- }
-
- /**
- * Activates the custom temp directory radio button.
- */
- private void selectCustomTempDirectory() {
- tempDirectoryTextField.setEnabled(true);
- chooseTempDirectoryAction.setEnabled(true);
- if (tempDirectoryTextField.getText().length() == 0) {
- chooseTempDirectory();
- if (tempDirectoryTextField.getText().length() == 0) {
- defaultTempDirectory.setSelected(true);
- }
- }
- }
-
- /**
- * Lets the user choose a new temp directory.
- */
- private void chooseTempDirectory() {
- JFileChooser fileChooser = new JFileChooser(tempDirectory);
- fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- int returnValue = fileChooser.showDialog(wizard, I18n.getMessage("jsite.preferences.temp-directory.choose.approve"));
- if (returnValue == JFileChooser.CANCEL_OPTION) {
- return;
- }
- tempDirectory = fileChooser.getSelectedFile().getPath();
- tempDirectoryTextField.setText(tempDirectory);
- }
-
-}
+++ /dev/null
-/*
- * jSite - ProjectFilesPage.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.text.MessageFormat;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.SwingUtilities;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-
-import de.todesbaum.jsite.application.FileOption;
-import de.todesbaum.jsite.application.Project;
-import de.todesbaum.jsite.gui.FileScanner.ScannedFile;
-import de.todesbaum.jsite.i18n.I18n;
-import de.todesbaum.jsite.i18n.I18nContainer;
-import de.todesbaum.util.mime.DefaultMIMETypes;
-import de.todesbaum.util.swing.TLabel;
-import de.todesbaum.util.swing.TWizard;
-import de.todesbaum.util.swing.TWizardPage;
-
-/**
- * Wizard page that lets the user manage the files of a project.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class ProjectFilesPage extends TWizardPage implements ActionListener, ListSelectionListener, DocumentListener, FileScannerListener {
-
- /** The project. */
- private Project project;
-
- /** The “scan files” action. */
- private Action scanAction;
-
- /** The “ignore hidden files” checkbox. */
- private JCheckBox ignoreHiddenFilesCheckBox;
-
- /** The list of project files. */
- private JList projectFileList;
-
- /** The “default file” checkbox. */
- private JCheckBox defaultFileCheckBox;
-
- /** The “insert” checkbox. */
- private JCheckBox fileOptionsInsertCheckBox;
-
- /** The “force insert” checkbox. */
- private JCheckBox fileOptionsForceInsertCheckBox;
-
- /** The “insert redirect” checkbox. */
- private JCheckBox fileOptionsInsertRedirectCheckBox;
-
- /** The “custom key” textfield. */
- private JTextField fileOptionsCustomKeyTextField;
-
- /** The “rename” check box. */
- private JCheckBox fileOptionsRenameCheckBox;
-
- /** The “new name” text field. */
- private JTextField fileOptionsRenameTextField;
-
- /** The “mime type” combo box. */
- private JComboBox fileOptionsMIMETypeComboBox;
-
- /**
- * Creates a new project file page.
- *
- * @param wizard
- * The wizard the page belongs to
- */
- public ProjectFilesPage(final TWizard wizard) {
- super(wizard);
- pageInit();
- }
-
- /**
- * Initializes the page and all its actions and components.
- */
- private void pageInit() {
- createActions();
- setLayout(new BorderLayout(12, 12));
- add(createProjectFilesPanel(), BorderLayout.CENTER);
- }
-
- /**
- * Creates all actions.
- */
- private void createActions() {
- scanAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.rescan")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionScan();
- }
- };
- scanAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
- scanAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.rescan.tooltip"));
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- scanAction.putValue(Action.NAME, I18n.getMessage("jsite.project-files.action.rescan"));
- scanAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.rescan.tooltip"));
- }
- });
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void pageAdded(TWizard wizard) {
- actionScan();
- this.wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
- this.wizard.setNextName(I18n.getMessage("jsite.project-files.insert-now"));
- this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
- }
-
- /**
- * Creates the panel contains the project file list and options.
- *
- * @return The created panel
- */
- private JComponent createProjectFilesPanel() {
- JPanel projectFilesPanel = new JPanel(new BorderLayout(12, 12));
-
- projectFileList = new JList();
- projectFileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- projectFileList.setMinimumSize(new Dimension(250, projectFileList.getPreferredSize().height));
- projectFileList.addListSelectionListener(this);
-
- projectFilesPanel.add(new JScrollPane(projectFileList), BorderLayout.CENTER);
-
- JPanel fileOptionsAlignmentPanel = new JPanel(new BorderLayout(12, 12));
- projectFilesPanel.add(fileOptionsAlignmentPanel, BorderLayout.PAGE_END);
- JPanel fileOptionsPanel = new JPanel(new GridBagLayout());
- fileOptionsAlignmentPanel.add(fileOptionsPanel, BorderLayout.PAGE_START);
-
- ignoreHiddenFilesCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.ignore-hidden-files"));
- ignoreHiddenFilesCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.ignore-hidden-files.tooltip"));
- ignoreHiddenFilesCheckBox.setName("ignore-hidden-files");
- ignoreHiddenFilesCheckBox.addActionListener(this);
- fileOptionsPanel.add(ignoreHiddenFilesCheckBox, new GridBagConstraints(0, 0, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
-
- fileOptionsPanel.add(new JButton(scanAction), new GridBagConstraints(0, 1, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
-
- final JLabel fileOptionsLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project-files.file-options") + "</b></html>");
- fileOptionsPanel.add(fileOptionsLabel, new GridBagConstraints(0, 2, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
-
- defaultFileCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.default"));
- defaultFileCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.default.tooltip"));
- defaultFileCheckBox.setName("default-file");
- defaultFileCheckBox.addActionListener(this);
- defaultFileCheckBox.setEnabled(false);
-
- fileOptionsPanel.add(defaultFileCheckBox, new GridBagConstraints(0, 3, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
-
- fileOptionsInsertCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.insert"), true);
- fileOptionsInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert.tooltip"));
- fileOptionsInsertCheckBox.setName("insert");
- fileOptionsInsertCheckBox.setMnemonic(KeyEvent.VK_I);
- fileOptionsInsertCheckBox.addActionListener(this);
- fileOptionsInsertCheckBox.setEnabled(false);
-
- fileOptionsPanel.add(fileOptionsInsertCheckBox, new GridBagConstraints(0, 4, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
-
- fileOptionsForceInsertCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.force-insert"));
- fileOptionsForceInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.force-insert.tooltip"));
- fileOptionsForceInsertCheckBox.setName("force-insert");
- fileOptionsForceInsertCheckBox.setMnemonic(KeyEvent.VK_F);
- fileOptionsForceInsertCheckBox.addActionListener(this);
- fileOptionsForceInsertCheckBox.setEnabled(false);
-
- fileOptionsPanel.add(fileOptionsForceInsertCheckBox, new GridBagConstraints(0, 5, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
-
- fileOptionsCustomKeyTextField = new JTextField(45);
- fileOptionsCustomKeyTextField.setToolTipText(I18n.getMessage("jsite.project-files.custom-key.tooltip"));
- fileOptionsCustomKeyTextField.setEnabled(false);
- fileOptionsCustomKeyTextField.getDocument().addDocumentListener(this);
-
- fileOptionsInsertRedirectCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.insert-redirect"), false);
- fileOptionsInsertRedirectCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert-redirect.tooltip"));
- fileOptionsInsertRedirectCheckBox.setName("insert-redirect");
- fileOptionsInsertRedirectCheckBox.setMnemonic(KeyEvent.VK_R);
- fileOptionsInsertRedirectCheckBox.addActionListener(this);
- fileOptionsInsertRedirectCheckBox.setEnabled(false);
-
- final TLabel customKeyLabel = new TLabel(I18n.getMessage("jsite.project-files.custom-key") + ":", KeyEvent.VK_K, fileOptionsCustomKeyTextField);
- fileOptionsPanel.add(fileOptionsInsertRedirectCheckBox, new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- fileOptionsPanel.add(customKeyLabel, new GridBagConstraints(1, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0));
- fileOptionsPanel.add(fileOptionsCustomKeyTextField, new GridBagConstraints(2, 6, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- fileOptionsRenameCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.rename"), false);
- fileOptionsRenameCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.rename.tooltip"));
- fileOptionsRenameCheckBox.setName("rename");
- fileOptionsRenameCheckBox.setMnemonic(KeyEvent.VK_N);
- fileOptionsRenameCheckBox.addActionListener(this);
- fileOptionsRenameCheckBox.setEnabled(false);
-
- fileOptionsRenameTextField = new JTextField();
- fileOptionsRenameTextField.setEnabled(false);
- fileOptionsRenameTextField.getDocument().addDocumentListener(new DocumentListener() {
-
- @SuppressWarnings("synthetic-access")
- private void storeText(DocumentEvent documentEvent) {
- FileOption fileOption = getSelectedFile();
- if (fileOption == null) {
- /* no file selected. */
- return;
- }
- Document document = documentEvent.getDocument();
- int documentLength = document.getLength();
- try {
- fileOption.setChangedName(document.getText(0, documentLength).trim());
- } catch (BadLocationException ble1) {
- /* ignore, it should never happen. */
- }
- }
-
- public void changedUpdate(DocumentEvent documentEvent) {
- storeText(documentEvent);
- }
-
- public void insertUpdate(DocumentEvent documentEvent) {
- storeText(documentEvent);
- }
-
- public void removeUpdate(DocumentEvent documentEvent) {
- storeText(documentEvent);
- }
-
- });
-
- fileOptionsPanel.add(fileOptionsRenameCheckBox, new GridBagConstraints(0, 7, 2, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- fileOptionsPanel.add(fileOptionsRenameTextField, new GridBagConstraints(2, 7, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- fileOptionsMIMETypeComboBox = new JComboBox(DefaultMIMETypes.getAllMIMETypes());
- fileOptionsMIMETypeComboBox.setToolTipText(I18n.getMessage("jsite.project-files.mime-type.tooltip"));
- fileOptionsMIMETypeComboBox.setName("project-files.mime-type");
- fileOptionsMIMETypeComboBox.addActionListener(this);
- fileOptionsMIMETypeComboBox.setEditable(true);
- fileOptionsMIMETypeComboBox.setEnabled(false);
-
- final TLabel mimeTypeLabel = new TLabel(I18n.getMessage("jsite.project-files.mime-type") + ":", KeyEvent.VK_M, fileOptionsMIMETypeComboBox);
- fileOptionsPanel.add(mimeTypeLabel, new GridBagConstraints(0, 8, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- fileOptionsPanel.add(fileOptionsMIMETypeComboBox, new GridBagConstraints(1, 8, 4, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- ignoreHiddenFilesCheckBox.setText(I18n.getMessage("jsite.project-files.ignore-hidden-files"));
- ignoreHiddenFilesCheckBox.setToolTipText(I18n.getMessage("jsite.projet-files.ignore-hidden-files.tooltip"));
- fileOptionsLabel.setText("<html><b>" + I18n.getMessage("jsite.project-files.file-options") + "</b></html>");
- defaultFileCheckBox.setText(I18n.getMessage("jsite.project-files.default"));
- defaultFileCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.default.tooltip"));
- fileOptionsInsertCheckBox.setText(I18n.getMessage("jsite.project-files.insert"));
- fileOptionsInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert.tooltip"));
- fileOptionsForceInsertCheckBox.setText(I18n.getMessage("jsite.project-files.force-insert"));
- fileOptionsForceInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.force-insert.tooltip"));
- fileOptionsInsertRedirectCheckBox.setText(I18n.getMessage("jsite.project-files.insert-redirect"));
- fileOptionsInsertRedirectCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert-redirect.tooltip"));
- fileOptionsCustomKeyTextField.setToolTipText(I18n.getMessage("jsite.project-files.custom-key.tooltip"));
- customKeyLabel.setText(I18n.getMessage("jsite.project-files.custom-key") + ":");
- fileOptionsRenameCheckBox.setText("jsite.project-files.rename");
- fileOptionsRenameCheckBox.setToolTipText("jsite.project-files.rename.tooltip");
- fileOptionsMIMETypeComboBox.setToolTipText(I18n.getMessage("jsite.project-files.mime-type.tooltip"));
- mimeTypeLabel.setText(I18n.getMessage("jsite.project-files.mime-type") + ":");
- }
- });
-
- return projectFilesPanel;
- }
-
- /**
- * Sets the project whose files to manage.
- *
- * @param project
- * The project whose files to manage
- */
- public void setProject(final Project project) {
- this.project = project;
- setHeading(MessageFormat.format(I18n.getMessage("jsite.project-files.heading"), project.getName()));
- setDescription(I18n.getMessage("jsite.project-files.description"));
- ignoreHiddenFilesCheckBox.setSelected(project.isIgnoreHiddenFiles());
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- setHeading(MessageFormat.format(I18n.getMessage("jsite.project-files.heading"), project.getName()));
- setDescription(I18n.getMessage("jsite.project-files.description"));
- }
- });
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Rescans the project’s files.
- */
- private void actionScan() {
- projectFileList.clearSelection();
- projectFileList.setListData(new Object[0]);
-
- wizard.setNextEnabled(false);
- wizard.setPreviousEnabled(false);
- wizard.setQuitEnabled(false);
-
- FileScanner fileScanner = new FileScanner(project);
- fileScanner.addFileScannerListener(this);
- new Thread(fileScanner).start();
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Updates the file list.
- */
- public void fileScannerFinished(FileScanner fileScanner) {
- final boolean error = fileScanner.isError();
- if (!error) {
- final List<ScannedFile> files = fileScanner.getFiles();
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- projectFileList.setListData(files.toArray());
- projectFileList.clearSelection();
- }
- });
- Set<String> entriesToRemove = new HashSet<String>();
- Iterator<String> filenames = new HashSet<String>(project.getFileOptions().keySet()).iterator();
- while (filenames.hasNext()) {
- String filename = filenames.next();
- boolean found = false;
- for (ScannedFile scannedFile : files) {
- if (scannedFile.getFilename().equals(filename)) {
- found = true;
- break;
- }
- }
- if (!found) {
- entriesToRemove.add(filename);
- }
- }
- for (String filename : entriesToRemove) {
- project.setFileOption(filename, null);
- }
- } else {
- JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.scan-error"), null, JOptionPane.ERROR_MESSAGE);
- }
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- wizard.setPreviousEnabled(true);
- wizard.setNextEnabled(!error);
- wizard.setQuitEnabled(true);
- }
- });
- }
-
- /**
- * Returns the {@link FileOption file options} for the currently selected
- * file.
- *
- * @return The {@link FileOption}s for the selected file, or {@code null} if
- * no file is selected
- */
- private FileOption getSelectedFile() {
- ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
- if (scannedFile == null) {
- return null;
- }
- return project.getFileOption(scannedFile.getFilename());
- }
-
- //
- // INTERFACE ActionListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void actionPerformed(ActionEvent actionEvent) {
- Object source = actionEvent.getSource();
- if ((source instanceof JCheckBox) && ("ignore-hidden-files".equals(((JCheckBox) source).getName()))) {
- project.setIgnoreHiddenFiles(((JCheckBox) source).isSelected());
- actionScan();
- return;
- }
- ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
- if (scannedFile == null) {
- return;
- }
- String filename = scannedFile.getFilename();
- FileOption fileOption = project.getFileOption(filename);
- if (source instanceof JCheckBox) {
- JCheckBox checkBox = (JCheckBox) source;
- if ("default-file".equals(checkBox.getName())) {
- if (checkBox.isSelected()) {
- if (filename.indexOf('/') > -1) {
- JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.invalid-default-file"), null, JOptionPane.ERROR_MESSAGE);
- checkBox.setSelected(false);
- } else {
- project.setIndexFile(filename);
- }
- } else {
- if (filename.equals(project.getIndexFile())) {
- project.setIndexFile(null);
- }
- }
- } else if ("insert".equals(checkBox.getName())) {
- boolean isInsert = checkBox.isSelected();
- fileOption.setInsert(isInsert);
- fileOptionsInsertRedirectCheckBox.setEnabled(!isInsert);
- } else if ("force-insert".equals(checkBox.getName())) {
- boolean isForceInsert = checkBox.isSelected();
- fileOption.setForceInsert(isForceInsert);
- } else if ("insert-redirect".equals(checkBox.getName())) {
- boolean isInsertRedirect = checkBox.isSelected();
- fileOption.setInsertRedirect(isInsertRedirect);
- fileOptionsCustomKeyTextField.setEnabled(isInsertRedirect);
- } else if ("rename".equals(checkBox.getName())) {
- boolean isRenamed = checkBox.isSelected();
- fileOptionsRenameTextField.setEnabled(isRenamed);
- fileOption.setChangedName(isRenamed ? fileOptionsRenameTextField.getText() : "");
- }
- } else if (source instanceof JComboBox) {
- JComboBox comboBox = (JComboBox) source;
- if ("project-files.mime-type".equals(comboBox.getName())) {
- fileOption.setMimeType((String) comboBox.getSelectedItem());
- }
- }
- }
-
- //
- // INTERFACE ListSelectionListener
- //
-
- /**
- * {@inheritDoc}
- */
- @SuppressWarnings("null")
- public void valueChanged(ListSelectionEvent e) {
- ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
- boolean enabled = scannedFile != null;
- String filename = (scannedFile == null) ? null : scannedFile.getFilename();
- defaultFileCheckBox.setEnabled(enabled);
- fileOptionsInsertCheckBox.setEnabled(enabled);
- fileOptionsRenameCheckBox.setEnabled(enabled);
- fileOptionsMIMETypeComboBox.setEnabled(enabled);
- if (filename != null) {
- FileOption fileOption = project.getFileOption(filename);
- defaultFileCheckBox.setSelected(filename.equals(project.getIndexFile()));
- fileOptionsInsertCheckBox.setSelected(fileOption.isInsert());
- fileOptionsForceInsertCheckBox.setEnabled(scannedFile.getHash().equals(fileOption.getLastInsertHash()));
- fileOptionsForceInsertCheckBox.setSelected(fileOption.isForceInsert());
- fileOptionsInsertRedirectCheckBox.setEnabled(!fileOption.isInsert());
- fileOptionsInsertRedirectCheckBox.setSelected(fileOption.isInsertRedirect());
- fileOptionsCustomKeyTextField.setEnabled(fileOption.isInsertRedirect());
- fileOptionsCustomKeyTextField.setText(fileOption.getCustomKey());
- fileOptionsRenameCheckBox.setSelected(fileOption.hasChangedName());
- fileOptionsRenameTextField.setEnabled(fileOption.hasChangedName());
- fileOptionsRenameTextField.setText(fileOption.getChangedName());
- fileOptionsMIMETypeComboBox.getModel().setSelectedItem(fileOption.getMimeType());
- } else {
- defaultFileCheckBox.setSelected(false);
- fileOptionsInsertCheckBox.setSelected(true);
- fileOptionsForceInsertCheckBox.setEnabled(false);
- fileOptionsForceInsertCheckBox.setSelected(false);
- fileOptionsInsertRedirectCheckBox.setEnabled(false);
- fileOptionsInsertRedirectCheckBox.setSelected(false);
- fileOptionsCustomKeyTextField.setEnabled(false);
- fileOptionsCustomKeyTextField.setText("CHK@");
- fileOptionsRenameCheckBox.setEnabled(false);
- fileOptionsRenameCheckBox.setSelected(false);
- fileOptionsRenameTextField.setEnabled(false);
- fileOptionsRenameTextField.setText("");
- fileOptionsMIMETypeComboBox.getModel().setSelectedItem(DefaultMIMETypes.DEFAULT_MIME_TYPE);
- }
- }
-
- //
- // INTERFACE DocumentListener
- //
-
- /**
- * Updates the options of the currently selected file with the changes made
- * in the “custom key” textfield.
- *
- * @param documentEvent
- * The document event to process
- */
- private void processDocumentUpdate(DocumentEvent documentEvent) {
- ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
- if (scannedFile == null) {
- return;
- }
- FileOption fileOption = project.getFileOption(scannedFile.getFilename());
- Document document = documentEvent.getDocument();
- try {
- String text = document.getText(0, document.getLength());
- fileOption.setCustomKey(text);
- } catch (BadLocationException ble1) {
- /* ignore. */
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void changedUpdate(DocumentEvent documentEvent) {
- processDocumentUpdate(documentEvent);
- }
-
- /**
- * {@inheritDoc}
- */
- public void insertUpdate(DocumentEvent documentEvent) {
- processDocumentUpdate(documentEvent);
- }
-
- /**
- * {@inheritDoc}
- */
- public void removeUpdate(DocumentEvent documentEvent) {
- processDocumentUpdate(documentEvent);
- }
-
-}
+++ /dev/null
-/*
- * jSite - ProjectInsertPage.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.ClipboardOwner;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-import java.text.DateFormat;
-import java.text.MessageFormat;
-import java.util.Date;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JProgressBar;
-import javax.swing.JTextField;
-import javax.swing.SwingUtilities;
-
-import de.todesbaum.jsite.application.AbortedException;
-import de.todesbaum.jsite.application.Freenet7Interface;
-import de.todesbaum.jsite.application.InsertListener;
-import de.todesbaum.jsite.application.Project;
-import de.todesbaum.jsite.application.ProjectInserter;
-import de.todesbaum.jsite.i18n.I18n;
-import de.todesbaum.jsite.i18n.I18nContainer;
-import de.todesbaum.util.freenet.fcp2.ClientPutDir.ManifestPutter;
-import de.todesbaum.util.freenet.fcp2.PriorityClass;
-import de.todesbaum.util.io.StreamCopier.ProgressListener;
-import de.todesbaum.util.swing.TWizard;
-import de.todesbaum.util.swing.TWizardPage;
-
-/**
- * Wizard page that shows the progress of an insert.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class ProjectInsertPage extends TWizardPage implements InsertListener, ClipboardOwner {
-
- /** The logger. */
- private static final Logger logger = Logger.getLogger(ProjectInsertPage.class.getName());
-
- /** The project inserter. */
- private ProjectInserter projectInserter;
-
- /** The “copy URI” action. */
- private Action copyURIAction;
-
- /** The “request URI” textfield. */
- private JTextField requestURITextField;
-
- /** The “start time” label. */
- private JLabel startTimeLabel;
-
- /** The progress bar. */
- private JProgressBar progressBar;
-
- /** The start time of the insert. */
- private long startTime = 0;
-
- /** The number of inserted blocks. */
- private volatile int insertedBlocks;
-
- /** Whether the “copy URI to clipboard” button was used. */
- private boolean uriCopied;
-
- /** Whether the insert is currently running. */
- private volatile boolean running = false;
-
- /**
- * Creates a new progress insert wizard page.
- *
- * @param wizard
- * The wizard this page belongs to
- */
- public ProjectInsertPage(final TWizard wizard) {
- super(wizard);
- createActions();
- pageInit();
- setHeading(I18n.getMessage("jsite.insert.heading"));
- setDescription(I18n.getMessage("jsite.insert.description"));
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- setHeading(I18n.getMessage("jsite.insert.heading"));
- setDescription(I18n.getMessage("jsite.insert.description"));
- }
- });
- projectInserter = new ProjectInserter();
- projectInserter.addInsertListener(this);
- }
-
- /**
- * Creates all used actions.
- */
- private void createActions() {
- copyURIAction = new AbstractAction(I18n.getMessage("jsite.project.action.copy-uri")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionCopyURI();
- }
- };
- copyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
- copyURIAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_U);
- copyURIAction.setEnabled(false);
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- copyURIAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.copy-uri"));
- copyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
- }
- });
- }
-
- /**
- * Initializes the page.
- */
- private void pageInit() {
- setLayout(new BorderLayout(12, 12));
- add(createProjectInsertPanel(), BorderLayout.CENTER);
- }
-
- /**
- * Creates the main panel.
- *
- * @return The main panel
- */
- private JComponent createProjectInsertPanel() {
- JComponent projectInsertPanel = new JPanel(new GridBagLayout());
-
- requestURITextField = new JTextField();
- requestURITextField.setEditable(false);
-
- startTimeLabel = new JLabel();
-
- progressBar = new JProgressBar(0, 1);
- progressBar.setStringPainted(true);
- progressBar.setValue(0);
-
- final JLabel projectInformationLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.insert.project-information") + "</b></html>");
- projectInsertPanel.add(projectInformationLabel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
- final JLabel requestURILabel = new JLabel(I18n.getMessage("jsite.insert.request-uri") + ":");
- projectInsertPanel.add(requestURILabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
- projectInsertPanel.add(requestURITextField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- final JLabel startTimeLeftLabel = new JLabel(I18n.getMessage("jsite.insert.start-time") + ":");
- projectInsertPanel.add(startTimeLeftLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
- projectInsertPanel.add(startTimeLabel, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- final JLabel progressLabel = new JLabel(I18n.getMessage("jsite.insert.progress") + ":");
- projectInsertPanel.add(progressLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
- projectInsertPanel.add(progressBar, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- projectInsertPanel.add(new JButton(copyURIAction), new GridBagConstraints(0, 4, 2, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0));
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- projectInformationLabel.setText("<html><b>" + I18n.getMessage("jsite.insert.project-information") + "</b></html>");
- requestURILabel.setText(I18n.getMessage("jsite.insert.request-uri") + ":");
- startTimeLeftLabel.setText(I18n.getMessage("jsite.insert.start-time") + ":");
- if (startTime != 0) {
- startTimeLabel.setText(DateFormat.getDateTimeInstance().format(new Date(startTime)));
- } else {
- startTimeLabel.setText("");
- }
- progressLabel.setText(I18n.getMessage("jsite.insert.progress") + ":");
- }
- });
-
- return projectInsertPanel;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void pageAdded(TWizard wizard) {
- this.wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
- this.wizard.setPreviousEnabled(false);
- this.wizard.setNextName(I18n.getMessage("jsite.general.cancel"));
- this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
- }
-
- /**
- * Starts the insert.
- */
- public void startInsert() {
- running = true;
- copyURIAction.setEnabled(false);
- progressBar.setValue(0);
- progressBar.setString(I18n.getMessage("jsite.insert.starting"));
- progressBar.setFont(progressBar.getFont().deriveFont(Font.PLAIN));
- projectInserter.start(new ProgressListener() {
-
- public void onProgress(final long copied, final long length) {
- SwingUtilities.invokeLater(new Runnable() {
-
- /**
- * {@inheritDoc}
- */
- @SuppressWarnings("synthetic-access")
- public void run() {
- int divisor = 1;
- while (((copied / divisor) > Integer.MAX_VALUE) || ((length / divisor) > Integer.MAX_VALUE)) {
- divisor *= 10;
- }
- progressBar.setMaximum((int) (length / divisor));
- progressBar.setValue((int) (copied / divisor));
- progressBar.setString("Uploaded: " + copied + " / " + length);
- }
- });
- }
- });
- }
-
- /**
- * Stops the currently running insert.
- */
- public void stopInsert() {
- if (running) {
- wizard.setNextEnabled(false);
- projectInserter.stop();
- }
- }
-
- /**
- * Returns whether the insert is currently running.
- *
- * @return {@code true} if the insert is currently running, {@code false}
- * otherwise
- */
- public boolean isRunning() {
- return running;
- }
-
- /**
- * Sets the project to insert.
- *
- * @param project
- * The project to insert
- */
- public void setProject(final Project project) {
- projectInserter.setProject(project);
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- requestURITextField.setText(project.getFinalRequestURI(1));
- }
- });
- }
-
- /**
- * Sets the freenet interface to use.
- *
- * @param freenetInterface
- * The freenet interface to use
- */
- public void setFreenetInterface(Freenet7Interface freenetInterface) {
- projectInserter.setFreenetInterface(freenetInterface);
- }
-
- /**
- * Sets the project inserter’s temp directory.
- *
- * @see ProjectInserter#setTempDirectory(String)
- * @param tempDirectory
- * The temp directory to use, or {@code null} to use the system
- * default
- */
- public void setTempDirectory(String tempDirectory) {
- projectInserter.setTempDirectory(tempDirectory);
- }
-
- /**
- * Returns whether the “copy URI to clipboard” button was used.
- *
- * @return {@code true} if an URI was copied to clipboard, {@code false}
- * otherwise
- */
- public boolean wasUriCopied() {
- return uriCopied;
- }
-
- /**
- * Sets whether to use the “early encode“ flag for the insert.
- *
- * @param useEarlyEncode
- * {@code true} to set the “early encode” flag for the insert,
- * {@code false} otherwise
- */
- public void setUseEarlyEncode(boolean useEarlyEncode) {
- projectInserter.setUseEarlyEncode(useEarlyEncode);
- }
-
- /**
- * Sets the insert priority.
- *
- * @param priority
- * The insert priority
- */
- public void setPriority(PriorityClass priority) {
- projectInserter.setPriority(priority);
- }
-
- /**
- * Sets the manifest putter to use for the insert.
- *
- * @see ProjectInserter#setManifestPutter(ManifestPutter)
- * @param manifestPutter
- * The manifest putter
- */
- public void setManifestPutter(ManifestPutter manifestPutter) {
- projectInserter.setManifestPutter(manifestPutter);
- }
-
- //
- // INTERFACE InsertListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void projectInsertStarted(final Project project) {
-
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- startTimeLabel.setText(DateFormat.getDateTimeInstance().format(new Date()));
- }
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectUploadFinished(Project project) {
- startTime = System.currentTimeMillis();
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- progressBar.setString(I18n.getMessage("jsite.insert.starting"));
- progressBar.setValue(0);
- }
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectURIGenerated(Project project, final String uri) {
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- copyURIAction.setEnabled(true);
- requestURITextField.setText(uri);
- }
- });
- logger.log(Level.FINEST, "Insert generated URI: " + uri);
- int slash = uri.indexOf('/');
- slash = uri.indexOf('/', slash + 1);
- int secondSlash = uri.indexOf('/', slash + 1);
- if (secondSlash == -1) {
- secondSlash = uri.length();
- }
- String editionNumber = uri.substring(slash + 1, secondSlash);
- logger.log(Level.FINEST, "Extracted edition number: " + editionNumber);
- int edition = -1;
- try {
- edition = Integer.valueOf(editionNumber);
- } catch (NumberFormatException nfe1) {
- /* ignore. */
- }
- logger.log(Level.FINEST, "Insert edition: " + edition + ", Project edition: " + project.getEdition());
- if ((edition != -1) && (edition == project.getEdition())) {
- JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.reinserted-edition"), I18n.getMessage("jsite.insert.reinserted-edition.title"), JOptionPane.INFORMATION_MESSAGE);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectInsertProgress(Project project, final int succeeded, final int failed, final int fatal, final int total, final boolean finalized) {
- insertedBlocks = succeeded;
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- if (total == 0) {
- return;
- }
- progressBar.setMaximum(total);
- progressBar.setValue(succeeded + failed + fatal);
- int progress = (succeeded + failed + fatal) * 100 / total;
- StringBuilder progressString = new StringBuilder();
- progressString.append(progress).append("% (");
- progressString.append(succeeded + failed + fatal).append('/').append(total);
- progressString.append(") (");
- progressString.append(getTransferRate());
- progressString.append(' ').append(I18n.getMessage("jsite.insert.k-per-s")).append(')');
- progressBar.setString(progressString.toString());
- if (finalized) {
- progressBar.setFont(progressBar.getFont().deriveFont(Font.BOLD));
- }
- }
- });
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectInsertFinished(Project project, boolean success, Throwable cause) {
- running = false;
- if (success) {
- String copyURILabel = I18n.getMessage("jsite.insert.okay-copy-uri");
- int selectedValue = JOptionPane.showOptionDialog(this, I18n.getMessage("jsite.insert.inserted"), I18n.getMessage("jsite.insert.done.title"), 0, JOptionPane.INFORMATION_MESSAGE, null, new Object[] { I18n.getMessage("jsite.general.ok"), copyURILabel }, copyURILabel);
- if (selectedValue == 1) {
- actionCopyURI();
- }
- } else {
- if (cause == null) {
- JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.insert-failed"), I18n.getMessage("jsite.insert.insert-failed.title"), JOptionPane.ERROR_MESSAGE);
- } else {
- if (cause instanceof AbortedException) {
- JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.insert-aborted"), I18n.getMessage("jsite.insert.insert-aborted.title"), JOptionPane.INFORMATION_MESSAGE);
- } else {
- JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.insert.insert-failed-with-cause"), cause.getMessage()), I18n.getMessage("jsite.insert.insert-failed.title"), JOptionPane.ERROR_MESSAGE);
- }
- }
- }
- SwingUtilities.invokeLater(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- progressBar.setValue(progressBar.getMaximum());
- progressBar.setString(I18n.getMessage("jsite.insert.done") + " (" + getTransferRate() + " " + I18n.getMessage("jsite.insert.k-per-s") + ")");
- wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
- wizard.setNextEnabled(true);
- wizard.setQuitEnabled(true);
- }
- });
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Copies the request URI of the project to the clipboard.
- */
- private void actionCopyURI() {
- uriCopied = true;
- Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- clipboard.setContents(new StringSelection(requestURITextField.getText()), this);
- }
-
- /**
- * Formats the given number so that it always has the the given number of
- * fractional digits.
- *
- * @param number
- * The number to format
- * @param digits
- * The number of fractional digits
- * @return The formatted number
- */
- private String formatNumber(double number, int digits) {
- int multiplier = (int) Math.pow(10, digits);
- String formattedNumber = String.valueOf((int) (number * multiplier) / (double) multiplier);
- if (formattedNumber.indexOf('.') == -1) {
- formattedNumber += '.';
- for (int digit = 0; digit < digits; digit++) {
- formattedNumber += "0";
- }
- }
- return formattedNumber;
- }
-
- /**
- * Returns the formatted transfer rate at this point.
- *
- * @return The formatted transfer rate
- */
- private String getTransferRate() {
- return formatNumber(insertedBlocks * 32.0 / ((System.currentTimeMillis() - startTime) / 1000), 1);
- }
-
- //
- // INTERFACE ClipboardOwner
- //
-
- /**
- * {@inheritDoc}
- */
- public void lostOwnership(Clipboard clipboard, Transferable contents) {
- /* ignore. */
- }
-
-}
+++ /dev/null
-/*
- * jSite - ProjectPage.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.ClipboardOwner;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-import java.io.IOException;
-import java.text.MessageFormat;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.border.EmptyBorder;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.text.AbstractDocument;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.DocumentFilter;
-
-import de.todesbaum.jsite.application.Freenet7Interface;
-import de.todesbaum.jsite.application.KeyDialog;
-import de.todesbaum.jsite.application.Project;
-import de.todesbaum.jsite.i18n.I18n;
-import de.todesbaum.jsite.i18n.I18nContainer;
-import de.todesbaum.util.swing.SortedListModel;
-import de.todesbaum.util.swing.TLabel;
-import de.todesbaum.util.swing.TWizard;
-import de.todesbaum.util.swing.TWizardPage;
-
-/**
- * Wizard page that lets the user manage his projects and start inserts.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class ProjectPage extends TWizardPage implements ListSelectionListener, DocumentListener, ClipboardOwner {
-
- /** The freenet interface. */
- private Freenet7Interface freenetInterface;
-
- /** The “browse” action. */
- private Action projectLocalPathBrowseAction;
-
- /** The “add project” action. */
- private Action projectAddAction;
-
- /** The “delete project” action. */
- private Action projectDeleteAction;
-
- /** The “clone project” action. */
- private Action projectCloneAction;
-
- /** The “manage keys” action. */
- private Action projectManageKeysAction;
-
- /** The “copy URI” action. */
- private Action projectCopyURIAction;
-
- /** The “reset edition” action. */
- private Action projectResetEditionAction;
-
- /** The file chooser. */
- private JFileChooser pathChooser;
-
- /** The project list model. */
- private SortedListModel<Project> projectListModel;
-
- /** The project list scroll pane. */
- private JScrollPane projectScrollPane;
-
- /** The project list. */
- private JList projectList;
-
- /** The project name textfield. */
- private JTextField projectNameTextField;
-
- /** The project description textfield. */
- private JTextField projectDescriptionTextField;
-
- /** The local path textfield. */
- private JTextField projectLocalPathTextField;
-
- /** The textfield for the complete URI. */
- private JTextField projectCompleteUriTextField;
-
- /** The project path textfield. */
- private JTextField projectPathTextField;
-
- /** Whether the “copy URI to clipboard” action was used. */
- private boolean uriCopied;
-
- /**
- * Creates a new project page.
- *
- * @param wizard
- * The wizard this page belongs to
- */
- public ProjectPage(final TWizard wizard) {
- super(wizard);
- setLayout(new BorderLayout(12, 12));
- dialogInit();
- setHeading(I18n.getMessage("jsite.project.heading"));
- setDescription(I18n.getMessage("jsite.project.description"));
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- setHeading(I18n.getMessage("jsite.project.heading"));
- setDescription(I18n.getMessage("jsite.project.description"));
- }
- });
- }
-
- /**
- * Initializes the page.
- */
- private void dialogInit() {
- createActions();
-
- pathChooser = new JFileChooser();
- projectListModel = new SortedListModel<Project>();
- projectList = new JList(projectListModel);
- projectList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- projectList.addListSelectionListener(this);
-
- add(projectScrollPane = new JScrollPane(projectList), BorderLayout.LINE_START);
- projectScrollPane.setPreferredSize(new Dimension(150, projectList.getPreferredSize().height));
- add(createInformationPanel(), BorderLayout.CENTER);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void pageAdded(TWizard wizard) {
- super.pageAdded(wizard);
- projectList.clearSelection();
- this.wizard.setPreviousName(I18n.getMessage("jsite.menu.nodes.manage-nodes"));
- this.wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
- this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
- this.wizard.setNextEnabled(false);
- }
-
- /**
- * Adds the given listener to the list of listeners.
- *
- * @param listener
- * The listener to add
- */
- public void addListSelectionListener(ListSelectionListener listener) {
- projectList.addListSelectionListener(listener);
- }
-
- /**
- * Removes the given listener from the list of listeners.
- *
- * @param listener
- * The listener to remove
- */
- public void removeListSelectionListener(ListSelectionListener listener) {
- projectList.removeListSelectionListener(listener);
- }
-
- /**
- * Creates all actions.
- */
- private void createActions() {
- projectLocalPathBrowseAction = new AbstractAction(I18n.getMessage("jsite.project.action.browse")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionLocalPathBrowse();
- }
- };
- projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip"));
- projectLocalPathBrowseAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_B);
- projectLocalPathBrowseAction.setEnabled(false);
-
- projectAddAction = new AbstractAction(I18n.getMessage("jsite.project.action.add-project")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionAdd();
- }
- };
- projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip"));
- projectAddAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
-
- projectDeleteAction = new AbstractAction(I18n.getMessage("jsite.project.action.delete-project")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionDelete();
- }
- };
- projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip"));
- projectDeleteAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
- projectDeleteAction.setEnabled(false);
-
- projectCloneAction = new AbstractAction(I18n.getMessage("jsite.project.action.clone-project")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionClone();
- }
- };
- projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip"));
- projectCloneAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_L);
- projectCloneAction.setEnabled(false);
-
- projectCopyURIAction = new AbstractAction(I18n.getMessage("jsite.project.action.copy-uri")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionCopyURI();
- }
- };
- projectCopyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
- projectCopyURIAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_U);
- projectCopyURIAction.setEnabled(false);
-
- projectManageKeysAction = new AbstractAction(I18n.getMessage("jsite.project.action.manage-keys")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionManageKeys();
- }
- };
- projectManageKeysAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.manage-keys.tooltip"));
- projectManageKeysAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_M);
- projectManageKeysAction.setEnabled(false);
-
- projectResetEditionAction = new AbstractAction(I18n.getMessage("jsite.project.action.reset-edition")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionResetEdition();
- }
- };
- projectResetEditionAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.reset-edition.tooltip"));
- projectResetEditionAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_R);
- projectResetEditionAction.setEnabled(false);
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- projectLocalPathBrowseAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.browse"));
- projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip"));
- projectAddAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.add-project"));
- projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip"));
- projectDeleteAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.delete-project"));
- projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip"));
- projectCloneAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.clone-project"));
- projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip"));
- projectCopyURIAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.copy-uri"));
- projectCopyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
- projectManageKeysAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.manage-keys"));
- projectManageKeysAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.manage-keys.tooltip"));
- projectResetEditionAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.reset-edition"));
- projectResetEditionAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.reset-edition.tooltip"));
- pathChooser.setApproveButtonText(I18n.getMessage("jsite.project.action.browse.choose"));
- }
- });
- }
-
- /**
- * Creates the information panel.
- *
- * @return The information panel
- */
- private JComponent createInformationPanel() {
- JPanel informationPanel = new JPanel(new BorderLayout(12, 12));
-
- JPanel informationTable = new JPanel(new GridBagLayout());
-
- JPanel functionButtons = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
- functionButtons.setBorder(new EmptyBorder(-12, -12, -12, -12));
- functionButtons.add(new JButton(projectAddAction));
- functionButtons.add(new JButton(projectDeleteAction));
- functionButtons.add(new JButton(projectCloneAction));
- functionButtons.add(new JButton(projectManageKeysAction));
-
- informationPanel.add(functionButtons, BorderLayout.PAGE_START);
- informationPanel.add(informationTable, BorderLayout.CENTER);
-
- final JLabel projectInformationLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.information") + "</b></html>");
- informationTable.add(projectInformationLabel, new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
-
- projectNameTextField = new JTextField();
- projectNameTextField.getDocument().putProperty("name", "project.name");
- projectNameTextField.getDocument().addDocumentListener(this);
- projectNameTextField.setEnabled(false);
-
- final TLabel projectNameLabel = new TLabel(I18n.getMessage("jsite.project.project.name") + ":", KeyEvent.VK_N, projectNameTextField);
- informationTable.add(projectNameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- informationTable.add(projectNameTextField, new GridBagConstraints(1, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- projectDescriptionTextField = new JTextField();
- projectDescriptionTextField.getDocument().putProperty("name", "project.description");
- projectDescriptionTextField.getDocument().addDocumentListener(this);
- projectDescriptionTextField.setEnabled(false);
-
- final TLabel projectDescriptionLabel = new TLabel(I18n.getMessage("jsite.project.project.description") + ":", KeyEvent.VK_D, projectDescriptionTextField);
- informationTable.add(projectDescriptionLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- informationTable.add(projectDescriptionTextField, new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- projectLocalPathTextField = new JTextField();
- projectLocalPathTextField.getDocument().putProperty("name", "project.localpath");
- projectLocalPathTextField.getDocument().addDocumentListener(this);
- projectLocalPathTextField.setEnabled(false);
-
- final TLabel projectLocalPathLabel = new TLabel(I18n.getMessage("jsite.project.project.local-path") + ":", KeyEvent.VK_L, projectLocalPathTextField);
- informationTable.add(projectLocalPathLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- informationTable.add(projectLocalPathTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- informationTable.add(new JButton(projectLocalPathBrowseAction), new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- final JLabel projectAddressLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.address") + "</b></html>");
- informationTable.add(projectAddressLabel, new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
-
- projectPathTextField = new JTextField();
- projectPathTextField.getDocument().putProperty("name", "project.path");
- projectPathTextField.getDocument().addDocumentListener(this);
- ((AbstractDocument) projectPathTextField.getDocument()).setDocumentFilter(new DocumentFilter() {
-
- /**
- * {@inheritDoc}
- */
- @Override
- @SuppressWarnings("synthetic-access")
- public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
- super.insertString(fb, offset, string.replaceAll("/", ""), attr);
- updateCompleteURI();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @SuppressWarnings("synthetic-access")
- public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
- super.replace(fb, offset, length, text.replaceAll("/", ""), attrs);
- updateCompleteURI();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @SuppressWarnings("synthetic-access")
- public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
- super.remove(fb, offset, length);
- updateCompleteURI();
- }
- });
- projectPathTextField.setEnabled(false);
-
- final TLabel projectPathLabel = new TLabel(I18n.getMessage("jsite.project.project.path") + ":", KeyEvent.VK_P, projectPathTextField);
- informationTable.add(projectPathLabel, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- informationTable.add(projectPathTextField, new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- projectCompleteUriTextField = new JTextField();
- projectCompleteUriTextField.setEditable(false);
- final TLabel projectUriLabel = new TLabel(I18n.getMessage("jsite.project.project.uri") + ":", KeyEvent.VK_U, projectCompleteUriTextField);
- informationTable.add(projectUriLabel, new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
- informationTable.add(projectCompleteUriTextField, new GridBagConstraints(1, 6, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- informationTable.add(new JButton(projectCopyURIAction), new GridBagConstraints(2, 6, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- public void run() {
- projectInformationLabel.setText("<html><b>" + I18n.getMessage("jsite.project.project.information") + "</b></html>");
- projectNameLabel.setText(I18n.getMessage("jsite.project.project.name") + ":");
- projectDescriptionLabel.setText(I18n.getMessage("jsite.project.project.description") + ":");
- projectLocalPathLabel.setText(I18n.getMessage("jsite.project.project.local-path") + ":");
- projectAddressLabel.setText("<html><b>" + I18n.getMessage("jsite.project.project.address") + "</b></html>");
- projectPathLabel.setText(I18n.getMessage("jsite.project.project.path") + ":");
- projectUriLabel.setText(I18n.getMessage("jsite.project.project.uri") + ":");
- }
- });
-
- return informationPanel;
- }
-
- /**
- * Sets the project list.
- *
- * @param projects
- * The list of projects
- */
- public void setProjects(Project[] projects) {
- projectListModel.clear();
- for (Project project : projects) {
- projectListModel.add(project);
- }
- }
-
- /**
- * Returns the list of projects.
- *
- * @return The list of projects
- */
- public Project[] getProjects() {
- return projectListModel.toArray(new Project[projectListModel.size()]);
- }
-
- /**
- * Sets the freenet interface to use.
- *
- * @param freenetInterface
- * The freenetInterface to use
- */
- public void setFreenetInterface(Freenet7Interface freenetInterface) {
- this.freenetInterface = freenetInterface;
- }
-
- /**
- * Returns the currently selected project.
- *
- * @return The currently selected project
- */
- public Project getSelectedProject() {
- return (Project) projectList.getSelectedValue();
- }
-
- /**
- * Returns whether the “copy URI to clipboard” button was used.
- *
- * @return {@code true} if the “copy URI to clipboard” button was used,
- * {@code false} otherwise
- */
- public boolean wasUriCopied() {
- return uriCopied;
- }
-
- /**
- * Updates the currently selected project with changed information from a
- * textfield.
- *
- * @param documentEvent
- * The document event to process
- */
- private void setTextField(DocumentEvent documentEvent) {
- Document document = documentEvent.getDocument();
- String propertyName = (String) document.getProperty("name");
- Project project = (Project) projectList.getSelectedValue();
- if (project == null) {
- return;
- }
- try {
- String text = document.getText(0, document.getLength()).trim();
- if ("project.name".equals(propertyName)) {
- project.setName(text);
- projectList.repaint();
- } else if ("project.description".equals(propertyName)) {
- project.setDescription(text);
- } else if ("project.localpath".equals(propertyName)) {
- project.setLocalPath(text);
- } else if ("project.privatekey".equals(propertyName)) {
- project.setInsertURI(text);
- } else if ("project.publickey".equals(propertyName)) {
- project.setRequestURI(text);
- } else if ("project.path".equals(propertyName)) {
- project.setPath(text);
- }
- } catch (BadLocationException e) {
- /* ignore. */
- }
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Lets the user choose a local path for a project.
- */
- private void actionLocalPathBrowse() {
- Project project = (Project) projectList.getSelectedValue();
- if (project == null) {
- return;
- }
- pathChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- if (pathChooser.showDialog(this, I18n.getMessage("jsite.project.action.browse.choose")) == JFileChooser.APPROVE_OPTION) {
- projectLocalPathTextField.setText(pathChooser.getSelectedFile().getPath());
- }
- }
-
- /**
- * Adds a new project.
- */
- private void actionAdd() {
- String[] keyPair = null;
- if (!freenetInterface.hasNode()) {
- JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
- return;
- }
- try {
- keyPair = freenetInterface.generateKeyPair();
- } catch (IOException ioe1) {
- JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE);
- return;
- }
- Project newProject = new Project();
- newProject.setName(I18n.getMessage("jsite.project.new-project.name"));
- newProject.setInsertURI(keyPair[0]);
- newProject.setRequestURI(keyPair[1]);
- newProject.setEdition(-1);
- newProject.setPath("");
- projectListModel.add(newProject);
- projectScrollPane.revalidate();
- projectScrollPane.repaint();
- projectList.setSelectedIndex(projectListModel.indexOf(newProject));
- }
-
- /**
- * Deletes the currently selected project.
- */
- private void actionDelete() {
- int selectedIndex = projectList.getSelectedIndex();
- if (selectedIndex > -1) {
- if (JOptionPane.showConfirmDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.action.delete-project.confirm"), ((Project) projectList.getSelectedValue()).getName()), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
- projectListModel.remove(selectedIndex);
- projectList.clearSelection();
- if (projectListModel.getSize() != 0) {
- projectList.setSelectedIndex(Math.min(selectedIndex, projectListModel.getSize() - 1));
- }
- }
- }
- }
-
- /**
- * Clones the currently selected project.
- */
- private void actionClone() {
- int selectedIndex = projectList.getSelectedIndex();
- if (selectedIndex > -1) {
- Project newProject = new Project((Project) projectList.getSelectedValue());
- newProject.setName(MessageFormat.format(I18n.getMessage("jsite.project.action.clone-project.copy"), newProject.getName()));
- projectListModel.add(newProject);
- projectList.setSelectedIndex(projectListModel.indexOf(newProject));
- }
- }
-
- /**
- * Copies the request URI of the currently selected project to the
- * clipboard.
- */
- private void actionCopyURI() {
- int selectedIndex = projectList.getSelectedIndex();
- if (selectedIndex > -1) {
- Project selectedProject = (Project) projectList.getSelectedValue();
- Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- clipboard.setContents(new StringSelection(selectedProject.getFinalRequestURI(0)), this);
- uriCopied = true;
- }
- }
-
- /**
- * Opens a {@link KeyDialog} and lets the user manipulate the keys of the
- * project.
- */
- private void actionManageKeys() {
- int selectedIndex = projectList.getSelectedIndex();
- if (selectedIndex > -1) {
- Project selectedProject = (Project) projectList.getSelectedValue();
- KeyDialog keyDialog = new KeyDialog(freenetInterface, wizard);
- keyDialog.setPrivateKey(selectedProject.getInsertURI());
- keyDialog.setPublicKey(selectedProject.getRequestURI());
- keyDialog.setVisible(true);
- if (!keyDialog.wasCancelled()) {
- String originalPublicKey = selectedProject.getRequestURI();
- String originalPrivateKey = selectedProject.getInsertURI();
- selectedProject.setInsertURI(keyDialog.getPrivateKey());
- selectedProject.setRequestURI(keyDialog.getPublicKey());
- if (!originalPublicKey.equals(selectedProject.getRequestURI()) || !originalPrivateKey.equals(selectedProject.getInsertURI())) {
- selectedProject.setEdition(-1);
- }
- updateCompleteURI();
- }
- }
- }
-
- /**
- * Resets the edition of the currently selected project.
- */
- private void actionResetEdition() {
- if (JOptionPane.showConfirmDialog(this, I18n.getMessage("jsite.project.warning.reset-edition"), null, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
- return;
- }
- int selectedIndex = projectList.getSelectedIndex();
- if (selectedIndex > -1) {
- Project selectedProject = (Project) projectList.getSelectedValue();
- selectedProject.setEdition(-1);
- updateCompleteURI();
- }
- }
-
- /**
- * Updates the complete URI text field.
- */
- private void updateCompleteURI() {
- int selectedIndex = projectList.getSelectedIndex();
- if (selectedIndex > -1) {
- Project selectedProject = (Project) projectList.getSelectedValue();
- projectCompleteUriTextField.setText(selectedProject.getFinalRequestURI(0));
- }
- }
-
- //
- // INTERFACE ListSelectionListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void valueChanged(ListSelectionEvent listSelectionEvent) {
- int selectedRow = projectList.getSelectedIndex();
- Project selectedProject = (Project) projectList.getSelectedValue();
- projectNameTextField.setEnabled(selectedRow > -1);
- projectDescriptionTextField.setEnabled(selectedRow > -1);
- projectLocalPathTextField.setEnabled(selectedRow > -1);
- projectPathTextField.setEnabled(selectedRow > -1);
- projectLocalPathBrowseAction.setEnabled(selectedRow > -1);
- projectDeleteAction.setEnabled(selectedRow > -1);
- projectCloneAction.setEnabled(selectedRow > -1);
- projectCopyURIAction.setEnabled(selectedRow > -1);
- projectManageKeysAction.setEnabled(selectedRow > -1);
- projectResetEditionAction.setEnabled(selectedRow > -1);
- if (selectedRow > -1) {
- projectNameTextField.setText(selectedProject.getName());
- projectDescriptionTextField.setText(selectedProject.getDescription());
- projectLocalPathTextField.setText(selectedProject.getLocalPath());
- projectPathTextField.setText(selectedProject.getPath());
- projectCompleteUriTextField.setText("freenet:" + selectedProject.getFinalRequestURI(0));
- } else {
- projectNameTextField.setText("");
- projectDescriptionTextField.setText("");
- projectLocalPathTextField.setText("");
- projectPathTextField.setText("");
- projectCompleteUriTextField.setText("");
- }
- }
-
- //
- // INTERFACE ChangeListener
- //
-
- //
- // INTERFACE DocumentListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void insertUpdate(DocumentEvent documentEvent) {
- setTextField(documentEvent);
- }
-
- /**
- * {@inheritDoc}
- */
- public void removeUpdate(DocumentEvent documentEvent) {
- setTextField(documentEvent);
- }
-
- /**
- * {@inheritDoc}
- */
- public void changedUpdate(DocumentEvent documentEvent) {
- setTextField(documentEvent);
- }
-
- //
- // INTERFACE ClipboardOwner
- //
-
- /**
- * {@inheritDoc}
- */
- public void lostOwnership(Clipboard clipboard, Transferable contents) {
- /* ignore. */
- }
-
-}
+++ /dev/null
-/*
- * jSite - I18n.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.i18n;
-
-import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-
-/**
- * Maps i18n keys to translated texts, depending on a current locale.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class I18n {
-
- /** The default locale, English. */
- private static Locale defaultLocale = new Locale("en");
-
- /** The current locale. */
- private static Locale currentLocale;
-
- /**
- * Returns the currently set locale.
- *
- * @return The current locale
- */
- public static Locale getLocale() {
- if (currentLocale == null) {
- currentLocale = Locale.getDefault();
- }
- return currentLocale;
- }
-
- /**
- * Sets the current locale.
- *
- * @param locale
- * The new current locale
- */
- public static void setLocale(Locale locale) {
- currentLocale = locale;
- Locale.setDefault(locale);
- }
-
- /**
- * Returns the resource bundle for the current locale.
- *
- * @return The resource bundle for the current locale
- */
- public static ResourceBundle getResourceBundle() {
- return getResourceBundle(getLocale());
- }
-
- /**
- * Returns the resource bundle for the given locale.
- *
- * @param locale
- * The locale to get the resource bundle for
- * @return The resource bundle for the given locale
- */
- public static ResourceBundle getResourceBundle(Locale locale) {
- return ResourceBundle.getBundle("de.todesbaum.jsite.i18n.jSite", locale);
- }
-
- /**
- * Retrieves a translated text for the given i18n key. If the resource
- * bundle for the current locale does not have a translation for the given
- * key, the default locale is tried. If that fails, the key is returned.
- *
- * @param key
- * The key to get the translation for
- * @return The translated value, or the key itself if not translation can be
- * found
- */
- public static String getMessage(String key) {
- try {
- return getResourceBundle().getString(key);
- } catch (MissingResourceException mre1) {
- try {
- return getResourceBundle(defaultLocale).getString(key);
- } catch (MissingResourceException mre2) {
- return key;
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - I18nContainer.java - Copyright © 2007–2012 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 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.i18n;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Container that collects {@link Runnable}s that change the texts of GUI
- * components when the current locale has changed.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class I18nContainer implements Iterable<Runnable> {
-
- /** The container singleton. */
- private static final I18nContainer singleton = new I18nContainer();
-
- /** The list of runnables that change texts. */
- private final List<Runnable> i18nRunnables = Collections.synchronizedList(new ArrayList<Runnable>());
-
- /**
- * The list of runnables that change texts and run after
- * {@link #i18nRunnables}.
- */
- private final List<Runnable> i18nPostRunnables = Collections.synchronizedList(new ArrayList<Runnable>());
-
- /**
- * Returns the singleton instance.
- *
- * @return The singleton instance
- */
- public static I18nContainer getInstance() {
- return singleton;
- }
-
- /**
- * Registers an i18n runnable that is run when the current locale has
- * changed.
- *
- * @param i18nRunnable
- * The runnable to register
- */
- public void registerRunnable(Runnable i18nRunnable) {
- i18nRunnables.add(i18nRunnable);
- }
-
- /**
- * Registers a {@link Runnable} that changes texts when the current locale
- * has changed and runs after {@link #i18nRunnables} have run.
- *
- * @param i18nPostRunnable
- * The runnable to register
- */
- public void registerPostRunnable(Runnable i18nPostRunnable) {
- i18nPostRunnables.add(i18nPostRunnable);
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Returns a combined list of {@link #i18nRunnables} and
- * {@link #i18nPostRunnables}, in that order.
- */
- public Iterator<Runnable> iterator() {
- List<Runnable> allRunnables = new ArrayList<Runnable>();
- allRunnables.addAll(i18nRunnables);
- allRunnables.addAll(i18nPostRunnables);
- return allRunnables.iterator();
- }
-
-}
+++ /dev/null
-#
-# jSite - jSite.properties - Copyright © 2006–2012 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
-# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-# English language file by David Roden <droden@gmail.com>
-
-# Attention, translators! Most of the strings here are used directly.
-# However, some of them are parsed by MessageFormat
-# (http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html)
-# and thus have to adhere to some rules (check the URL above). This is the
-# case when a line contains placeholders like {0} or {0,number}! In these
-# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
-# otherwise the placeholder will not be replaced!
-
-jsite.general.ok=OK
-jsite.general.cancel=Cancel
-
-jsite.wizard.previous=Previous
-jsite.wizard.next=Next
-jsite.wizard.quit=Quit
-
-jsite.quit.question=Do you really want to quit?
-jsite.quit.question.title=Really quit?
-jsite.quit.overwrite-configuration=<html><b>Overwrite configuration?</b><br><br>A configuration file already exists:<br><code>{0}</code><br><br>Should it be overwritten?</html>
-jsite.quit.overwrite-configuration.title=Overwrite configuration?
-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
-jsite.menu.language.en=English
-jsite.menu.language.de=Deutsch
-jsite.menu.language.fr=Fran\u00e7ais
-jsite.menu.language.it=Italiano
-jsite.menu.language.pl=Polski
-jsite.menu.nodes=Nodes
-jsite.menu.nodes.manage-nodes=Manage nodes
-jsite.menu.options=Options
-jsite.menu.options.preferences=Preferences
-jsite.menu.help=Help
-jsite.menu.help.check-for-updates=Check for Updates
-jsite.menu.help.about=About
-
-jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006\u20132012 David Roden<br>Released under the GNU General Public License</html>
-
-jsite.node-manager.heading=Node Manager
-jsite.node-manager.description=Manage your nodes here.
-jsite.node-manager.node-information=Node Information
-jsite.node-manager.add-node=Add Node
-jsite.node-manager.new-node=New Node
-jsite.node-manager.delete-node=Delete Node
-jsite.node-manager.delete-node.warning=<html><b>Confirm node deletion</b><br><br>Really delete this node?</html>
-jsite.node-manager.name=Name
-jsite.node-manager.hostname=Hostname
-jsite.node-manager.port=Port
-
-jsite.preferences.heading=Preferences
-jsite.preferences.description=Use this page to manage some global settings.
-jsite.preferences.temp-directory=Directory for temporary files
-jsite.preferences.temp-directory.default=Default (chosen by system)
-jsite.preferences.temp-directory.custom=Custom
-jsite.preferences.temp-directory.choose=Choose
-jsite.preferences.temp-directory.choose.approve=Choose
-jsite.preferences.config-directory=Location of configuration file
-jsite.preferences.config-directory.jar=Next to the JAR file
-jsite.preferences.config-directory.home=Home directory
-jsite.preferences.config-directory.custom=Custom directory
-jsite.preferences.insert-options=Insert options
-jsite.preferences.insert-options.use-early-encode=Generate final URI early
-jsite.preferences.insert-options.priority=Priority
-jsite.preferences.insert-options.manifest-putter=Manifest Putter
-
-jsite.insert.heading=Project insert
-jsite.insert.description=Please wait while the project is being inserted.
-jsite.insert.project-information=Project information
-jsite.insert.request-uri=Freesite
-jsite.insert.start-time=Start time
-jsite.insert.starting=Starting\u2026
-jsite.insert.done=Done.
-jsite.insert.done.title=Insert done
-jsite.insert.insert-aborted=The insert was aborted.
-jsite.insert.insert-aborted.title=Insert Aborted
-jsite.insert.progress=Progress
-jsite.insert.k-per-s=KB/s
-jsite.insert.insert-failed=<html><b>Insert failed</b><br><br>The insert of the project failed.<br>Some files could not be inserted.</html>
-jsite.insert.insert-failed-with-cause=<html><b>Insert failed</b><br><br>The insert of the project failed.<br>Some files could not be inserted.<br>The following error occured:<br><br><code>{0}</code></html>
-jsite.insert.insert-failed.title=Insert Failed
-jsite.insert.inserted=<html><b>Project inserted</b><br><br>Your project was inserted successfully.</html>
-jsite.insert.okay-copy-uri=Copy URI to Clipboard
-jsite.insert.reinserted-edition=<html><b>Edition Reinserted</b><br><br>The edition you are just inserting<br>has already been inserted before.</html>
-jsite.insert.reinserted-edition.title=Edition Reinserted
-
-jsite.file-scanner.can-not-read-directory=Can not read directory
-
-jsite.project.heading=Select a Project
-jsite.project.description=Select a project to process from the list below, or create a new project.
-jsite.project.action.browse=Browse
-jsite.project.action.browse.choose=Choose
-jsite.project.action.browse.tooltip=Browse for directory
-jsite.project.action.add-project=Add project
-jsite.project.action.add-project.tooltip=Add a new project
-jsite.project.new-project.name=New Project
-jsite.project.action.delete-project=Delete project
-jsite.project.action.delete-project.tooltip=Delete a project
-jsite.project.action.delete-project.confirm=<html><b>Confirm deletion</b><br><br>The project \u201c{0}\u201d will be deleted!<br>Do you want to continue?</html>
-jsite.project.action.clone-project=Clone project
-jsite.project.action.clone-project.copy=Copy of {0}
-jsite.project.action.clone-project.tooltip=Clone the selected project
-jsite.project.action.copy-uri=Copy URI to Clipboard
-jsite.project.action.copy-uri.tooltip=Copies the URI of the project to the clipboard
-jsite.project.action.manage-keys=Manage Keys
-jsite.project.action.manage-keys.tooltip=Manages the keys of this project
-jsite.project.action.reset-edition=Reset Edition
-jsite.project.action.reset-edition.tooltip=Resets the edition number of the project
-jsite.project.project.information=Project Information
-jsite.project.project.name=Name
-jsite.project.project.description=Description
-jsite.project.project.local-path=Local path
-jsite.project.project.address=Address
-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.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!<br>Also, the edition will be reset.</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>
-
-jsite.project-files.heading=Project Files
-jsite.project-files.description=<html>On this page you can specify parameters for the files within the project, such as<br>externally generated keys or MIME types, if the automatic detection failed.</html>
-jsite.project-files.action.rescan=Re-scan
-jsite.project-files.action.rescan.tooltip=Re-scan the project directory for new files
-jsite.project-files.ignore-hidden-files=Ignore hidden files
-jsite.project-files.ignore-hidden-files.tooltip=When selected, hidden files are not inserted
-jsite.project-files.file-options=File Options
-jsite.project-files.default=Default file
-jsite.project-files.default.tooltip=Specify that this file is the project\u2019s index file
-jsite.project-files.insert=Insert
-jsite.project-files.insert.tooltip=Uncheck if you do not want to insert this file
-jsite.project-files.force-insert=Force insert
-jsite.project-files.force-insert.tooltip=Forces the insert of this file even it is not modified
-jsite.project-files.insert-redirect=Redirect
-jsite.project-files.insert-redirect.tooltip=Check if you want to insert a redirect for this file
-jsite.project-files.custom-key=Custom key
-jsite.project-files.custom-key.tooltip=The externally created key for the file
-jsite.project-files.rename=Rename
-jsite.project-files.rename.tooltip=Renames the file in the uploaded site
-jsite.project-files.mime-type=MIME type
-jsite.project-files.mime-type.tooltip=Select the correct MIME type here if the detection failed
-jsite.project-files.container=Container
-jsite.project-files.container.tooltip=Selects a container for the current file
-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.insert-now=Insert now
-jsite.project-files.invalid-default-file=Only files in the root directory may be selected as default files.
-
-jsite.update-checker.found-version.title=Found New Version
-jsite.update-checker.found-version.message=<html>A new version was found.<br><br>Version {0} (released {1,date})</html>
-jsite.update-checker.latest-version.title=Update Check
-jsite.update-checker.latest-version.newer.message=<html>You are running version {0} but a newer<br>version ({1}) has been found!</html>
-jsite.update-checker.latest-version.older.message=<html>You are running version {0} but the<br>latest version seems to be {1}.</html>
-jsite.update-checker.latest-version.okay.message=<html>You are currently running version {0}<br>which is the latest version.</html>
-
-jsite.key-dialog.title=Manage Project Keys
-jsite.key-dialog.button.ok.tooltip=Accepts the changes
-jsite.key-dialog.button.cancel.tooltip=Discards the changes
-jsite.key-dialog.button.generate=Regenerate Keys
-jsite.key-dialog.button.generate.tooltip=Create a new key pair
-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.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.warning.site-larger-than-2-mib=<html><b>Site is larger than 2 MiB!</b><br><br>Your site contains more than 2 megabytes of data.<br>Due to bugs in Freenet it will probably not load correctly.<br>Try to reduce the size of your site, or continue at your own peril.</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>
-jsite.error.duplicate-file=<html><b>Duplicate file</b><br><br>The file <code>{0}</code> is inserted twice!<br>Please check your filenames and redirects.</html>
+++ /dev/null
-#
-# jSite - jSite_de.properties - Copyright © 2006–2012 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
-# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-# German language file by David Roden <droden@gmail.com>
-
-# Attention, translators! Most of the strings here are used directly.
-# However, some of them are parsed by MessageFormat
-# (http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html)
-# and thus have to adhere to some rules (check the URL above). This is the
-# case when a line contains placeholders like {0} or {0,number}! In these
-# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
-# otherwise the placeholder will not be replaced!
-
-jsite.general.ok=OK
-jsite.general.cancel=Abbrechen
-
-jsite.wizard.previous=Zur\u00fcck
-jsite.wizard.next=Vorw\u00e4rts
-jsite.wizard.quit=Beenden
-
-jsite.quit.question=M\u00f6chten Sie jSite wirklich beenden?
-jsite.quit.question.title=Wirklich beenden?
-jsite.quit.overwrite-configuration=<html><b>Konfiguration \u00fcberschreiben?</b><br><br>Es existiert bereits eine Konfigurationsdatei unter:<br><code>{0}</code><br><br>Soll sie \u00fcberschrieben werden?</html>
-jsite.quit.overwrite-configuration.title=Konfiguration \u00fcberschreiben?
-jsite.quit.config-not-saved=<html><b>Konfiguration nicht gespeichert</b><br><br>Die Konfiguration konnte nicht gespeichert werden.<br>Soll jSite trotzdem beendet werden?</html>
-
-jsite.menu.languages=Sprachen
-jsite.menu.language.en=English
-jsite.menu.language.de=Deutsch
-jsite.menu.language.fr=Fran\u00e7ais
-jsite.menu.language.it=Italiano
-jsite.menu.language.pl=Polski
-jsite.menu.nodes=Nodes
-jsite.menu.nodes.manage-nodes=Nodes verwalten
-jsite.menu.options=Optionen
-jsite.menu.options.preferences=Einstellungen
-jsite.menu.help=Hilfe
-jsite.menu.help.check-for-updates=Auf Updates pr\u00fcfen
-jsite.menu.help.about=\u00dcber
-
-jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006\u20132012 David Roden<br>Ver\u00f6ffentlicht unter der GNU General Public License</html>
-
-jsite.node-manager.heading=Nodeverwaltung
-jsite.node-manager.description=Verwalten Sie hier Ihre Nodes.
-jsite.node-manager.node-information=Nodeinformation
-jsite.node-manager.add-node=Node hinzuf\u00fcgen
-jsite.node-manager.new-node=Neuer Node
-jsite.node-manager.delete-node=Node l\u00f6schen
-jsite.node-manager.delete-node.warning=<html><b>Nodel\u00f6schung best\u00e4tigen</b><br><br>Wollen Sie diesen Node wirklich l\u00f6schen?</html>
-jsite.node-manager.name=Name
-jsite.node-manager.hostname=Hostname
-jsite.node-manager.port=Port
-
-jsite.preferences.heading=Einstellungen
-jsite.preferences.description=Auf dieser Seite k\u00f6nnen einige globale Einstellungen vorgenommen werden.
-jsite.preferences.temp-directory=Verzeichnis f\u00fcr tempor\u00e4re Dateien
-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.preferences.insert-options=Einf\u00fcgeoptionen
-jsite.preferences.insert-options.use-early-encode=Endg\u00fcltige URI fr\u00fcher berechnen
-jsite.preferences.insert-options.priority=Priorit\u00e4t
-jsite.preferences.insert-options.manifest-putter=Manifesterstellung
-
-jsite.insert.heading=Projekt einf\u00fcgen
-jsite.insert.description=Bitte warten Sie, w\u00e4hrend das Projekt eingef\u00fcgt wird.
-jsite.insert.project-information=Projektinformationen
-jsite.insert.request-uri=Freesite
-jsite.insert.start-time=Beginn
-jsite.insert.starting=Beginne\u2026
-jsite.insert.done=Fertig.
-jsite.insert.done.title=Einf\u00fcgen abgeschlossen
-jsite.insert.insert-aborted=Das Einf\u00fcgen wurde abgebrochen.
-jsite.insert.insert-aborted.title=Einf\u00fcgen abgebrochen
-jsite.insert.progress=Fortschritt
-jsite.insert.k-per-s=KB/s
-jsite.insert.insert-failed=<html><b>Einf\u00fcgen fehlgeschlagen</b><br><br>Das Einf\u00fcgen des Projektes ist fehlgeschlagen, da<br>einige Dateien nicht eingef\u00fcgt werden konnten.</html>
-jsite.insert.insert-failed-with-cause=<html><b>Einf\u00fcgen fehlgeschlagen</b><br><br>Das Einf\u00fcgen des Projektes ist fehlgeschlagen, da<br>einige Dateien nicht eingef\u00fcgt werden konnten.<br>Folgender Fehler trat auf:<br><br><code>{0}</code></html>
-jsite.insert.insert-failed.title=Einf\u00fcgen fehlgeschlagen
-jsite.insert.inserted=<html><b>Projekt eingef\u00fcgt</b><br><br>Ihr Projekt wurde erfolgreich eingef\u00fcgt.</html>
-jsite.insert.okay-copy-uri=URI kopieren
-jsite.insert.reinserted-edition=<html><b>Edition bereits eingef\u00fcgt</b><br><br>Die Edition, die gerade eingef\u00fcgt wird,<br>ist schon einmal eingef\u00fcgt worden.</html>
-jsite.insert.reinserted-edition.title=Edition bereits eingef\u00fcgt
-
-jsite.file-scanner.can-not-read-directory=Kann Verzeichnis nicht lesen
-
-jsite.project.heading=Projekt ausw\u00e4hlen
-jsite.project.description=W\u00e4hlen Sie das Projekt aus, welches sie einf\u00fcgen m\u00f6chten, oder erstellen Sie ein neues Projekt.
-jsite.project.action.browse=Durchsuchen
-jsite.project.action.browse.choose=Ausw\u00e4hlen
-jsite.project.action.browse.tooltip=Lokalen Pfad f\u00fcr Projekt ausw\u00e4hlen
-jsite.project.action.add-project=Projekt erstellen
-jsite.project.action.add-project.tooltip=Ein neues Projekt erstellen
-jsite.project.new-project.name=Neues Projekt
-jsite.project.action.delete-project=Projekt l\u00f6schen
-jsite.project.action.delete-project.tooltip=Ein Projekt l\u00f6schen
-jsite.project.action.delete-project.confirm=<html><b>L\u00f6schung best\u00e4tigen</b><br><br>Das Projekt \u201e{0}\u201c wird gel\u00f6scht!<br>M\u00f6chten Sie fortfahren?</html>
-jsite.project.action.clone-project=Projekt duplizieren
-jsite.project.action.clone-project.copy=Kopie von {0}
-jsite.project.action.clone-project.tooltip=Das ausgew\u00e4hlte Projekt duplizieren
-jsite.project.action.copy-uri=URI kopieren
-jsite.project.action.copy-uri.tooltip=Kopiert die URI des ausgew\u00e4hlten Projektes in die Zwischenablage
-jsite.project.action.manage-keys=Schl\u00fcsselverwaltung
-jsite.project.action.manage-keys.tooltip=Verwaltet die Schl\u00fcssel des Projekts
-jsite.project.action.reset-edition=Edition zur\u00fccksetzen
-jsite.project.action.reset-edition.tooltip=Setzt die Editionsnummer des Projekts zur\u00fcck
-jsite.project.project.information=Projektinformation
-jsite.project.project.name=Name
-jsite.project.project.description=Beschreibung
-jsite.project.project.local-path=Lokaler Pfad
-jsite.project.project.address=Adresse
-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.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! Au\u00dferdem wird die Edition zur\u00fcckgesetzt.</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>
-
-jsite.project-files.heading=Projektdateien
-jsite.project-files.description=<html>Auf dieser Seite k\u00f6nnen Parameter f\u00fcr die einzelnen Dateien dieses Projekts angegeben werden, z.B.<br>extern erstellte Schl\u00fcssel oder der korrekte MIME-Typ, wenn er nicht automatisch richtig erkannt wurde.</html>
-jsite.project-files.action.rescan=Erneut einlesen
-jsite.project-files.action.rescan.tooltip=Die Liste mit Dateien dieses Projekts neu einlesen
-jsite.project-files.ignore-hidden-files=Versteckte Dateien ignorieren
-jsite.project-files.ignore-hidden-files.tooltip=Verhindert, dass versteckte Dateien hochgeladen werden
-jsite.project-files.file-options=Dateioptionen
-jsite.project-files.default=Index-Datei
-jsite.project-files.default.tooltip=Lege Index-Datei f\u00fcr Projekt fest
-jsite.project-files.insert=Einf\u00fcgen
-jsite.project-files.insert.tooltip=jSite f\u00fcgt diese Datei ein
-jsite.project-files.force-insert=Einf\u00fcgen erzwingen
-jsite.project-files.force-insert.tooltip=F\u00fcgt diese Datei ein, auch wenn sie nicht modifiziert wurde
-jsite.project-files.insert-redirect=Umleitung
-jsite.project-files.insert-redirect.tooltip=F\u00fcgt eine Umleitung ein
-jsite.project-files.custom-key=Extern erstellter Schl\u00fcssel
-jsite.project-files.custom-key.tooltip=Der extern erstellte Schl\u00fcssel f\u00fcr diese Datei
-jsite.project-files.rename=Umbenennen
-jsite.project-files.rename.tooltip=Benennt die Datei in der eingef\u00fcgten Seite um
-jsite.project-files.mime-type=MIME-Typ
-jsite.project-files.mime-type.tooltip=Den richtigen MIME-Typ hier ausw\u00e4hlen, wenn die automatische Erkennenung falsch ist
-jsite.project-files.container=Container
-jsite.project-files.container.tooltip=W\u00e4hlt einen Container f\u00fcr diese Datei aus
-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.insert-now=Jetzt einf\u00fcgen
-jsite.project-files.invalid-default-file=Nur Dateien im obersten Verzeichnis d\u00fcrfen als Index-Dateien ausgew\u00e4hlt werden.
-
-jsite.update-checker.found-version.title=Neue Version gefunden
-jsite.update-checker.found-version.message=<html>Eine neue Version wurde gefunden.<br><br>Version {0} (ver\u00f6ffentlicht {1,date})</html>
-jsite.update-checker.latest-version.title=Update\u00fcberpr\u00fcfung
-jsite.update-checker.latest-version.newer.message=<html>Es l\u00e4uft momentan Version {0}, aber eine<br>neue Version ({1}) wurde bereits gefunden!</html>
-jsite.update-checker.latest-version.older.message=<html>Es l\u00e4uft momentan Version {0}, aber die<br>aktuelle Version ist erst {1}.</html>
-jsite.update-checker.latest-version.okay.message=<html>Es l\u00e4uft momentan Version {0},<br>und diese Version ist aktuell.</html>
-
-jsite.key-dialog.title=Projektschl\u00fcsselverwaltung
-jsite.key-dialog.button.ok.tooltip=\u00c4nderungen akzeptieren
-jsite.key-dialog.button.cancel.tooltip=\u00c4nderungen verwerfen
-jsite.key-dialog.button.generate=Schl\u00fcssel neu generieren
-jsite.key-dialog.button.generate.tooltip=Generiert ein neues Schl\u00fcsselpaar
-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.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.warning.site-larger-than-2-mib=<html><b>Ihr Projekt ist gr\u00f6\u00dfer als 2 Megabyte!</b><br><br>Ihr Projekt enth\u00e4lt mehr als 2 Megabyte an Daten. Aufgrund<br>eines Fehlers in Freenet wird die Seite wahrscheinlich nicht<br>korrekt angezeigt werden. Bitte reduzieren Sie die Gr\u00f6\u00dfe<br>Ihres Projektes, oder fahren Sie auf eigene Gefahr fort.</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>
-jsite.error.duplicate-file=<html><b>Doppelte Datei</b><br><br>Die Datei <code>{0}</code> wird zweimal eingef\u00fcgt!<br>Bitte \u00fcberpr\u00fcfen Sie Ihre Umleitungen und Dateinamen!</html>
+++ /dev/null
-#
-# jSite - jSite_fr.properties - Copyright © 2006–2012 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
-# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-
-# French language file by Florent Daigni\u00e8re <nextgens@freenetproject.org>, Julien Cornuwel <batosai@batosai.net>, and Clement Vollet <cvollet@gmail.com>.
-
-# Attention, translators! Most of the strings here are used directly.
-# However, some of them are parsed by MessageFormat
-# (http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html)
-# and thus have to adhere to some rules (check the URL above). This is the
-# case when a line contains placeholders like {0} or {0,number}! In these
-# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
-# otherwise the placeholder will not be replaced!
-
-jsite.general.ok=OK
-jsite.general.cancel=Annuler
-
-jsite.wizard.previous=Pr\u00e9c\u00e9dent
-jsite.wizard.next=Suivant
-jsite.wizard.quit=Quitter
-
-jsite.quit.question=Voulez-vous r\u00e9ellement quitter?
-jsite.quit.question.title=Souhaitez vous quitter?
-jsite.quit.overwrite-configuration=<html><b>Ecraser la configuration?</b><br><br>Un fichier de configuration éxiste déjà:<br><code>{0}</code><br><br>Doit-il être écrasé ?</html>
-jsite.quit.overwrite-configuration.title=Ecraser la configuration?
-jsite.quit.config-not-saved=<html><b>Configuration non sauvegard\u00e9e</b><br><br>La configuration n'a pas pu \u00eatre sauv\u00e9e.<br>Voulez vous quitter tout de m\u00eame?</html>
-
-jsite.menu.languages=Langue
-jsite.menu.language.en=English
-jsite.menu.language.de=Deutsch
-jsite.menu.language.fr=Fran\u00e7ais
-jsite.menu.language.it=Italiano
-jsite.menu.language.pl=Polski
-jsite.menu.nodes=Noeud
-jsite.menu.nodes.manage-nodes=G\u00e9rer les noeuds
-jsite.menu.options=Options
-jsite.menu.options.preferences=Pr\u00e9f\u00e9rences
-jsite.menu.help=Aide
-jsite.menu.help.check-for-updates=Mises \u00e0 jour
-jsite.menu.help.about=A propos de jSite
-
-jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006\u20132012 David Roden<br>Publié sous GNU General Public License</html>
-
-jsite.node-manager.heading=Gestionnaire de noeud
-jsite.node-manager.description=G\u00e9rez vos noeuds.
-jsite.node-manager.node-information=Information sur le noeud
-jsite.node-manager.add-node=Ajouter un noeud
-jsite.node-manager.new-node=Nouveau noeud
-jsite.node-manager.delete-node=Supprimer un noeud
-jsite.node-manager.delete-node.warning=<html><b>Confirmer la suppression</b><br><br>Supprimer r\u00e9ellement ce noeud?</html>
-jsite.node-manager.name=Nom
-jsite.node-manager.hostname=Nom de machine
-jsite.node-manager.port=Port
-
-jsite.preferences.heading=Pr\u00e9f\u00e9rences
-jsite.preferences.description=Utilisez cette page pour g\u00e9rer quelques param\u00e8tres globaux.
-jsite.preferences.temp-directory=R\u00e9pertoire des fichiers temporaires
-jsite.preferences.temp-directory.default=D\u00e9faut (choix syst\u00e8mes)
-jsite.preferences.temp-directory.custom=Personnalis\u00e9
-jsite.preferences.temp-directory.choose=Choisir
-jsite.preferences.temp-directory.choose.approve=Choisir
-jsite.preferences.config-directory=Chemin du fichier de configuration
-jsite.preferences.config-directory.jar=Suivant, le fichier JAR
-jsite.preferences.config-directory.home=Acceuil
-jsite.preferences.config-directory.custom=Répertoire personnel
-jsite.preferences.insert-options=Options d'insertion
-jsite.preferences.insert-options.use-early-encode=Générer d'abord l'URI
-jsite.preferences.insert-options.priority=Priorité
-jsite.preferences.insert-options.manifest-putter=Ajout de Manifest
-
-jsite.insert.heading=Projet d'insertion
-jsite.insert.description=Veuillez attendre durant l'insertion du projet.
-jsite.insert.project-information=Information \u00e0 propos du projet.
-jsite.insert.request-uri=Freesite
-jsite.insert.start-time=Commenc\u00e9 \u00e0
-jsite.insert.starting=D\u00e9marrage\u2026
-jsite.insert.done=Termin\u00e9.
-jsite.insert.done.title=Insertion effectu\u00e9e
-jsite.insert.insert-aborted=L'insertion a été annulée.
-jsite.insert.insert-aborted.title=Insertion Annulée
-jsite.insert.progress=Avancement
-jsite.insert.k-per-s=Ko/s
-jsite.insert.insert-failed=<html><b>Insertion \u00e9chou\u00e9e</b><br><br>L'insertion du projet \u00e0 \u00e9chou\u00e9e.<br>Certain fichiers n'ont pas \u00e9t\u00e9 ins\u00e9r\u00e9s.</html>
-jsite.insert.insert-failed-with-cause=<html><b>Insertion \u00e9chou\u00e9e</b><br><br>L'insertion du projet \u00e0 \u00e9chou\u00e9e.<br>Certain fichiers n'ont pas \u00e9t\u00e9 ins\u00e9r\u00e9s.<br>L'erreur suivante s'est produite:<br><br><code>{0}</code></html>
-jsite.insert.insert-failed.title=Insertion Echouée
-jsite.insert.inserted=<html><b>Projet ins\u00e9r\u00e9!</b><br><br>Votre projet \u00e0 \u00e9t\u00e9 correctement ins\u00e9r\u00e9.</html>
-jsite.insert.okay-copy-uri=Copier l'URI vers le presse-papiers
-jsite.insert.reinserted-edition=<html><b>Edition r\u00e9ins\u00e9r\u00e9e</b><br><br>L'\u00e9dition que vous \u00eates en train d'ins\u00e9rer<br>a d\u00e9j\u00e0 \u00e9t\u00e9 ins\u00e9r\u00e9e avant.</html>
-jsite.insert.reinserted-edition.title=Edition r\u00e9ins\u00e9r\u00e9e
-
-jsite.file-scanner.can-not-read-directory=Impossible de lire le r\u00e9pertoire
-
-jsite.project.heading=S\u00e9lectionnez un projet
-jsite.project.description=S\u00e9lectionnez un projet de la liste ou cr\u00e9ez en un nouveau.
-jsite.project.action.browse=Naviguer
-jsite.project.action.browse.choose=Choisir
-jsite.project.action.browse.tooltip=Choisir un r\u00e9pertoire
-jsite.project.action.add-project=Ajouter un projet
-jsite.project.action.add-project.tooltip=Ajouter un projet
-jsite.project.new-project.name=Nouveau projet
-jsite.project.action.delete-project=D\u00e9truire le projet
-jsite.project.action.delete-project.tooltip=D\u00e9truire le projet
-jsite.project.action.delete-project.confirm=<html><b>Confirmez la suppression</b><br><br>Le projet \u201c{0}\u201d va \u00eatre d\u00e9truit!<br>Voulez vous poursuivre?</html>
-jsite.project.action.clone-project=Cloner le projet
-jsite.project.action.clone-project.copy=Copie de {0}
-jsite.project.action.clone-project.tooltip=Cloner le projet s\u00e9lectionn\u00e9
-jsite.project.action.copy-uri=Copier l'URI dans le presse-papier
-jsite.project.action.copy-uri.tooltip=Copie l'URI du projet dans le presse-papier
-jsite.project.action.generate-new-key=G\u00e9n\u00e9rer une nouvelle cl\u00e9
-jsite.project.action.generate-new-key.tooltip=Cr\u00e9e une nouvelle cl\u00e9 pour ce projet
-jsite.project.action.reset-edition=Remettre \u00e0 z\u00e9ro l'\u00e9dition
-jsite.project.action.reset-edition.tooltip=Remettre \u00e0 z\u00e9ro l'\u00e9dition du projet
-jsite.project.project.information=Informations concernant le projet
-jsite.project.project.name=Nom
-jsite.project.project.description=Description
-jsite.project.project.local-path=Chemin local
-jsite.project.project.address=Adresse
-jsite.project.project.path=Chemin du freesite
-jsite.project.project.edition=Edition
-jsite.project.project.uri=URI
-jsite.project.keygen.io-error=<html><b>Erreur de communication avec le noeud</b><br><br>La communication avec le noeud \u00e0 \u00e9chou\u00e9e<br>Erreur:<br><br><code>{0}</code><br><br>Assurez vous que les informations saisies dans la page de configuration sont correctes.</html>
-jsite.project.warning.generate-new-key=<html><b>G\u00e9n\u00e9rer une nouvelle cl\u00e9 ?</b><br><br>Si vous g\u00e9n\u00e9rez une nouvelle cl\u00e9, votre site sera publi\u00e9<br>avec cette nouvelle cl\u00e9. La confiance que les autres<br>utilisateurs pla\u00e7aient dans l'ancienne cl\u00e9 sera perdue !</html>
-jsite.project.warning.reset-edition=<html><b>Remettre \u00e0 z\u00e9ro l'\u00e9dition ?</b><br><br>Remettre \u00e0 z\u00e9ro l'\u00e9dition peut faire \u00e9chouer l'insertion<br> ou poser des probl\u00e8mes si vous n'avez pas chang\u00e9<br>le chemin ou les cl\u00e9s du projet !</html>
-jsite.project.warning.use-clipboard-now=<html><b>URI copi\u00e9e</b><br><br>Veuillez noter qu'il est possible qu'en quittant jSite<br>maintenant le presse-papiers soit vid\u00e9. Merci d'utiliser<br>l'URI copi\u00e9e imm\u00e9diatement dans une autre fen\u00eatre !</html>
-
-jsite.project-files.heading=Fichiers du projet
-jsite.project-files.description=<html>Dans cette page vous pouvez sp\u00e9cifier les informations concernant la configuration des noeuds telles que:<br>Le type de contenu mime si l'auto d\u00e9tection \u00e0 \u00e9chou\u00e9e.</html>
-jsite.project-files.action.rescan=Re-scan
-jsite.project-files.action.rescan.tooltip=V\u00e9rifier la pr\u00e9sence de nouveau fichiers
-jsite.project-files.ignore-hidden-files=Ignorer les fichiers cach\u00e9s
-jsite.project-files.ignore-hidden-files.tooltip=Si s\u00e9lectionn\u00e9, les fichiers cach\u00e9s ne sont pas ins\u00e9r\u00e9s
-jsite.project-files.file-options=Option des fichiers
-jsite.project-files.default=Fichier par d\u00e9faut
-jsite.project-files.default.tooltip=Est-ce l'index?
-jsite.project-files.insert=Ins\u00e9rer
-jsite.project-files.insert.tooltip=D\u00e9cochez si vous ne voulez pas ins\u00e9rer ce fichier
-jsite.project-files.force-insert=Forcer l'insertion
-jsite.project-files.force-insert.tooltip=Forcer l'insertion de ce fichier tant qu'il n'est pas modifié
-jsite.project-files.insert-redirect=Redirection
-jsite.project-files.insert-redirect.tooltip=Cochez si vous voulez ins\u00e9rer une redirection pour ce fichier
-jsite.project-files.custom-key=Clef existante
-jsite.project-files.custom-key.tooltip=Utiliser une clef existante pour ce fichier
-jsite.project-files.rename=Renommer
-jsite.project-files.rename.tooltip=Renomme le fichier dans le site ins\u00e9r\u00e9
-jsite.project-files.mime-type=MIME type
-jsite.project-files.mime-type.tooltip=S\u00e9lectionez le type MIME du fichier si la d\u00e9tection \u00e0 \u00e9chou\u00e9e
-jsite.project-files.container=Container
-jsite.project-files.container.tooltip=S\u00e9lectionnez un container pour le fichier
-jsite.project-files.scan-error=<html><b>Erreur lors du parcours des fichiers</b><br><br>Soit le r\u00e9pertoire du projet n'existe pas,<br>ou des fichiers/r\u00e9pertoires sont inaccessibles.<br>Veuillez revenir en arri\u00e8re et s\u00e9lectionner un autre r\u00e9pertoire.</html>
-jsite.project-files.insert-now=Ins\u00e9rer
-jsite.project-files.invalid-default-file=Seulement les fichiers de la racine peuvent être selectionnés comme fichiers par defaut
-
-jsite.update-checker.found-version.title=Nouvelle version disponible
-jsite.update-checker.found-version.message=<html>Une nouvelle version est disponible.<br><br>Version {0} (publi\u00e9e le {1,date})</html>
-jsite.update-checker.latest-version.title=Recherche de mises \u00e0 jour
-jsite.update-checker.latest-version.newer.message=<html>Vous utilisez la version {0} mais une version<br>plus r\u00e9cente ({1}) est disponible!</html>
-jsite.update-checker.latest-version.older.message=<html>Vous utilisez la version {0} mais la<br>derni\u00e8re version semble \u00eatre la {1}.</html>
-jsite.update-checker.latest-version.okay.message=<html>Vous utilisez la version {0}<br>qui semble \u00eatre la derni\u00e8re.</html>
-
-jsite.key-dialog.title=G\u00e9rer les cl\u00e9s des projets
-jsite.key-dialog.button.ok.tooltip=Accepter les changements
-jsite.key-dialog.button.cancel.tooltip=Annuler les changements
-jsite.key-dialog.button.generate=Reg\u00e9n\u00e9rer les cl\u00e9s
-jsite.key-dialog.button.generate.tooltip=Cr\u00e9er une nouvelle paire de cl\u00e9s
-jsite.key-dialog.label.keys=<html><b>Cl\u00e9s</b></html>
-jsite.key-dialog.label.private-key=Cl\u00e9 priv\u00e9e
-jsite.key-dialog.label.public-key=Cl\u00e9 publique
-jsite.key-dialog.label.actions=<html><b>Actions</b></html>
-
-jsite.warning.empty-index=<html><b>Pas de fichier par d\u00e9faut</b><br><br>Avez vous sp\u00e9cifi\u00e9 un fichier par d\u00e9faut pour le projet?<br>M\u00eame s'il est possible de ne pas en sp\u00e9cifier, c'est g\u00e9n\u00e9ralement une mauvaise id\u00e9e.</html>
-jsite.warning.index-not-html=<html><b>Le fichier principal n'est pas un fichier HTML!</b><br><br>Votre fichier par d\u00e9faut n'est pas du type MIME "text/html"!<br>Chargez ce type de fichiers dans un navigateur peut \u00eatre dangereux.</html>
-
-jsite.error.no-node-selected=<html><b>Pas de noeud s\u00e9lectionn\u00e9</b><br><br>S\u00e9lectionnez un noeud dans le menu!</html>
-jsite.error.no-node-running=<html><b>Ce noeud n'est pas actif!</b><br><br>Vous ne pouvez pas utiliser jSite sans noeud actif.<br>Veuillez d\u00e9marrer votre noeud et r\u00e9essayer.</html>
-jsite.error.no-local-path=<html><b>Pas de chemin local sp\u00e9cifi\u00e9</b><br><br>Vous avez omis de sp\u00e9cifier le chemin local \u00e0 ins\u00e9rer.</html>
-jsite.error.no-path=<html><b>Vous n'avez pas sp\u00e9cifi\u00e9 de chemin dans le freesite</b><br><br>Vous n'avez pas sp\u00e9cifi\u00e9 de chemin dans le freesite.<br>Ce champ est n\u00e9cessaire.</html>
-jsite.error.index-missing=<html>Votre fichier par d\u00e9faut est manquant</b><br><br>Un fichier par d\u00e9faut est sp\u00e9cifi\u00e9 mais il<br>n'existe plus ! S\u00e9lectionnez un nouveau<br>fichier par d\u00e9faut dans la liste.</html>
-jsite.error.index-not-inserted=<html><b>Fichier par d\u00e9faut non ins\u00e9r\u00e9</b><br><br>Vous avez choisi de ne pas ins\u00e9rer le fichier par d\u00e9faut !<br>Vous devez soit l'ins\u00e9rer soit choisir<br>un fichier par d\u00e9faut diff\u00e9rent !</html>
-jsite.error.no-custom-key=<html><b>Pas de clef existante sp\u00e9cifi\u00e9e pour ce fichier</b><br><br>Vous avez sp\u00e9cifier de ne pas ins\u00e9rer <code>{0}</code><br> mais n'avez pas sp\u00e9cifier de clef ou rediriger!</html>
-jsite.error.no-files-to-insert=<html><b>Aucun fichier \u00e0 ins\u00e9rer</b><br><br>Vous n'avez s\u00e9lectionn\u00e9 aucun fichier pour l'insertion !<br>Veuillez s\u00e9lectionner au moins un fichier \u00e0 ins\u00e9rer.</html>
-jsite.error.duplicate-file=<html><b>Fichier dupliqu\u00e9</b><br><br>Le fichier <code>{0}</code> est ins\u00e9r\u00e9 deux fois !<br>Veuillez v\u00e9rifier les noms de fichier et les redirections.</html>
+++ /dev/null
-/*
- * jSite - CLI.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.main;
-
-import java.io.PrintWriter;
-
-import de.todesbaum.jsite.application.Freenet7Interface;
-import de.todesbaum.jsite.application.InsertListener;
-import de.todesbaum.jsite.application.Node;
-import de.todesbaum.jsite.application.Project;
-import de.todesbaum.jsite.application.ProjectInserter;
-import de.todesbaum.util.io.StreamCopier.ProgressListener;
-
-/**
- * Command-line interface for jSite.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class CLI implements InsertListener {
-
- /** Object used for synchronization. */
- private Object lockObject = new Object();
-
- /** Writer for the console. */
- private PrintWriter outputWriter = new PrintWriter(System.out, true);
-
- /** The freenet interface. */
- private Freenet7Interface freenetInterface;
-
- /** The project inserter. */
- private ProjectInserter projectInserter = new ProjectInserter();
-
- /** The list of nodes. */
- private Node[] nodes;
-
- /** The projects. */
- private Project[] projects;
-
- /** Whether the insert has finished. */
- private boolean finished = false;
-
- /** Whether the insert finished successfully. */
- private boolean success;
-
- /**
- * Creates a new command-line interface.
- *
- * @param args
- * The command-line arguments
- */
- private CLI(String[] args) {
-
- if ((args.length == 0) || args[0].equals("-h") || args[0].equals("--help")) {
- outputWriter.println("\nParameters:\n");
- outputWriter.println(" --config-file=<configuration file>");
- outputWriter.println(" --node=<node name>");
- outputWriter.println(" --project=<project name>");
- outputWriter.println(" --local-directory=<local directory>");
- outputWriter.println(" --path=<path>");
- outputWriter.println(" --edition=<edition>");
- outputWriter.println("\nA project gets inserted when a new project is loaded on the command line,");
- outputWriter.println("or when the command line is finished. --local-directory, --path, and --edition");
- outputWriter.println("override the parameters in the project.");
- return;
- }
-
- String configFile = System.getProperty("user.home") + "/.jSite/config7";
- for (String argument : args) {
- String value = argument.substring(argument.indexOf('=') + 1).trim();
- if (argument.startsWith("--config-file=")) {
- configFile = value;
- }
- }
-
- ConfigurationLocator configurationLocator = new ConfigurationLocator();
- if (configFile != null) {
- configurationLocator.setCustomLocation(configFile);
- }
- Configuration configuration = new Configuration(configurationLocator, configurationLocator.findPreferredLocation());
-
- projectInserter.addInsertListener(this);
- projects = configuration.getProjects();
- Node node = configuration.getSelectedNode();
- nodes = configuration.getNodes();
-
- freenetInterface = new Freenet7Interface();
- freenetInterface.setNode(node);
-
- projectInserter.setFreenetInterface(freenetInterface);
-
- Project currentProject = null;
- for (String argument : args) {
- if (argument.startsWith("--config-file=")) {
- /* we already parsed this one. */
- continue;
- }
- String value = argument.substring(argument.indexOf('=') + 1).trim();
- if (argument.startsWith("--node=")) {
- Node newNode = getNode(value);
- if (newNode == null) {
- outputWriter.println("Node \"" + value + "\" not found.");
- return;
- }
- node = newNode;
- freenetInterface.setNode(node);
- } else if (argument.startsWith("--project=")) {
- if (currentProject != null) {
- if (insertProject(currentProject)) {
- outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted.");
- } else {
- outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted.");
- }
- currentProject = null;
- }
- currentProject = getProject(value);
- if (currentProject == null) {
- outputWriter.println("Project \"" + value + "\" not found.");
- }
- } else if (argument.startsWith("--local-directory")) {
- if (currentProject == null) {
- outputWriter.println("You can't specifiy --local-directory before --project.");
- return;
- }
- currentProject.setLocalPath(value);
- } else if (argument.startsWith("--path=")) {
- if (currentProject == null) {
- outputWriter.println("You can't specify --path before --project.");
- return;
- }
- currentProject.setPath(value);
- } else if (argument.startsWith("--edition=")) {
- if (currentProject == null) {
- outputWriter.println("You can't specify --edition before --project.");
- return;
- }
- currentProject.setEdition(Integer.parseInt(value));
- } else {
- outputWriter.println("Unknown parameter: " + argument);
- return;
- }
- }
-
- int errorCode = 1;
- if (currentProject != null) {
- if (insertProject(currentProject)) {
- outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted.");
- errorCode = 0;
- } else {
- outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted.");
- }
- }
-
- configuration.setProjects(projects);
- configuration.save();
-
- System.exit(errorCode);
- }
-
- /**
- * Returns the project with the given name.
- *
- * @param name
- * The name of the project
- * @return The project, or <code>null</code> if no project could be found
- */
- private Project getProject(String name) {
- for (Project project : projects) {
- if (project.getName().equals(name)) {
- return project;
- }
- }
- return null;
- }
-
- /**
- * Returns the node with the given name.
- *
- * @param name
- * The name of the node
- * @return The node, or <code>null</code> if no node could be found
- */
- private Node getNode(String name) {
- for (Node node : nodes) {
- if (node.getName().equals(name)) {
- return node;
- }
- }
- return null;
- }
-
- /**
- * Inserts the given project.
- *
- * @param currentProject
- * The project to insert
- * @return <code>true</code> if the insert finished successfully,
- * <code>false</code> otherwise
- */
- private boolean insertProject(Project currentProject) {
- if (!freenetInterface.hasNode()) {
- outputWriter.println("Node is not running!");
- return false;
- }
- projectInserter.setProject(currentProject);
- projectInserter.start(new ProgressListener() {
-
- public void onProgress(long copied, long length) {
- System.out.print("Uploaded: " + copied + " / " + length + " bytes...\r");
- }
- });
- synchronized (lockObject) {
- while (!finished) {
- try {
- lockObject.wait();
- } catch (InterruptedException e) {
- /* ignore, we're in a loop. */
- }
- }
- }
- return success;
- }
-
- //
- // INTERFACE InsertListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void projectInsertStarted(Project project) {
- outputWriter.println("Starting Insert of project \"" + project.getName() + "\".");
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectUploadFinished(Project project) {
- outputWriter.println("Project \"" + project.getName() + "\" has been uploaded, starting insert...");
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectURIGenerated(Project project, String uri) {
- outputWriter.println("URI: " + uri);
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized) {
- outputWriter.println("Progress: " + succeeded + " done, " + failed + " failed, " + fatal + " fatal, " + total + " total" + (finalized ? " (finalized)" : "") + ", " + ((succeeded + failed + fatal) * 100 / total) + "%");
- }
-
- /**
- * {@inheritDoc}
- */
- public void projectInsertFinished(Project project, boolean success, Throwable cause) {
- outputWriter.println("Request URI: " + project.getFinalRequestURI(0));
- finished = true;
- this.success = success;
- synchronized (lockObject) {
- lockObject.notify();
- }
- }
-
- //
- // MAIN
- //
-
- /**
- * Creates a new command-line interface with the given arguments.
- *
- * @param args
- * The command-line arguments
- */
- public static void main(String[] args) {
- new CLI(args);
- }
-
-}
+++ /dev/null
-/*
- * jSite - Configuration.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.main;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-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.freenet.fcp2.ClientPutDir.ManifestPutter;
-import de.todesbaum.util.freenet.fcp2.PriorityClass;
-import de.todesbaum.util.io.Closer;
-import de.todesbaum.util.io.StreamCopier;
-import de.todesbaum.util.xml.SimpleXML;
-import de.todesbaum.util.xml.XML;
-
-/**
- * The configuration.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class Configuration {
-
- /** The root node of the configuration. */
- private SimpleXML rootNode;
-
- /** The configuration locator. */
- private final ConfigurationLocator configurationLocator;
-
- /** Where the configuration resides. */
- private ConfigurationLocation configurationLocation;
-
- /**
- * Creates a new configuration that is read from the given file.
- *
- * @param configurationLocator
- * The configuration locator
- * @param configurationLocation
- * The configuration directory
- */
- public Configuration(ConfigurationLocator configurationLocator, ConfigurationLocation configurationLocation) {
- this.configurationLocator = configurationLocator;
- this.configurationLocation = configurationLocation;
- readConfiguration(configurationLocator.getFile(configurationLocation));
- }
-
- //
- // ACCESSORS
- //
-
- /**
- * Returns the configuration locator.
- *
- * @return The configuration locator
- */
- public ConfigurationLocator getConfigurationLocator() {
- return configurationLocator;
- }
-
- /**
- * Returns the location the configuration will be written to when calling
- * {@link #save()}.
- *
- * @return The location the configuration will be written to
- */
- public ConfigurationLocation getConfigurationDirectory() {
- return configurationLocation;
- }
-
- /**
- * Sets the location the configuration will be written to when calling
- * {@link #save()}.
- *
- * @param configurationLocation
- * The location to write the configuration to
- */
- 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(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");
- }
-
- /**
- * Saves the configuration.
- *
- * @return <code>true</code> if the configuration could be saved,
- * <code>false</code> otherwise
- */
- public boolean save() {
- 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()) {
- return false;
- }
- }
- FileOutputStream fileOutputStream = null;
- ByteArrayInputStream configurationInputStream = null;
- try {
- byte[] configurationBytes = XML.transformToByteArray(rootNode.getDocument());
- configurationInputStream = new ByteArrayInputStream(configurationBytes);
- fileOutputStream = new FileOutputStream(configurationFile);
- StreamCopier.copy(configurationInputStream, fileOutputStream, configurationBytes.length);
- return true;
- } catch (IOException ioe1) {
- /* ignore. */
- } finally {
- Closer.close(configurationInputStream);
- Closer.close(fileOutputStream);
- }
- return false;
- }
-
- /**
- * Returns the value of a node.
- *
- * @param nodeNames
- * The name of all nodes in the chain
- * @param defaultValue
- * The default value to return if the node could not be found
- * @return The value of the node, or the default value if the node could not
- * be found
- */
- private String getNodeValue(String[] nodeNames, String defaultValue) {
- SimpleXML node = rootNode;
- int nodeIndex = 0;
- while ((node != null) && (nodeIndex < nodeNames.length)) {
- node = node.getNode(nodeNames[nodeIndex++]);
- }
- if (node == null) {
- return defaultValue;
- }
- return node.getValue();
- }
-
- /**
- * Returns the integer value of a node.
- *
- * @param nodeNames
- * The names of all nodes in the chain
- * @param defaultValue
- * The default value to return if the node can not be found
- * @return The parsed integer value, or the default value if the node can
- * not be found or the value can not be parsed into an integer
- */
- private int getNodeIntValue(String[] nodeNames, int defaultValue) {
- try {
- return Integer.parseInt(getNodeValue(nodeNames, String.valueOf(defaultValue)));
- } catch (NumberFormatException nfe1) {
- /* ignore. */
- }
- return defaultValue;
- }
-
- /**
- * Returns the boolean value of a node.
- *
- * @param nodeNames
- * The names of all nodes in the chain
- * @param defaultValue
- * The default value to return if the node can not be found
- * @return The parsed boolean value, or the default value if the node can
- * not be found
- */
- private boolean getNodeBooleanValue(String[] nodeNames, boolean defaultValue) {
- String nodeValue = getNodeValue(nodeNames, null);
- if (nodeValue == null) {
- return defaultValue;
- }
- return Boolean.parseBoolean(nodeValue);
- }
-
- /**
- * Returns the hostname of the node.
- *
- * @return The hostname of the node
- * @deprecated Use {@link #getSelectedNode()} instead
- */
- @Deprecated
- public String getNodeAddress() {
- return getNodeValue(new String[] { "node-address" }, "localhost");
- }
-
- /**
- * Sets the hostname of the node.
- *
- * @param nodeAddress
- * The hostname of the node
- * @deprecated Use {@link #setSelectedNode(Node)} instead
- */
- @Deprecated
- public void setNodeAddress(String nodeAddress) {
- rootNode.replace("node-address", nodeAddress);
- }
-
- /**
- * The port number of the node
- *
- * @return The port number of the node
- * @deprecated Use {@link #getSelectedNode()} instead.
- */
- @Deprecated
- public int getNodePort() {
- return getNodeIntValue(new String[] { "node-port" }, 9481);
- }
-
- /**
- * Sets the port number of the node.
- *
- * @param nodePort
- * The port number of the node
- * @deprecated Use {@link #setSelectedNode(Node)} instead
- */
- @Deprecated
- public void setNodePort(int nodePort) {
- rootNode.replace("node-port", String.valueOf(nodePort));
- }
-
- /**
- * Returns whether the node configuration page should be skipped on startup.
- *
- * @return <code>true</code> to skip the node configuration page on startup,
- * <code>false</code> to show it
- */
- public boolean isSkipNodePage() {
- return getNodeBooleanValue(new String[] { "skip-node-page" }, false);
- }
-
- /**
- * Sets whether the node configuration page should be skipped on startup.
- *
- * @param skipNodePage
- * <code>true</code> to skip the node configuration page on
- * startup, <code>false</code> to show it
- */
- public void setSkipNodePage(boolean skipNodePage) {
- rootNode.replace("skip-node-page", String.valueOf(skipNodePage));
- }
-
- /**
- * Returns all configured projects.
- *
- * @return A list of all projects
- */
- public Project[] getProjects() {
- List<Project> projects = new ArrayList<Project>();
- SimpleXML projectsNode = rootNode.getNode("project-list");
- if (projectsNode != null) {
- SimpleXML[] projectNodes = projectsNode.getNodes("project");
- for (SimpleXML projectNode : projectNodes) {
- try {
- Project project = new Project();
- projects.add(project);
- project.setDescription(projectNode.getNode("description").getValue(""));
- String indexFile = projectNode.getNode("index-file").getValue("");
- if (indexFile.indexOf('/') > -1) {
- indexFile = "";
- }
- project.setIndexFile(indexFile);
- project.setLastInsertionTime(Long.parseLong(projectNode.getNode("last-insertion-time").getValue("0")));
- project.setLocalPath(projectNode.getNode("local-path").getValue(""));
- project.setName(projectNode.getNode("name").getValue(""));
- project.setPath(projectNode.getNode("path").getValue(""));
- if ((project.getPath() != null) && (project.getPath().indexOf("/") != -1)) {
- project.setPath(project.getPath().replaceAll("/", ""));
- }
- project.setEdition(Integer.parseInt(projectNode.getNode("edition").getValue("0")));
- project.setInsertURI(projectNode.getNode("insert-uri").getValue(""));
- project.setRequestURI(projectNode.getNode("request-uri").getValue(""));
- if (projectNode.getNode("ignore-hidden-files") != null) {
- project.setIgnoreHiddenFiles(Boolean.parseBoolean(projectNode.getNode("ignore-hidden-files").getValue("true")));
- } else {
- project.setIgnoreHiddenFiles(true);
- }
-
- /* load last insert hashes. */
- Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
- SimpleXML lastInsertHashesNode = projectNode.getNode("last-insert-hashes");
- if (lastInsertHashesNode != null) {
- for (SimpleXML fileNode : lastInsertHashesNode.getNodes("file")) {
- String filename = fileNode.getNode("filename").getValue();
- String lastInsertHash = fileNode.getNode("last-insert-hash").getValue();
- int lastInsertEdition = Integer.valueOf(fileNode.getNode("last-insert-edition").getValue());
- String lastInsertFilename = filename;
- if (fileNode.getNode("last-insert-filename") != null) {
- lastInsertFilename = fileNode.getNode("last-insert-filename").getValue();
- }
- FileOption fileOption = project.getFileOption(filename);
- fileOption.setLastInsertHash(lastInsertHash).setLastInsertEdition(lastInsertEdition).setLastInsertFilename(lastInsertFilename);
- fileOptions.put(filename, fileOption);
- }
- }
-
- SimpleXML fileOptionsNode = projectNode.getNode("file-options");
- if (fileOptionsNode != null) {
- SimpleXML[] fileOptionNodes = fileOptionsNode.getNodes("file-option");
- for (SimpleXML fileOptionNode : fileOptionNodes) {
- String filename = fileOptionNode.getNode("filename").getValue();
- FileOption fileOption = project.getFileOption(filename);
- fileOption.setInsert(Boolean.parseBoolean(fileOptionNode.getNode("insert").getValue()));
- if (fileOptionNode.getNode("insert-redirect") != null) {
- fileOption.setInsertRedirect(Boolean.parseBoolean(fileOptionNode.getNode("insert-redirect").getValue()));
- }
- fileOption.setCustomKey(fileOptionNode.getNode("custom-key").getValue(""));
- if (fileOptionNode.getNode("changed-name") != null) {
- fileOption.setChangedName(fileOptionNode.getNode("changed-name").getValue());
- }
- fileOption.setMimeType(fileOptionNode.getNode("mime-type").getValue(""));
- fileOptions.put(filename, fileOption);
- }
- }
- project.setFileOptions(fileOptions);
- } catch (NumberFormatException nfe1) {
- nfe1.printStackTrace();
- }
- }
- }
- return projects.toArray(new Project[projects.size()]);
- }
-
- /**
- * Sets the list of all projects.
- *
- * @param projects
- * The list of all projects
- */
- public void setProjects(Project[] projects) {
- SimpleXML projectsNode = new SimpleXML("project-list");
- for (Project project : projects) {
- SimpleXML projectNode = projectsNode.append("project");
- projectNode.append("edition", String.valueOf(project.getEdition()));
- projectNode.append("description", project.getDescription());
- projectNode.append("index-file", project.getIndexFile());
- projectNode.append("last-insertion-time", String.valueOf(project.getLastInsertionTime()));
- projectNode.append("local-path", project.getLocalPath());
- projectNode.append("name", project.getName());
- projectNode.append("path", project.getPath());
- projectNode.append("insert-uri", project.getInsertURI());
- projectNode.append("request-uri", project.getRequestURI());
- projectNode.append("ignore-hidden-files", String.valueOf(project.isIgnoreHiddenFiles()));
-
- /* store last insert hashes. */
- SimpleXML lastInsertHashesNode = projectNode.append("last-insert-hashes");
- for (Entry<String, FileOption> fileOption : project.getFileOptions().entrySet()) {
- if ((fileOption.getValue().getLastInsertHash() == null) || (fileOption.getValue().getLastInsertHash().length() == 0)) {
- continue;
- }
- SimpleXML fileNode = lastInsertHashesNode.append("file");
- fileNode.append("filename", fileOption.getKey());
- fileNode.append("last-insert-hash", fileOption.getValue().getLastInsertHash());
- fileNode.append("last-insert-edition", String.valueOf(fileOption.getValue().getLastInsertEdition()));
- fileNode.append("last-insert-filename", fileOption.getValue().getLastInsertFilename());
- }
-
- SimpleXML fileOptionsNode = projectNode.append("file-options");
- Iterator<Entry<String, FileOption>> entries = project.getFileOptions().entrySet().iterator();
- while (entries.hasNext()) {
- Entry<String, FileOption> entry = entries.next();
- FileOption fileOption = entry.getValue();
- if (fileOption.isCustom()) {
- SimpleXML fileOptionNode = fileOptionsNode.append("file-option");
- fileOptionNode.append("filename", entry.getKey());
- fileOptionNode.append("insert", String.valueOf(fileOption.isInsert()));
- fileOptionNode.append("insert-redirect", String.valueOf(fileOption.isInsertRedirect()));
- fileOptionNode.append("custom-key", fileOption.getCustomKey());
- fileOptionNode.append("changed-name", fileOption.getChangedName());
- fileOptionNode.append("mime-type", fileOption.getMimeType());
- }
- }
- }
- rootNode.replace(projectsNode);
- }
-
- /**
- * Returns the stored locale.
- *
- * @return The stored locale
- */
- public Locale getLocale() {
- String language = getNodeValue(new String[] { "i18n", "language" }, "en");
- String country = getNodeValue(new String[] { "i18n", "country" }, null);
- if (country != null) {
- return new Locale(language, country);
- }
- return new Locale(language);
- }
-
- /**
- * Sets the locale to store.
- *
- * @param locale
- * The locale to store
- */
- public void setLocale(Locale locale) {
- SimpleXML i18nNode = new SimpleXML("i18n");
- if (locale.getCountry().length() != 0) {
- i18nNode.append("country", locale.getCountry());
- }
- i18nNode.append("language", locale.getLanguage());
- rootNode.replace(i18nNode);
- return;
- }
-
- /**
- * Returns a list of configured nodes.
- *
- * @return The list of the configured nodes
- */
- public Node[] getNodes() {
- SimpleXML nodesNode = rootNode.getNode("nodes");
- if (nodesNode == null) {
- String hostname = getNodeAddress();
- int port = getNodePort();
- if (hostname == null) {
- hostname = "127.0.0.1";
- port = 9481;
- }
- return new Node[] { new Node(hostname, port, "Node") };
- }
- SimpleXML[] nodeNodes = nodesNode.getNodes("node");
- Node[] returnNodes = new Node[nodeNodes.length];
- int nodeIndex = 0;
- for (SimpleXML nodeNode : nodeNodes) {
- String name = nodeNode.getNode("name").getValue();
- String hostname = nodeNode.getNode("hostname").getValue();
- int port = Integer.parseInt(nodeNode.getNode("port").getValue());
- Node node = new Node(hostname, port, name);
- returnNodes[nodeIndex++] = node;
- }
- return returnNodes;
- }
-
- /**
- * Sets the list of configured nodes.
- *
- * @param nodes
- * The list of configured nodes
- */
- public void setNodes(Node[] nodes) {
- SimpleXML nodesNode = new SimpleXML("nodes");
- for (Node node : nodes) {
- SimpleXML nodeNode = nodesNode.append("node");
- nodeNode.append("name", node.getName());
- nodeNode.append("hostname", node.getHostname());
- nodeNode.append("port", String.valueOf(node.getPort()));
- }
- rootNode.replace(nodesNode);
- rootNode.remove("node-address");
- rootNode.remove("node-port");
- }
-
- /**
- * Sets the selected node.
- *
- * @param selectedNode
- * The selected node
- */
- public void setSelectedNode(Node selectedNode) {
- SimpleXML selectedNodeNode = new SimpleXML("selected-node");
- selectedNodeNode.append("name", selectedNode.getName());
- selectedNodeNode.append("hostname", selectedNode.getHostname());
- selectedNodeNode.append("port", String.valueOf(selectedNode.getPort()));
- rootNode.replace(selectedNodeNode);
- }
-
- /**
- * Returns the selected node.
- *
- * @return The selected node
- */
- public Node getSelectedNode() {
- SimpleXML selectedNodeNode = rootNode.getNode("selected-node");
- if (selectedNodeNode == null) {
- String hostname = getNodeAddress();
- int port = getNodePort();
- if (hostname == null) {
- hostname = "127.0.0.1";
- port = 9481;
- }
- return new Node(hostname, port, "Node");
- }
- String name = selectedNodeNode.getNode("name").getValue();
- String hostname = selectedNodeNode.getNode("hostname").getValue();
- int port = Integer.valueOf(selectedNodeNode.getNode("port").getValue());
- return new Node(hostname, port, name);
- }
-
- /**
- * Returns the temp directory to use.
- *
- * @return The temp directoy, or {@code null} to use the default temp
- * directory
- */
- public String getTempDirectory() {
- return getNodeValue(new String[] { "temp-directory" }, null);
- }
-
- /**
- * Sets the temp directory to use.
- *
- * @param tempDirectory
- * The temp directory to use, or {@code null} to use the default
- * temp directory
- */
- public void setTempDirectory(String tempDirectory) {
- if (tempDirectory != null) {
- SimpleXML tempDirectoryNode = new SimpleXML("temp-directory");
- tempDirectoryNode.setValue(tempDirectory);
- rootNode.replace(tempDirectoryNode);
- } else {
- rootNode.remove("temp-directory");
- }
- }
-
- /**
- * Returns whether to use the “early encode“ flag for the insert.
- *
- * @return {@code true} to set the “early encode” flag for the insert,
- * {@code false} otherwise
- */
- public boolean useEarlyEncode() {
- return getNodeBooleanValue(new String[] { "use-early-encode" }, false);
- }
-
- /**
- * Sets whether to use the “early encode“ flag for the insert.
- *
- * @param useEarlyEncode
- * {@code true} to set the “early encode” flag for the insert,
- * {@code false} otherwise
- * @return This configuration
- */
- public Configuration setUseEarlyEncode(boolean useEarlyEncode) {
- rootNode.replace("use-early-encode", String.valueOf(useEarlyEncode));
- return this;
- }
-
- /**
- * Returns the insert priority.
- *
- * @return The insert priority
- */
- public PriorityClass getPriority() {
- return PriorityClass.valueOf(getNodeValue(new String[] { "insert-priority" }, "interactive"));
- }
-
- /**
- * Sets the insert priority.
- *
- * @param priority
- * The insert priority
- * @return This configuration
- */
- public Configuration setPriority(PriorityClass priority) {
- rootNode.replace("insert-priority", priority.toString());
- return this;
- }
-
- /**
- * Returns the manifest putter.
- *
- * @return The manifest putter
- */
- public ManifestPutter getManifestPutter() {
- return ManifestPutter.valueOf(getNodeValue(new String[] { "manifest-putter" }, "simple").toUpperCase());
- }
-
- /**
- * Sets the manifest putter.
- *
- * @param manifestPutter
- * The manifest putter
- * @return This configuration
- */
- public Configuration setManifestPutter(ManifestPutter manifestPutter) {
- rootNode.replace("manifest-putter", manifestPutter.name().toLowerCase());
- return this;
- }
-
-}
+++ /dev/null
-/*
- * jSite - ConfigurationLocator.java - Copyright © 2011–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.main;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Locator for configuration files in different places.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class ConfigurationLocator {
-
- /**
- * The location of the configuration directory.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
- public enum ConfigurationLocation {
-
- /** 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,
-
- /** Custom location. */
- CUSTOM,
-
- }
-
- /** The possible configuration locations. */
- private final Map<ConfigurationLocation, String> configurationFiles = new HashMap<ConfigurationLocation, String>();
-
- /**
- * Creates a new configuration locator. If this class is loaded from a JAR
- * file, {@link ConfigurationLocation#NEXT_TO_JAR_FILE} is added to the list
- * of possible configuration file locations.
- * {@link ConfigurationLocation#HOME_DIRECTORY} is always added to this
- * list, {@link ConfigurationLocation#CUSTOM} has to be enabled by calling
- * {@link #setCustomLocation(String)}.
- */
- public ConfigurationLocator() {
- /* are we executed from a JAR file? */
- String resource = getClass().getResource("/" + getClass().getName().replace(".", "/") + ".class").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");
- configurationFiles.put(ConfigurationLocation.NEXT_TO_JAR_FILE, configurationFile.getPath());
- }
- File homeDirectoryFile = new File(System.getProperty("user.home"), ".jSite/config7");
- configurationFiles.put(ConfigurationLocation.HOME_DIRECTORY, homeDirectoryFile.getPath());
- }
-
- //
- // ACCESSORS
- //
-
- /**
- * Sets the location of the custom configuration file.
- *
- * @param customFile
- * The custom location of the configuration file
- */
- public void setCustomLocation(String customFile) {
- configurationFiles.put(ConfigurationLocation.CUSTOM, customFile);
- }
-
- /**
- * Returns whether the given location is valid. Certain locations (such as
- * {@link ConfigurationLocation#NEXT_TO_JAR_FILE}) may be invalid in certain
- * circumstances (such as the application not being run from a JAR file). A
- * location being valid does not imply that a configuration file does exist
- * at the given location, use {@link #hasFile(ConfigurationLocation)} to
- * check for a configuration file at the desired location.
- *
- * @param configurationLocation
- * The configuration location
- * @return {@code true} if the location is valid, {@code false} otherwise
- */
- public boolean isValidLocation(ConfigurationLocation configurationLocation) {
- return configurationFiles.containsKey(configurationLocation);
- }
-
- /**
- * Checks whether a configuration file exists at the given location.
- *
- * @param configurationLocation
- * The configuration location
- * @return {@code true} if a configuration file exists at the given
- * location, {@code false} otherwise
- */
- public boolean hasFile(ConfigurationLocation configurationLocation) {
- if (!isValidLocation(configurationLocation)) {
- return false;
- }
- return new File(configurationFiles.get(configurationLocation)).exists();
- }
-
- /**
- * Returns the configuration file for the given location.
- *
- * @param configurationLocation
- * The location to get the file for
- * @return The name of the configuration file at the given location, or
- * {@code null} if the given location is invalid
- */
- public String getFile(ConfigurationLocation configurationLocation) {
- return configurationFiles.get(configurationLocation);
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Finds the preferred location of the configuration file.
- *
- * @see #findPreferredLocation(ConfigurationLocation)
- * @return The preferred location of the configuration file
- */
- public ConfigurationLocation findPreferredLocation() {
- return findPreferredLocation(ConfigurationLocation.NEXT_TO_JAR_FILE);
- }
-
- /**
- * Finds the preferred location of the configuration file. The following
- * checks are performed: if a custom configuration location has been defined
- * (by calling {@link #setCustomLocation(String)})
- * {@link ConfigurationLocation#CUSTOM} is returned. If the application is
- * run from a JAR file and a configuration file is found next to the JAR
- * file (i.e. in the same directory),
- * {@link ConfigurationLocation#NEXT_TO_JAR_FILE} is returned. If a
- * configuration file exists in the user’s home directory,
- * {@link ConfigurationLocation#HOME_DIRECTORY} is returned. Otherwise, the
- * given {@code defaultLocation} is returned.
- *
- * @param defaultLocation
- * The default location to return if no other configuration file
- * is found
- * @return The configuration location to load the configuration from
- */
- public ConfigurationLocation findPreferredLocation(ConfigurationLocation defaultLocation) {
- if (hasFile(ConfigurationLocation.CUSTOM)) {
- return ConfigurationLocation.CUSTOM;
- }
- if (hasFile(ConfigurationLocation.NEXT_TO_JAR_FILE)) {
- return ConfigurationLocation.NEXT_TO_JAR_FILE;
- }
- if (hasFile(ConfigurationLocation.HOME_DIRECTORY)) {
- return ConfigurationLocation.HOME_DIRECTORY;
- }
- if (isValidLocation(defaultLocation)) {
- return defaultLocation;
- }
- return ConfigurationLocation.HOME_DIRECTORY;
- }
-
-}
+++ /dev/null
-/*
- * jSite - Main.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.main;
-
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.ButtonGroup;
-import javax.swing.Icon;
-import javax.swing.JList;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-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.ProjectInserter.CheckReport;
-import de.todesbaum.jsite.application.ProjectInserter.Issue;
-import de.todesbaum.jsite.application.UpdateChecker;
-import de.todesbaum.jsite.application.UpdateListener;
-import de.todesbaum.jsite.gui.NodeManagerListener;
-import de.todesbaum.jsite.gui.NodeManagerPage;
-import de.todesbaum.jsite.gui.PreferencesPage;
-import de.todesbaum.jsite.gui.ProjectFilesPage;
-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.ConfigurationLocator.ConfigurationLocation;
-import de.todesbaum.util.image.IconLoader;
-import de.todesbaum.util.swing.TWizard;
-import de.todesbaum.util.swing.TWizardPage;
-import de.todesbaum.util.swing.WizardListener;
-
-/**
- * The main class that ties together everything.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class Main implements ActionListener, ListSelectionListener, WizardListener, NodeManagerListener, UpdateListener {
-
- /** The logger. */
- private static final Logger logger = Logger.getLogger(Main.class.getName());
-
- /** The version. */
- private static final Version VERSION = new Version(0, 10);
-
- /** The configuration. */
- private Configuration configuration;
-
- /** The freenet interface. */
- private Freenet7Interface freenetInterface = new Freenet7Interface();
-
- /** The update checker. */
- private final UpdateChecker updateChecker;
-
- /** The jSite icon. */
- private Icon jSiteIcon;
-
- /**
- * Enumeration for all possible pages.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
- private static enum PageType {
-
- /** The node manager page. */
- PAGE_NODE_MANAGER,
-
- /** The project page. */
- PAGE_PROJECTS,
-
- /** The project files page. */
- PAGE_PROJECT_FILES,
-
- /** The project insert page. */
- PAGE_INSERT_PROJECT,
-
- /** The preferences page. */
- PAGE_PREFERENCES
-
- }
-
- /** The supported locales. */
- private static final Locale[] SUPPORTED_LOCALES = new Locale[] { Locale.ENGLISH, Locale.GERMAN, Locale.FRENCH };
-
- /** The actions that switch the language. */
- private Map<Locale, Action> languageActions = new HashMap<Locale, Action>();
-
- /** The “manage nodes” action. */
- private Action manageNodeAction;
-
- /** The “preferences” action. */
- private Action optionsPreferencesAction;
-
- /** The “check for updates” action. */
- private Action checkForUpdatesAction;
-
- /** The “about jSite” action. */
- private Action aboutAction;
-
- /** The wizard. */
- private TWizard wizard;
-
- /** The node menu. */
- private JMenu nodeMenu;
-
- /** The currently selected node. */
- private Node selectedNode;
-
- /** Mapping from page type to page. */
- private final Map<PageType, TWizardPage> pages = new HashMap<PageType, TWizardPage>();
-
- /** The original location of the configuration file. */
- private ConfigurationLocation originalLocation;
-
- /**
- * Creates a new core with the default configuration file.
- */
- private Main() {
- this(null);
- }
-
- /**
- * Creates a new core with the given configuration from the given file.
- *
- * @param configFilename
- * The name of the configuration file
- */
- private Main(String configFilename) {
- /* collect all possible configuration file locations. */
- ConfigurationLocator configurationLocator = new ConfigurationLocator();
- if (configFilename != null) {
- configurationLocator.setCustomLocation(configFilename);
- }
-
- originalLocation = configurationLocator.findPreferredLocation();
- logger.log(Level.CONFIG, "Using configuration from " + originalLocation + ".");
- configuration = new Configuration(configurationLocator, originalLocation);
-
- Locale.setDefault(configuration.getLocale());
- I18n.setLocale(configuration.getLocale());
- wizard = new TWizard();
- createActions();
- wizard.setJMenuBar(createMenuBar());
- wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
- wizard.setPreviousEnabled(false);
- wizard.setNextEnabled(true);
- wizard.addWizardListener(this);
- jSiteIcon = IconLoader.loadIcon("/jsite-icon.png");
- wizard.setIcon(jSiteIcon);
-
- updateChecker = new UpdateChecker(freenetInterface);
- updateChecker.addUpdateListener(this);
- updateChecker.start();
-
- initPages();
- showPage(PageType.PAGE_PROJECTS);
- }
-
- /**
- * Creates all actions.
- */
- private void createActions() {
- for (final Locale locale : SUPPORTED_LOCALES) {
- languageActions.put(locale, new AbstractAction(I18n.getMessage("jsite.menu.language." + locale.getLanguage()), IconLoader.loadIcon("/flag-" + locale.getLanguage() + ".png")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- switchLanguage(locale);
- }
- });
- }
- manageNodeAction = new AbstractAction(I18n.getMessage("jsite.menu.nodes.manage-nodes")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- showPage(PageType.PAGE_NODE_MANAGER);
- optionsPreferencesAction.setEnabled(true);
- wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
- wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
- }
- };
- optionsPreferencesAction = new AbstractAction(I18n.getMessage("jsite.menu.options.preferences")) {
-
- /**
- * {@inheritDoc}
- */
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- optionsPreferences();
- }
- };
- checkForUpdatesAction = new AbstractAction(I18n.getMessage("jsite.menu.help.check-for-updates")) {
-
- /**
- * {@inheritDoc}
- */
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- showLatestUpdate();
- }
- };
- aboutAction = new AbstractAction(I18n.getMessage("jsite.menu.help.about")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent e) {
- JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.about.message"), getVersion().toString()), null, JOptionPane.INFORMATION_MESSAGE, jSiteIcon);
- }
- };
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- manageNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.nodes.manage-nodes"));
- optionsPreferencesAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.options.preferences"));
- checkForUpdatesAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.help.check-for-updates"));
- aboutAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.help.about"));
- }
- });
- }
-
- /**
- * Creates the menu bar.
- *
- * @return The menu bar
- */
- private JMenuBar createMenuBar() {
- JMenuBar menuBar = new JMenuBar();
- final JMenu languageMenu = new JMenu(I18n.getMessage("jsite.menu.languages"));
- menuBar.add(languageMenu);
- ButtonGroup languageButtonGroup = new ButtonGroup();
- for (Locale locale : SUPPORTED_LOCALES) {
- Action languageAction = languageActions.get(locale);
- JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(languageActions.get(locale));
- if (locale.equals(Locale.getDefault())) {
- menuItem.setSelected(true);
- }
- languageAction.putValue("menuItem", menuItem);
- languageButtonGroup.add(menuItem);
- languageMenu.add(menuItem);
- }
- nodeMenu = new JMenu(I18n.getMessage("jsite.menu.nodes"));
- menuBar.add(nodeMenu);
- selectedNode = configuration.getSelectedNode();
- nodesUpdated(configuration.getNodes());
-
- final JMenu optionsMenu = new JMenu(I18n.getMessage("jsite.menu.options"));
- menuBar.add(optionsMenu);
- optionsMenu.add(optionsPreferencesAction);
-
- /* evil hack to right-align the help menu */
- JPanel panel = new JPanel();
- panel.setOpaque(false);
- menuBar.add(panel);
-
- final JMenu helpMenu = new JMenu(I18n.getMessage("jsite.menu.help"));
- menuBar.add(helpMenu);
- helpMenu.add(checkForUpdatesAction);
- helpMenu.add(aboutAction);
-
- I18nContainer.getInstance().registerRunnable(new Runnable() {
-
- @SuppressWarnings("synthetic-access")
- public void run() {
- languageMenu.setText(I18n.getMessage("jsite.menu.languages"));
- nodeMenu.setText(I18n.getMessage("jsite.menu.nodes"));
- optionsMenu.setText(I18n.getMessage("jsite.menu.options"));
- helpMenu.setText(I18n.getMessage("jsite.menu.help"));
- for (Map.Entry<Locale, Action> languageActionEntry : languageActions.entrySet()) {
- languageActionEntry.getValue().putValue(Action.NAME, I18n.getMessage("jsite.menu.language." + languageActionEntry.getKey().getLanguage()));
- }
- }
- });
-
- return menuBar;
- }
-
- /**
- * Initializes all pages.
- */
- private void initPages() {
- NodeManagerPage nodeManagerPage = new NodeManagerPage(wizard);
- nodeManagerPage.setName("page.node-manager");
- nodeManagerPage.addNodeManagerListener(this);
- nodeManagerPage.setNodes(configuration.getNodes());
- pages.put(PageType.PAGE_NODE_MANAGER, nodeManagerPage);
-
- ProjectPage projectPage = new ProjectPage(wizard);
- projectPage.setName("page.project");
- projectPage.setProjects(configuration.getProjects());
- projectPage.setFreenetInterface(freenetInterface);
- projectPage.addListSelectionListener(this);
- pages.put(PageType.PAGE_PROJECTS, projectPage);
-
- ProjectFilesPage projectFilesPage = new ProjectFilesPage(wizard);
- projectFilesPage.setName("page.project.files");
- pages.put(PageType.PAGE_PROJECT_FILES, projectFilesPage);
-
- ProjectInsertPage projectInsertPage = new ProjectInsertPage(wizard);
- projectInsertPage.setName("page.project.insert");
- projectInsertPage.setFreenetInterface(freenetInterface);
- pages.put(PageType.PAGE_INSERT_PROJECT, projectInsertPage);
-
- PreferencesPage preferencesPage = new PreferencesPage(wizard);
- preferencesPage.setName("page.preferences");
- preferencesPage.setTempDirectory(configuration.getTempDirectory());
- pages.put(PageType.PAGE_PREFERENCES, preferencesPage);
- }
-
- /**
- * Shows the page with the given type.
- *
- * @param pageType
- * The page type to show
- */
- private void showPage(PageType pageType) {
- wizard.setPreviousEnabled(pageType.ordinal() > 0);
- wizard.setNextEnabled(pageType.ordinal() < (pages.size() - 1));
- wizard.setPage(pages.get(pageType));
- wizard.setTitle(pages.get(pageType).getHeading() + " - jSite");
- }
-
- /**
- * 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,
- * <code>false</code> otherwise
- */
- private boolean saveConfiguration() {
- NodeManagerPage nodeManagerPage = (NodeManagerPage) pages.get(PageType.PAGE_NODE_MANAGER);
- configuration.setNodes(nodeManagerPage.getNodes());
- if (selectedNode != null) {
- configuration.setSelectedNode(selectedNode);
- }
-
- ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
- configuration.setProjects(projectPage.getProjects());
-
- PreferencesPage preferencesPage = (PreferencesPage) pages.get(PageType.PAGE_PREFERENCES);
- configuration.setTempDirectory(preferencesPage.getTempDirectory());
-
- return configuration.save();
- }
-
- /**
- * Finds a supported locale for the given locale.
- *
- * @param forLocale
- * The locale to find a supported locale for
- * @return The supported locale that was found, or the default locale if no
- * supported locale could be found
- */
- private Locale findSupportedLocale(Locale forLocale) {
- for (Locale locale : SUPPORTED_LOCALES) {
- if (locale.equals(forLocale)) {
- return locale;
- }
- }
- for (Locale locale : SUPPORTED_LOCALES) {
- if (locale.getCountry().equals(forLocale.getCountry()) && locale.getLanguage().equals(forLocale.getLanguage())) {
- return locale;
- }
- }
- for (Locale locale : SUPPORTED_LOCALES) {
- if (locale.getLanguage().equals(forLocale.getLanguage())) {
- return locale;
- }
- }
- return SUPPORTED_LOCALES[0];
- }
-
- /**
- * Returns the version.
- *
- * @return The version
- */
- public static final Version getVersion() {
- return VERSION;
- }
-
- //
- // ACTIONS
- //
-
- /**
- * Switches the language of the interface to the given locale.
- *
- * @param locale
- * The locale to switch to
- */
- private void switchLanguage(Locale locale) {
- Locale supportedLocale = findSupportedLocale(locale);
- Action languageAction = languageActions.get(supportedLocale);
- JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) languageAction.getValue("menuItem");
- menuItem.setSelected(true);
- I18n.setLocale(supportedLocale);
- for (Runnable i18nRunnable : I18nContainer.getInstance()) {
- try {
- i18nRunnable.run();
- } catch (Throwable t) {
- /* we probably shouldn't swallow this. */
- }
- }
- wizard.setPage(wizard.getPage());
- configuration.setLocale(supportedLocale);
- }
-
- /**
- * Shows a dialog with general preferences.
- */
- private void optionsPreferences() {
- ((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));
- ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setUseEarlyEncode(configuration.useEarlyEncode());
- ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setPriority(configuration.getPriority());
- ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setManifestPutter(configuration.getManifestPutter());
- showPage(PageType.PAGE_PREFERENCES);
- optionsPreferencesAction.setEnabled(false);
- wizard.setNextEnabled(true);
- wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
- }
-
- /**
- * Shows a dialog box that shows the last version that was found by the
- * {@link UpdateChecker}.
- */
- private void showLatestUpdate() {
- Version latestVersion = updateChecker.getLatestVersion();
- int versionDifference = latestVersion.compareTo(VERSION);
- if (versionDifference > 0) {
- JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.newer.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
- } else if (versionDifference < 0) {
- JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.older.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
- } else {
- JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.okay.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
- }
- }
-
- //
- // INTERFACE ListSelectionListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void valueChanged(ListSelectionEvent e) {
- JList list = (JList) e.getSource();
- int selectedRow = list.getSelectedIndex();
- wizard.setNextEnabled(selectedRow > -1);
- }
-
- //
- // INTERFACE WizardListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void wizardNextPressed(TWizard wizard) {
- String pageName = wizard.getPage().getName();
- if ("page.node-manager".equals(pageName)) {
- showPage(PageType.PAGE_PROJECTS);
- } else if ("page.project".equals(pageName)) {
- ProjectPage projectPage = (ProjectPage) wizard.getPage();
- Project project = projectPage.getSelectedProject();
- if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) {
- 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.warning.no-path"), null, JOptionPane.ERROR_MESSAGE);
- return;
- }
- ((ProjectFilesPage) pages.get(PageType.PAGE_PROJECT_FILES)).setProject(project);
- ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).setProject(project);
- showPage(PageType.PAGE_PROJECT_FILES);
- } else if ("page.project.files".equals(pageName)) {
- ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
- Project project = projectPage.getSelectedProject();
- if (selectedNode == null) {
- JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.error.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
- return;
- }
- 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;
- }
- 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;
- }
- }
- boolean nodeRunning = false;
- try {
- nodeRunning = freenetInterface.isNodePresent();
- } catch (IOException e) {
- /* ignore. */
- }
- if (!nodeRunning) {
- JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.error.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
- return;
- }
- configuration.save();
- showPage(PageType.PAGE_INSERT_PROJECT);
- ProjectInsertPage projectInsertPage = (ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT);
- String tempDirectory = ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).getTempDirectory();
- projectInsertPage.setTempDirectory(tempDirectory);
- projectInsertPage.setUseEarlyEncode(configuration.useEarlyEncode());
- projectInsertPage.setPriority(configuration.getPriority());
- projectInsertPage.setManifestPutter(configuration.getManifestPutter());
- projectInsertPage.startInsert();
- nodeMenu.setEnabled(false);
- optionsPreferencesAction.setEnabled(false);
- } else if ("page.project.insert".equals(pageName)) {
- ProjectInsertPage projectInsertPage = (ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT);
- if (projectInsertPage.isRunning()) {
- projectInsertPage.stopInsert();
- } else {
- showPage(PageType.PAGE_PROJECTS);
- nodeMenu.setEnabled(true);
- 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.setUseEarlyEncode(preferencesPage.useEarlyEncode());
- configuration.setPriority(preferencesPage.getPriority());
- configuration.setManifestPutter(preferencesPage.getManifestPutter());
- configuration.setConfigurationLocation(preferencesPage.getConfigurationLocation());
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void wizardPreviousPressed(TWizard wizard) {
- String pageName = wizard.getPage().getName();
- if ("page.project".equals(pageName) || "page.preferences".equals(pageName)) {
- showPage(PageType.PAGE_NODE_MANAGER);
- optionsPreferencesAction.setEnabled(true);
- } else if ("page.project.files".equals(pageName)) {
- showPage(PageType.PAGE_PROJECTS);
- } else if ("page.project.insert".equals(pageName)) {
- showPage(PageType.PAGE_PROJECT_FILES);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void wizardQuitPressed(TWizard wizard) {
- if (((ProjectPage) pages.get(PageType.PAGE_PROJECTS)).wasUriCopied() || ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).wasUriCopied()) {
- JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.use-clipboard-now"));
- }
- if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), I18n.getMessage("jsite.quit.question.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
- if (isOverwritingConfiguration() && !originalLocation.equals(configuration.getConfigurationDirectory())) {
- int overwriteConfigurationAnswer = JOptionPane.showConfirmDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.quit.overwrite-configuration"), configuration.getConfigurationLocator().getFile(configuration.getConfigurationDirectory())), I18n.getMessage("jsite.quit.overwrite-configuration.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
- if (overwriteConfigurationAnswer == JOptionPane.YES_OPTION) {
- if (saveConfiguration()) {
- System.exit(0);
- }
- } else if (overwriteConfigurationAnswer == JOptionPane.CANCEL_OPTION) {
- return;
- }
- if (overwriteConfigurationAnswer == JOptionPane.NO_OPTION) {
- 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);
- }
- }
- }
-
- //
- // INTERFACE NodeManagerListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void nodesUpdated(Node[] nodes) {
- nodeMenu.removeAll();
- ButtonGroup nodeButtonGroup = new ButtonGroup();
- Node newSelectedNode = null;
- for (Node node : nodes) {
- JRadioButtonMenuItem nodeMenuItem = new JRadioButtonMenuItem(node.getName());
- nodeMenuItem.putClientProperty("Node", node);
- nodeMenuItem.addActionListener(this);
- nodeButtonGroup.add(nodeMenuItem);
- if (node.equals(selectedNode)) {
- newSelectedNode = node;
- nodeMenuItem.setSelected(true);
- }
- nodeMenu.add(nodeMenuItem);
- }
- nodeMenu.addSeparator();
- nodeMenu.add(manageNodeAction);
- selectedNode = newSelectedNode;
- freenetInterface.setNode(selectedNode);
- }
-
- /**
- * {@inheritDoc}
- */
- public void nodeSelected(Node node) {
- for (Component menuItem : nodeMenu.getMenuComponents()) {
- if (menuItem instanceof JMenuItem) {
- if (node.equals(((JMenuItem) menuItem).getClientProperty("Node"))) {
- ((JMenuItem) menuItem).setSelected(true);
- }
- }
- }
- freenetInterface.setNode(node);
- selectedNode = node;
- }
-
- //
- // INTERFACE ActionListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void actionPerformed(ActionEvent e) {
- Object source = e.getSource();
- if (source instanceof JRadioButtonMenuItem) {
- JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) source;
- Node node = (Node) menuItem.getClientProperty("Node");
- selectedNode = node;
- freenetInterface.setNode(selectedNode);
- }
- }
-
- //
- // INTERFACE UpdateListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void foundUpdateData(Version foundVersion, long versionTimestamp) {
- logger.log(Level.FINEST, "Found version {0} from {1,date}.", new Object[] { foundVersion, versionTimestamp });
- if (foundVersion.compareTo(VERSION) > 0) {
- JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.found-version.message"), foundVersion.toString(), new Date(versionTimestamp)), I18n.getMessage("jsite.update-checker.found-version.title"), JOptionPane.INFORMATION_MESSAGE);
- }
- }
-
- //
- // MAIN METHOD
- //
-
- /**
- * Main method that is called by the VM.
- *
- * @param args
- * The command-line arguments
- */
- public static void main(String[] args) {
- /* initialize logger. */
- Logger logger = Logger.getLogger("de.todesbaum");
- Handler handler = new ConsoleHandler();
- logger.addHandler(handler);
- String configFilename = null;
- boolean nextIsConfigFilename = false;
- for (String argument : args) {
- if (nextIsConfigFilename) {
- configFilename = argument;
- nextIsConfigFilename = false;
- }
- if ("--help".equals(argument)) {
- printHelp();
- return;
- } else if ("--debug".equals(argument)) {
- logger.setLevel(Level.ALL);
- handler.setLevel(Level.ALL);
- } else if ("--config-file".equals(argument)) {
- nextIsConfigFilename = true;
- }
- }
- if (nextIsConfigFilename) {
- System.out.println("--config-file needs parameter!");
- return;
- }
- new Main(configFilename);
- }
-
- /**
- * Prints a small syntax help.
- */
- private static void printHelp() {
- System.out.println("--help\tshows this cruft");
- System.out.println("--debug\tenables some debug output");
- System.out.println("--config-file <file>\tuse specified configuration file");
- }
-
-}
+++ /dev/null
-/*
- * jSite - Version.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.jsite.main;
-
-/**
- * Container for version information.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public class Version implements Comparable<Version> {
-
- /** The components of the version information. */
- private final int[] components;
-
- /**
- * Creates a new version container with the given components.
- *
- * @param components
- * The version components
- */
- public Version(int... components) {
- this.components = new int[components.length];
- System.arraycopy(components, 0, this.components, 0, components.length);
- }
-
- /**
- * Returns the number of version components.
- *
- * @return The number of version components
- */
- public int size() {
- return components.length;
- }
-
- /**
- * Returns the version component with the given index.
- *
- * @param index
- * The index of the version component
- * @return The version component
- */
- public int getComponent(int index) {
- return components[index];
- }
-
- /**
- * Parses a version from the given string.
- *
- * @param versionString
- * The version string to parse
- * @return The parsed version, or <code>null</code> if the string could not
- * be parsed
- */
- public static Version parse(String versionString) {
- String[] componentStrings = versionString.split("\\.");
- int[] components = new int[componentStrings.length];
- int index = -1;
- for (String componentString : componentStrings) {
- try {
- components[++index] = Integer.parseInt(componentString);
- } catch (NumberFormatException nfe1) {
- return null;
- }
- }
- return new Version(components);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- StringBuilder versionString = new StringBuilder();
- for (int component : components) {
- if (versionString.length() != 0) {
- versionString.append('.');
- }
- versionString.append(component);
- }
- return versionString.toString();
- }
-
- /**
- * {@inheritDoc}
- */
- public int compareTo(Version version) {
- int lessComponents = Math.min(components.length, version.components.length);
- for (int index = 0; index < lessComponents; index++) {
- if (version.components[index] == components[index]) {
- continue;
- }
- return components[index] - version.components[index];
- }
- return components.length - version.components.length;
- }
-
-}
+++ /dev/null
-/*
- * jSite - Client.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import de.todesbaum.util.io.StreamCopier.ProgressListener;
-
-/**
- * A Client executes {@link Command}s over a {@link Connection} to a
- * {@link Node} and delivers resulting {@link Message}s.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class Client implements ConnectionListener {
-
- /** The connection this client operates on. */
- private final Connection connection;
-
- /** The identifiers the client filters messages for. */
- private List<String> identifiers = new ArrayList<String>();
-
- /** The queued messages. */
- private final List<Message> messageQueue = new ArrayList<Message>();
-
- /** Whether the client was disconnected. */
- private boolean disconnected = false;
-
- /** Whether to catch all messages from the connection. */
- private boolean catchAll = false;
-
- /**
- * Creates a new client that operates on the specified connection.
- *
- * @param connection
- * The connection to operate on
- */
- public Client(Connection connection) {
- this.connection = connection;
- connection.addConnectionListener(this);
- }
-
- /**
- * Creates a new client that operates on the specified connection and
- * immediately executes the specified command.
- *
- * @param connection
- * The connection to operate on
- * @param command
- * The command to execute
- * @throws IOException
- * if an I/O error occurs
- * @see #execute(Command)
- */
- public Client(Connection connection, Command command) throws IOException {
- this(connection);
- execute(command);
- }
-
- /**
- * Returns whether this client catches all messages going over the
- * connection.
- *
- * @return <code>true</code> if the client catches all messages,
- * <code>false</code> otherwise
- */
- public boolean isCatchAll() {
- return catchAll;
- }
-
- /**
- * Sets whether this client catches all messages going over the connection.
- *
- * @param catchAll
- * <code>true</code> if the client should catch all messages,
- * <code>false</code> otherwise
- */
- public void setCatchAll(boolean catchAll) {
- this.catchAll = catchAll;
- }
-
- /**
- * Executes the specified command. This will also clear the queue of
- * messages, discarding all messages that resulted from the previous command
- * and have not yet been read.
- *
- * @param command
- * The command to execute
- * @throws IOException
- * if an I/O error occurs
- * @see #execute(Command, boolean)
- */
- public void execute(Command command) throws IOException {
- execute(command, true);
- }
-
- /**
- * Executes the specified command. This will also clear the queue of
- * messages, discarding all messages that resulted from the previous
- * command and have not yet been read.
- *
- * @param command
- * The command to execute
- * @param progressListener
- * The progress listener for payload transfers
- * @throws IOException
- * if an I/O error occurs
- * @see #execute(Command, boolean)
- */
- public void execute(Command command, ProgressListener progressListener) throws IOException {
- execute(command, true, progressListener);
- }
-
- /**
- * Executes the specified command and optionally clears the list of
- * identifiers this clients listens to before starting the command.
- *
- * @param command
- * The command to execute
- * @param removeExistingIdentifiers
- * If <code>true</code>, the list of identifiers that this
- * clients listens to is cleared
- * @throws IOException
- * if an I/O error occurs
- */
- public void execute(Command command, boolean removeExistingIdentifiers) throws IOException {
- execute(command, removeExistingIdentifiers, null);
- }
-
- /**
- * Executes the specified command and optionally clears the list of
- * identifiers this clients listens to before starting the command.
- *
- * @param command
- * The command to execute
- * @param removeExistingIdentifiers
- * If <code>true</code>, the list of identifiers that this
- * clients listens to is cleared
- * @param progressListener
- * The progress listener for payload transfers
- * @throws IOException
- * if an I/O error occurs
- */
- public void execute(Command command, boolean removeExistingIdentifiers, ProgressListener progressListener) throws IOException {
- synchronized (messageQueue) {
- messageQueue.clear();
- if (removeExistingIdentifiers) {
- identifiers.clear();
- }
- identifiers.add(command.getIdentifier());
- }
- connection.execute(command, progressListener);
- }
-
- /**
- * Returns the next message, waiting endlessly for it, if need be. If you
- * are not sure whether a message will arrive, better use
- * {@link #readMessage(long)} to only wait for a specific time.
- *
- * @return The next message that resulted from the execution of the last
- * command
- * @see #readMessage(long)
- * @see #execute(Command)
- */
- public Message readMessage() {
- return readMessage(0);
- }
-
- /**
- * Returns the next message. If the message queue is currently empty, at
- * least <code>maxWaitTime</code> milliseconds will be waited for a
- * message to arrive.
- *
- * @param maxWaitTime
- * The minimum time to wait for a message, in milliseconds
- * @return The message, or <code>null</code> if no message arrived in time
- * or the client is currently disconnected
- * @see #isDisconnected()
- * @see Object#wait(long)
- */
- public Message readMessage(long maxWaitTime) {
- synchronized (messageQueue) {
- if (disconnected) {
- return null;
- }
- if (messageQueue.size() == 0) {
- try {
- messageQueue.wait(maxWaitTime);
- } catch (InterruptedException ie1) {
- }
- }
- if (messageQueue.size() > 0) {
- return messageQueue.remove(0);
- }
- }
- return null;
- }
-
- /**
- * Returns whether the client is currently disconnected.
- *
- * @return <code>true</code> if the client is disconnected,
- * <code>false</code> otherwise
- */
- public boolean isDisconnected() {
- synchronized (messageQueue) {
- return disconnected;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void messageReceived(Connection connection, Message message) {
- synchronized (messageQueue) {
- if (catchAll || (message.getIdentifier().length() == 0) || identifiers.contains(message.getIdentifier())) {
- messageQueue.add(message);
- messageQueue.notify();
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void connectionTerminated(Connection connection) {
- synchronized (messageQueue) {
- disconnected = true;
- messageQueue.notify();
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - ClientGet.java - Copyright © 2008–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Implementation of the “ClientGet” command.
- *
- * @author David ‘BombeB Roden <bombe@freenetproject.org>
- */
-public class ClientGet extends Command {
-
- private boolean ignoreDataStore;
- private boolean dataStoreOnly;
- private String uri;
- private Verbosity verbosity = Verbosity.NONE;
- private long maxSize = -1;
- private long maxTempSize = -1;
- private int maxRetries = -1;
- private PriorityClass priorityClass = PriorityClass.INTERACTIVE;
- private Persistence persistence = Persistence.CONNECTION;
- private String clientToken;
- private boolean global = false;
- private ReturnType returnType = ReturnType.direct;
- private boolean binaryBlob = false;
- private String allowedMimeTypes = null;
- private String filename = null;
- private String tempFilename = null;
-
- /**
- *Creates a new ClientGet command with the given request identifier.
- *
- * @param identifier
- * The request identifier
- */
- public ClientGet(String identifier) {
- super("ClientGet", identifier);
- }
-
- /**
- * TODO
- *
- * @return
- */
- public boolean isIgnoreDataStore() {
- return ignoreDataStore;
- }
-
- /**
- * TODO
- *
- * @param ignoreDataStore
- */
- public void setIgnoreDataStore(boolean ignoreDataStore) {
- this.ignoreDataStore = ignoreDataStore;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public boolean isDataStoreOnly() {
- return dataStoreOnly;
- }
-
- /**
- * TODO
- *
- * @param dataStoreOnly
- */
- public void setDataStoreOnly(boolean dataStoreOnly) {
- this.dataStoreOnly = dataStoreOnly;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public String getUri() {
- return uri;
- }
-
- /**
- * TODO
- *
- * @param uri
- */
- public void setUri(String uri) {
- this.uri = uri;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public Verbosity getVerbosity() {
- return verbosity;
- }
-
- /**
- * TODO
- *
- * @param verbosity
- */
- public void setVerbosity(Verbosity verbosity) {
- this.verbosity = verbosity;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public long getMaxSize() {
- return maxSize;
- }
-
- /**
- * TODO
- *
- * @param maxSize
- */
- public void setMaxSize(long maxSize) {
- this.maxSize = maxSize;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public long getMaxTempSize() {
- return maxTempSize;
- }
-
- /**
- * TODO
- *
- * @param maxTempSize
- */
- public void setMaxTempSize(long maxTempSize) {
- this.maxTempSize = maxTempSize;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public int getMaxRetries() {
- return maxRetries;
- }
-
- /**
- * TODO
- *
- * @param maxRetries
- */
- public void setMaxRetries(int maxRetries) {
- this.maxRetries = maxRetries;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public PriorityClass getPriorityClass() {
- return priorityClass;
- }
-
- /**
- * TODO
- *
- * @param priorityClass
- */
- public void setPriorityClass(PriorityClass priorityClass) {
- this.priorityClass = priorityClass;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public Persistence getPersistence() {
- return persistence;
- }
-
- /**
- * TODO
- *
- * @param persistence
- */
- public void setPersistence(Persistence persistence) {
- this.persistence = persistence;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public String getClientToken() {
- return clientToken;
- }
-
- /**
- * TODO
- *
- * @param clientToken
- */
- public void setClientToken(String clientToken) {
- this.clientToken = clientToken;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public boolean isGlobal() {
- return global;
- }
-
- /**
- * TODO
- *
- * @param global
- */
- public void setGlobal(boolean global) {
- this.global = global;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public ReturnType getReturnType() {
- return returnType;
- }
-
- /**
- * TODO
- *
- * @param returnType
- */
- public void setReturnType(ReturnType returnType) {
- this.returnType = returnType;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public boolean isBinaryBlob() {
- return binaryBlob;
- }
-
- /**
- * TODO
- *
- * @param binaryBlob
- */
- public void setBinaryBlob(boolean binaryBlob) {
- this.binaryBlob = binaryBlob;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public String getAllowedMimeTypes() {
- return allowedMimeTypes;
- }
-
- /**
- * TODO
- *
- * @param allowedMimeTypes
- */
- public void setAllowedMimeTypes(String allowedMimeTypes) {
- this.allowedMimeTypes = allowedMimeTypes;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public String getFilename() {
- return filename;
- }
-
- /**
- * TODO
- *
- * @param filename
- */
- public void setFilename(String filename) {
- this.filename = filename;
- }
-
- /**
- * TODO
- *
- * @return
- */
- public String getTempFilename() {
- return tempFilename;
- }
-
- /**
- * TODO
- *
- * @param tempFilename
- */
- public void setTempFilename(String tempFilename) {
- this.tempFilename = tempFilename;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void write(Writer writer) throws IOException {
- super.write(writer);
- writer.write("IgnoreDS=" + ignoreDataStore + LINEFEED);
- writer.write("DSonly=" + dataStoreOnly + LINEFEED);
- writer.write("URI=" + uri + LINEFEED);
- writer.write("Verbosity=" + verbosity.getValue() + LINEFEED);
- if (maxSize > -1) {
- writer.write("MaxSize=" + maxSize + LINEFEED);
- }
- if (maxTempSize > -1) {
- writer.write("MaxTempSize=" + maxTempSize + LINEFEED);
- }
- if (maxRetries >= -1) {
- writer.write("MaxRetries=" + maxRetries + LINEFEED);
- }
- writer.write("PriorityClass=" + priorityClass.getValue() + LINEFEED);
- writer.write("Persistence=" + persistence.getName() + LINEFEED);
- if (clientToken != null) {
- writer.write("ClientToken=" + clientToken + LINEFEED);
- }
- writer.write("Global=" + global + LINEFEED);
- writer.write("BinaryBlob=" + binaryBlob + LINEFEED);
- if (allowedMimeTypes != null) {
- writer.write("AllowedMIMETypes=" + allowedMimeTypes + LINEFEED);
- }
- if (returnType == ReturnType.disk) {
- writer.write("Filename=" + filename + LINEFEED);
- if (tempFilename != null) {
- writer.write("TempFilename=" + tempFilename + LINEFEED);
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - ClientHello.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Implementation of the <code>ClientHello</code> command. This command must
- * be sent as the first command on a connection ({@link de.todesbaum.util.freenet.fcp2.Connection#connect()}
- * takes care of that) and must not be sent afterwards.
- * <p>
- * The node can answer with the following messages: <code>NodeHello</code>.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class ClientHello extends Command {
-
- /** The name of the client. */
- protected String name;
-
- /** The version of the FCP protocol the client expects. */
- protected String expectedVersion = "2.0";
-
- /**
- * Creates a new <code>ClientHello</code> command.
- */
- public ClientHello() {
- super("ClientHello", "ClientHello-" + System.currentTimeMillis());
- }
-
- /**
- * Returns the value of the <code>ExpectedVersion</code> parameter of this
- * command. At the moment this value is not used by the node but in the
- * future this may be used to enforce certain node versions.
- *
- * @return The expected version
- */
- public String getExpectedVersion() {
- return expectedVersion;
- }
-
- /**
- * Sets the value of the <code>ExpectedVersion</code> parameter of this
- * command. At the moment this value is not used by the node but in the
- * future this may be used to enforce certain node versions.
- *
- * @param expectedVersion
- * The expected version
- */
- public void setExpectedVersion(String expectedVersion) {
- this.expectedVersion = expectedVersion;
- }
-
- /**
- * Returns the name of the client that is connecting.
- *
- * @return The name of the client
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the name of the client that is connecting.
- *
- * @param name
- * The name of the client
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void write(Writer writer) throws IOException {
- writer.write("Name=" + name + LINEFEED);
- writer.write("ExpectedVersion=" + expectedVersion + LINEFEED);
- }
-
-}
+++ /dev/null
-/*
- * jSite - ClientPut.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Abstract base class for all put requests. It contains all parameters that put
- * requests have in common.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public abstract class ClientPut extends Command {
-
- /** The URI of this request. */
- protected final String uri;
-
- /** The client token of this request. */
- protected String clientToken = null;
-
- /** Whether this request should only create a CHK. */
- protected boolean getCHKOnly = false;
-
- /** Whether this request is a global request. */
- protected boolean global = false;
-
- /** Whether the node should not try to compress the file. */
- protected boolean dontCompress = false;
-
- /** The maximum number of retries of this command. */
- protected int maxRetries = 0;
-
- /** Whether to generate the keys early. */
- protected boolean earlyEncode = false;
-
- /** The persistence of this request. */
- protected Persistence persistence = Persistence.CONNECTION;
-
- /** The priority class of this request. */
- protected PriorityClass priorityClass = PriorityClass.INTERACTIVE;
-
- /** The verbosiry of this request. */
- protected Verbosity verbosity = Verbosity.NONE;
-
- /**
- * Creates a new put request with the specified name, identifier and URI.
- *
- * @param name
- * The name of this request
- * @param identifier
- * The identifier of this request
- * @param uri
- * The URI of this request
- */
- protected ClientPut(String name, String identifier, String uri) {
- super(name, identifier);
- this.uri = uri;
- }
-
- /**
- * Returns whether the node should not try to compress the data.
- *
- * @return <code>true</code> if the node should <strong>not</strong> try
- * to compress the data
- */
- public boolean isDontCompress() {
- return dontCompress;
- }
-
- /**
- * Sets whether the node should not try to compress the data. A client might
- * set this hint on data that is clearly not compressible, like MPEG audio
- * files, JPEG or PNG images, highly compressed movies, or compressed
- * archives like ZIP files. Otherwise the node will try to compress the file
- * which -- depending on the size of the data -- might take a lot of time
- * and memory.
- *
- * @param dontCompress
- * <code>true</code> if the node should <strong>not</strong>
- * try to compress the data
- */
- public void setDontCompress(boolean dontCompress) {
- this.dontCompress = dontCompress;
- }
-
- /**
- * Returns whether this request should only return the CHK of the data.
- * @return Whether this request should only return the CHK of the data
- */
- public boolean isGetCHKOnly() {
- return getCHKOnly;
- }
-
- /**
- * Sets whether this request should only return the CHK of the data.
- * @param getCHKOnly
- * <code>true</code> if this request should only return the CHK of the data
- */
- public void setGetCHKOnly(boolean getCHKOnly) {
- this.getCHKOnly = getCHKOnly;
- }
-
- /**
- * Returns whether this request is a global request.
- * @return <code>true</code> if this request is a global request, <code>false</code> otherwise
- */
- public boolean isGlobal() {
- return global;
- }
-
- /**
- * Sets whether this request is a global request.
- * @param global
- * <code>true</code> if this request is a global request, <code>false</code> otherwise
- */
- public void setGlobal(boolean global) {
- this.global = global;
- }
-
- /**
- * Returns the maximum number of retries of this request.
- * @return The maximum number of retries of this request
- */
- public int getMaxRetries() {
- return maxRetries;
- }
-
- /**
- * Sets the maximum number of retries of this request
- * @param maxRetries
- * The maximum number of retries of this request
- */
- public void setMaxRetries(int maxRetries) {
- this.maxRetries = maxRetries;
- }
-
- /**
- * Returns whether the data should be encoded early to generate the final
- * key as fast as possible.
- *
- * @return {@code true} if the key should be generated early, {@code false}
- * otherwise
- */
- public boolean isEarlyEncode() {
- return earlyEncode;
- }
-
- /**
- * Sets whether the data should be encoded early to generate the final key
- * as fast as possible.
- *
- * @param earlyEncode
- * {@code true} if the key should be generated early, {@code
- * false} otherwise
- */
- public void setEarlyEncode(boolean earlyEncode) {
- this.earlyEncode = earlyEncode;
- }
-
- /**
- * Returns the priority class of this request.
- * @return The priority class of this request
- */
- public PriorityClass getPriorityClass() {
- return priorityClass;
- }
-
- /**
- * Sets the priority class of this request.
- * @param priorityClass
- * The priority class of this request
- */
- public void setPriorityClass(PriorityClass priorityClass) {
- this.priorityClass = priorityClass;
- }
-
- /**
- * Returns the verbosity of this request.
- * @return The verbosity of this request
- */
- public Verbosity getVerbosity() {
- return verbosity;
- }
-
- /**
- * Sets the verbosity of this request.
- * @param verbosity
- * The verbosity of this request
- */
- public void setVerbosity(Verbosity verbosity) {
- this.verbosity = verbosity;
- }
-
- /**
- * Returns the URI of this request
- * @return The URI of this request.
- */
- public String getUri() {
- return uri;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void write(Writer writer) throws IOException {
- super.write(writer);
- writer.write("URI=" + uri + LINEFEED);
- if (verbosity != null)
- writer.write("Verbosity=" + verbosity.getValue() + LINEFEED);
- if (maxRetries != 0)
- writer.write("MaxRetries=" + maxRetries + LINEFEED);
- writer.write("EarlyEncode=" + earlyEncode);
- if (priorityClass != null)
- writer.write("PriorityClass=" + priorityClass.getValue() + LINEFEED);
- writer.write("GetCHKOnly=" + getCHKOnly + LINEFEED);
- writer.write("Global=" + global + LINEFEED);
- writer.write("DontCompress=" + dontCompress + LINEFEED);
- if (clientToken != null)
- writer.write("ClientToken=" + clientToken + LINEFEED);
- if (persistence != null)
- writer.write("Persistence=" + persistence.getName() + LINEFEED);
- }
-
-}
+++ /dev/null
-/*
- * jSite - ClientPutComplexDir.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.List;
-
-import de.todesbaum.util.io.Closer;
-
-/**
- * Implementation of the <code>ClientPutComplexDir</code> command. This command
- * can be used to insert directories that do not exist on disk.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class ClientPutComplexDir extends ClientPutDir<ClientPutComplexDir> {
-
- /** The file entries of this directory. */
- private List<FileEntry> fileEntries = new ArrayList<FileEntry>();
-
- /** Whether this request has payload. */
- private boolean hasPayload = false;
-
- /** The input streams for the payload. */
- private File payloadFile;
-
- /** The total number of bytes of the payload. */
- private long payloadLength = 0;
-
- /** The temp directory to use. */
- private final String tempDirectory;
-
- /**
- * Creates a new <code>ClientPutComplexDir</code> command with the specified
- * identifier and URI.
- *
- * @param identifier
- * The identifier of the command
- * @param uri
- * The URI of the command
- */
- public ClientPutComplexDir(String identifier, String uri) {
- this(identifier, uri, null);
- }
-
- /**
- * Creates a new <code>ClientPutComplexDir</code> command with the specified
- * identifier and URI.
- *
- * @param identifier
- * The identifier of the command
- * @param uri
- * The URI of the command
- * @param tempDirectory
- * The temp directory to use, or {@code null} to use the default
- * temp directory
- */
- public ClientPutComplexDir(String identifier, String uri, String tempDirectory) {
- super("ClientPutComplexDir", identifier, uri);
- this.tempDirectory = tempDirectory;
- }
-
- /**
- * Adds a file to the directory inserted by this request.
- *
- * @param fileEntry
- * The file entry to add to the directory
- * @throws IOException
- * if an I/O error occurs when creating the payload stream
- */
- public void addFileEntry(FileEntry fileEntry) throws IOException {
- if (fileEntry instanceof DirectFileEntry) {
- if (payloadFile == null) {
- try {
- payloadFile = File.createTempFile("payload", ".dat", (tempDirectory != null) ? new File(tempDirectory) : null);
- payloadFile.deleteOnExit();
- } catch (IOException e) {
- /* ignore. */
- }
- }
- if (payloadFile != null) {
- InputStream payloadInputStream = ((DirectFileEntry) fileEntry).getDataInputStream();
- FileOutputStream payloadOutputStream = null;
- try {
- payloadOutputStream = new FileOutputStream(payloadFile, true);
- byte[] buffer = new byte[65536];
- int read = 0;
- while ((read = payloadInputStream.read(buffer)) != -1) {
- payloadOutputStream.write(buffer, 0, read);
- }
- payloadOutputStream.flush();
- fileEntries.add(fileEntry);
- } catch (IOException ioe1) {
- payloadFile.delete();
- throw ioe1;
- } finally {
- Closer.close(payloadOutputStream);
- Closer.close(payloadInputStream);
- }
- }
- } else {
- fileEntries.add(fileEntry);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void write(Writer writer) throws IOException {
- super.write(writer);
- int fileIndex = 0;
- for (FileEntry fileEntry : fileEntries) {
- writer.write("Files." + fileIndex + ".Name=" + fileEntry.getFilename() + LINEFEED);
- if (fileEntry.getContentType() != null) {
- writer.write("Files." + fileIndex + ".Metadata.ContentType=" + fileEntry.getContentType() + LINEFEED);
- }
- writer.write("Files." + fileIndex + ".UploadFrom=" + fileEntry.getName() + LINEFEED);
- if (fileEntry instanceof DirectFileEntry) {
- hasPayload = true;
- writer.write("Files." + fileIndex + ".DataLength=" + ((DirectFileEntry) fileEntry).getDataLength() + LINEFEED);
- payloadLength += ((DirectFileEntry) fileEntry).getDataLength();
- } else if (fileEntry instanceof DiskFileEntry) {
- writer.write("Files." + fileIndex + ".Filename=" + ((DiskFileEntry) fileEntry).getFilename() + LINEFEED);
- } else if (fileEntry instanceof RedirectFileEntry) {
- writer.write("Files." + fileIndex + ".TargetURI=" + ((RedirectFileEntry) fileEntry).getTargetURI() + LINEFEED);
- }
- fileIndex++;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected boolean hasPayload() {
- return hasPayload;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected long getPayloadLength() {
- return payloadLength;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected InputStream getPayload() {
- if (payloadFile != null) {
- try {
- return new FileInputStream(payloadFile);
- } catch (FileNotFoundException e) {
- /* shouldn't occur. */
- }
- }
- return null;
- }
-
-}
+++ /dev/null
-/*
- * jSite - ClientPutDir.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Abstract base class for all put requests that insert a directory.
- *
- * @param <C>
- * The type of the “ClientPutDir” command
- * @author David Roden <droden@gmail.com>
- */
-public class ClientPutDir<C extends ClientPutDir<?>> extends ClientPut {
-
- /**
- * All possible manifest putters. Manifest putters are used to distribute
- * files of a directory insert to different containers, depending on size,
- * type, and other factors.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
- public enum ManifestPutter {
-
- /**
- * Use the “simple” manifest putter. Despite its name this is currently
- * the default manifest putter.
- */
- SIMPLE("simple"),
-
- /** Use the “default” manifest putter. */
- DEFAULT("default");
-
- /** The name of the manifest putter. */
- private final String name;
-
- /**
- * Creates a new manifest putter.
- *
- * @param name
- * The name of the manifest putter
- */
- private ManifestPutter(String name) {
- this.name = name;
- }
-
- /**
- * Returns the name of the manifest putter.
- *
- * @return The name of the manifest putter
- */
- public String getName() {
- return name;
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return name.substring(0, 1).toUpperCase() + name.substring(1);
- }
-
- }
-
- /** The default file of the directory. */
- protected String defaultName;
-
- /** The manifest putter to use. */
- private ManifestPutter manifestPutter;
-
- /**
- * Creates a new request with the specified name, identifier, and URI.
- *
- * @param name
- * The name of the request
- * @param identifier
- * The identifier of the request
- * @param uri
- * The URI of the request
- */
- public ClientPutDir(String name, String identifier, String uri) {
- super(name, identifier, uri);
- }
-
- /**
- * Returns the default name of the directory.
- *
- * @return The default name of the directory
- */
- public String getDefaultName() {
- return defaultName;
- }
-
- /**
- * Sets the default name of the directory. The default name of a directory
- * is the name of the file that will be delivered if the directory was
- * requested without a filename. It's about the same as the
- * <code>index.html</code> file that gets delivered if you only request a
- * directory from a webserver.
- *
- * @param defaultName
- * The default name of the directory
- */
- public void setDefaultName(String defaultName) {
- this.defaultName = defaultName;
- }
-
- /**
- * Returns the current manifest putter.
- *
- * @return The current manifest putter (may be {@code null})
- */
- public ManifestPutter getManifestPutter() {
- return manifestPutter;
- }
-
- /**
- * Sets the manifest putter for the “ClientPutDir” command. If {@code null}
- * is given the node will choose a manifest putter.
- *
- * @param manifestPutter
- * The manifest putter to use for the command (may be
- * {@code null})
- * @return This ClientPutDir command
- */
- @SuppressWarnings("unchecked")
- public C setManifestPutter(ManifestPutter manifestPutter) {
- this.manifestPutter = manifestPutter;
- return (C) this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void write(Writer writer) throws IOException {
- super.write(writer);
- if (defaultName != null)
- writer.write("DefaultName=" + defaultName + LINEFEED);
- if (manifestPutter != null) {
- writer.write("ManifestPutter=" + manifestPutter.getName() + LINEFEED);
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - Command.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Writer;
-
-/**
- * Abstract base class for all commands.
- * <p>
- * In addition to the replies listed at the type comment of each specific
- * command the node can <strong>always</strong> send the following messages:
- * <code>ProtocolError</code> (if this library screws up),
- * <code>CloseConnectionDuplicateClientName</code> (if a client with the same
- * name of the {@link de.todesbaum.util.freenet.fcp2.Connection} connects). So
- * when receiving messages from the node you should always be prepared for
- * something you did not expect.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public abstract class Command {
-
- /** The line feed sequence used by the library. */
- protected static final String LINEFEED = "\r\n";
-
- /**
- * The name of the command. The name is sent to the node so it can not be
- * chosen arbitrarily!
- */
- private final String commandName;
-
- /**
- * The identifier of the command. This identifier is used to identify
- * replies that are caused by a command.
- */
- private final String identifier;
-
- /**
- * Creates a new command with the specified name and identifier.
- *
- * @param name
- * The name of the command
- * @param identifier
- * The identifier of the command
- */
- public Command(String name, String identifier) {
- this.commandName = name;
- this.identifier = identifier;
- }
-
- /**
- * Returns the name of this command.
- *
- * @return The name of this command
- */
- public String getCommandName() {
- return commandName;
- }
-
- /**
- * Return the identifier of this command.
- *
- * @return The identifier of this command
- */
- public String getIdentifier() {
- return identifier;
- }
-
- /**
- * Writes all parameters to the specified writer.
- * <p>
- * <strong>NOTE:</strong> Subclasses of Command <strong>must</strong> call
- * <code>super.write(writer)</code> before or after writing their own
- * parameters!
- *
- * @param writer
- * The stream to write the parameters to
- * @throws IOException
- * if an I/O error occurs
- */
- protected void write(Writer writer) throws IOException {
- if (identifier != null)
- writer.write("Identifier=" + identifier + LINEFEED);
- }
-
- /**
- * Returns whether this command has payload to send after the message.
- * Subclasses need to return <code>true</code> here if they need to send
- * payload after the message.
- *
- * @return <code>true</code> if this command has payload to send,
- * <code>false</code> otherwise
- */
- protected boolean hasPayload() {
- return false;
- }
-
- /**
- * Returns the payload of this command as an {@link InputStream}. This
- * method is never called if {@link #hasPayload()} returns
- * <code>false</code>.
- *
- * @return The payload of this command
- */
- protected InputStream getPayload() {
- return null;
- }
-
- /**
- * Returns the length of the payload. This method is never called if
- * {@link #hasPayload()} returns <code>false</code>.
- *
- * @return The length of the payload
- */
- protected long getPayloadLength() {
- return -1;
- }
-
-}
+++ /dev/null
-/*
- * jSite - Connection.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.net.Socket;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-
-import de.todesbaum.util.io.Closer;
-import de.todesbaum.util.io.LineInputStream;
-import de.todesbaum.util.io.StreamCopier;
-import de.todesbaum.util.io.StreamCopier.ProgressListener;
-import de.todesbaum.util.io.TempFileInputStream;
-
-/**
- * A physical connection to a Freenet node.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class Connection {
-
- /** The listeners that receive events from this connection. */
- private List<ConnectionListener> connectionListeners = new ArrayList<ConnectionListener>();
-
- /** The node this connection is connected to. */
- private final Node node;
-
- /** The name of this connection. */
- private final String name;
-
- /** The network socket of this connection. */
- private Socket nodeSocket;
-
- /** The input stream that reads from the socket. */
- private InputStream nodeInputStream;
-
- /** The output stream that writes to the socket. */
- private OutputStream nodeOutputStream;
-
- /** The thread that reads from the socket. */
- private NodeReader nodeReader;
-
- /** A writer for the output stream. */
- private Writer nodeWriter;
-
- /** The NodeHello message sent by the node on connect. */
- protected Message nodeHello;
-
- /** The temp directory to use. */
- private String tempDirectory;
-
- /**
- * Creates a new connection to the specified node with the specified name.
- *
- * @param node
- * The node to connect to
- * @param name
- * The name of this connection
- */
- public Connection(Node node, String name) {
- this.node = node;
- this.name = name;
- }
-
- /**
- * Adds a listener that gets notified on connection events.
- *
- * @param connectionListener
- * The listener to add
- */
- public void addConnectionListener(ConnectionListener connectionListener) {
- connectionListeners.add(connectionListener);
- }
-
- /**
- * Removes a listener from the list of registered listeners. Only the first
- * matching listener is removed.
- *
- * @param connectionListener
- * The listener to remove
- * @see List#remove(java.lang.Object)
- */
- public void removeConnectionListener(ConnectionListener connectionListener) {
- connectionListeners.remove(connectionListener);
- }
-
- /**
- * Notifies listeners about a received message.
- *
- * @param message
- * The received message
- */
- protected void fireMessageReceived(Message message) {
- for (ConnectionListener connectionListener : connectionListeners) {
- connectionListener.messageReceived(this, message);
- }
- }
-
- /**
- * Notifies listeners about the loss of the connection.
- */
- protected void fireConnectionTerminated() {
- for (ConnectionListener connectionListener : connectionListeners) {
- connectionListener.connectionTerminated(this);
- }
- }
-
- /**
- * Returns the name of the connection.
- *
- * @return The name of the connection
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the temp directory to use for creation of temporary files.
- *
- * @param tempDirectory
- * The temp directory to use, or {@code null} to use the default
- * temp directory
- */
- public void setTempDirectory(String tempDirectory) {
- this.tempDirectory = tempDirectory;
- }
-
- /**
- * Connects to the node.
- *
- * @return <code>true</code> if the connection succeeded and the node
- * returned a NodeHello message
- * @throws IOException
- * if an I/O error occurs
- * @see #getNodeHello()
- */
- public synchronized boolean connect() throws IOException {
- nodeSocket = null;
- nodeInputStream = null;
- nodeOutputStream = null;
- nodeWriter = null;
- nodeReader = null;
- try {
- nodeSocket = new Socket(node.getHostname(), node.getPort());
- nodeSocket.setReceiveBufferSize(65535);
- nodeInputStream = nodeSocket.getInputStream();
- nodeOutputStream = nodeSocket.getOutputStream();
- nodeWriter = new OutputStreamWriter(nodeOutputStream, Charset.forName("UTF-8"));
- nodeReader = new NodeReader(nodeInputStream);
- Thread nodeReaderThread = new Thread(nodeReader);
- nodeReaderThread.setDaemon(true);
- nodeReaderThread.start();
- ClientHello clientHello = new ClientHello();
- clientHello.setName(name);
- clientHello.setExpectedVersion("2.0");
- execute(clientHello);
- synchronized (this) {
- try {
- wait();
- } catch (InterruptedException e) {
- }
- }
- return nodeHello != null;
- } catch (IOException ioe1) {
- disconnect();
- throw ioe1;
- }
- }
-
- /**
- * Returns whether this connection is still connected to the node.
- *
- * @return <code>true</code> if this connection is still valid,
- * <code>false</code> otherwise
- */
- public boolean isConnected() {
- return (nodeHello != null) && (nodeSocket != null) && (nodeSocket.isConnected());
- }
-
- /**
- * Returns the NodeHello message the node sent on connection.
- *
- * @return The NodeHello message of the node
- */
- public Message getNodeHello() {
- return nodeHello;
- }
-
- /**
- * Disconnects from the node.
- */
- public void disconnect() {
- Closer.close(nodeWriter);
- nodeWriter = null;
- Closer.close(nodeOutputStream);
- nodeOutputStream = null;
- Closer.close(nodeInputStream);
- nodeInputStream = null;
- nodeInputStream = null;
- Closer.close(nodeSocket);
- nodeSocket = null;
- synchronized (this) {
- notify();
- }
- fireConnectionTerminated();
- }
-
- /**
- * Executes the specified command.
- *
- * @param command
- * The command to execute
- * @throws IllegalStateException
- * if the connection is not connected
- * @throws IOException
- * if an I/O error occurs
- */
- public synchronized void execute(Command command) throws IllegalStateException, IOException {
- execute(command, null);
- }
-
- /**
- * Executes the specified command.
- *
- * @param command
- * The command to execute
- * @param progressListener
- * A progress listener for a payload transfer
- * @throws IllegalStateException
- * if the connection is not connected
- * @throws IOException
- * if an I/O error occurs
- */
- public synchronized void execute(Command command, ProgressListener progressListener) throws IllegalStateException, IOException {
- if (nodeSocket == null) {
- throw new IllegalStateException("connection is not connected");
- }
- nodeWriter.write(command.getCommandName() + Command.LINEFEED);
- command.write(nodeWriter);
- nodeWriter.write("EndMessage" + Command.LINEFEED);
- nodeWriter.flush();
- if (command.hasPayload()) {
- InputStream payloadInputStream = null;
- try {
- payloadInputStream = command.getPayload();
- StreamCopier.copy(payloadInputStream, nodeOutputStream, command.getPayloadLength(), progressListener);
- } finally {
- Closer.close(payloadInputStream);
- }
- nodeOutputStream.flush();
- }
- }
-
- /**
- * The reader thread for this connection. This is essentially a thread that
- * reads lines from the node, creates messages from them and notifies
- * listeners about the messages.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
- private class NodeReader implements Runnable {
-
- /** The input stream to read from. */
- @SuppressWarnings("hiding")
- private InputStream nodeInputStream;
-
- /**
- * Creates a new reader that reads from the specified input stream.
- *
- * @param nodeInputStream
- * The input stream to read from
- */
- public NodeReader(InputStream nodeInputStream) {
- this.nodeInputStream = nodeInputStream;
- }
-
- /**
- * Main loop of the reader. Lines are read and converted into
- * {@link Message} objects.
- */
- @SuppressWarnings("synthetic-access")
- public void run() {
- LineInputStream nodeReader = null;
- try {
- nodeReader = new LineInputStream(nodeInputStream);
- String line = "";
- Message message = null;
- while (line != null) {
- line = nodeReader.readLine();
- // System.err.println("> " + line);
- if (line == null) {
- break;
- }
- if (message == null) {
- message = new Message(line);
- continue;
- }
- if ("Data".equals(line)) {
- /* need to read message from stream now */
- File tempFile = null;
- try {
- tempFile = File.createTempFile("fcpv2", "data", (tempDirectory != null) ? new File(tempDirectory) : null);
- tempFile.deleteOnExit();
- FileOutputStream tempFileOutputStream = new FileOutputStream(tempFile);
- long dataLength = Long.parseLong(message.get("DataLength"));
- StreamCopier.copy(nodeInputStream, tempFileOutputStream, dataLength);
- tempFileOutputStream.close();
- message.setPayloadInputStream(new TempFileInputStream(tempFile));
- } catch (IOException ioe1) {
- ioe1.printStackTrace();
- }
- }
- if ("Data".equals(line) || "EndMessage".equals(line)) {
- if (message.getName().equals("NodeHello")) {
- nodeHello = message;
- synchronized (Connection.this) {
- Connection.this.notify();
- }
- } else {
- fireMessageReceived(message);
- }
- message = null;
- continue;
- }
- int equalsPosition = line.indexOf('=');
- if (equalsPosition > -1) {
- String key = line.substring(0, equalsPosition).trim();
- String value = line.substring(equalsPosition + 1).trim();
- if (key.equals("Identifier")) {
- message.setIdentifier(value);
- } else {
- message.put(key, value);
- }
- continue;
- }
- /* skip lines consisting of whitespace only */
- if (line.trim().length() == 0) {
- continue;
- }
- /* if we got here, some error occured! */
- throw new IOException("Unexpected line: " + line);
- }
- } catch (IOException ioe1) {
- // ioe1.printStackTrace();
- } finally {
- if (nodeReader != null) {
- try {
- nodeReader.close();
- } catch (IOException ioe1) {
- }
- }
- if (nodeInputStream != null) {
- try {
- nodeInputStream.close();
- } catch (IOException ioe1) {
- }
- }
- }
- Connection.this.disconnect();
- }
-
- }
-
-}
+++ /dev/null
-/*
- * jSite - ConnectionListener.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.util.EventListener;
-
-/**
- * Interface for clients that want to be notified when a message was received.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public interface ConnectionListener extends EventListener {
-
- /**
- * Notifies a client that a message was received.
- *
- * @param connection
- * The connection the message was received on
- * @param message
- * The message that was received
- */
- public void messageReceived(Connection connection, Message message);
-
- /**
- * Notifies a client that the connection to the node has been lost.
- *
- * @param connection
- * The connection that was lost
- */
- public void connectionTerminated(Connection connection);
-
-}
+++ /dev/null
-/*
- * jSite - DirectFileEntry.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
-/**
- * A {@link FileEntry} that sends its payload directly to the node, using the
- * existing FCP connection.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class DirectFileEntry extends FileEntry {
-
- /** The input stream to read the data for this file from. */
- private final InputStream dataInputStream;
-
- /** The length of the data. */
- private final long dataLength;
-
- /**
- * Creates a new FileEntry with the specified name and content type that
- * gets its data from the specified byte array.
- *
- * @param filename
- * The name of the file
- * @param contentType
- * The content type of the file
- * @param dataBytes
- * The content of the file
- */
- public DirectFileEntry(String filename, String contentType, byte[] dataBytes) {
- this(filename, contentType, new ByteArrayInputStream(dataBytes), dataBytes.length);
- }
-
- /**
- * Creates a new FileEntry with the specified name and content type that
- * gets its data from the specified input stream.
- *
- * @param filename
- * The name of the file
- * @param contentType
- * The content type of the file
- * @param dataInputStream
- * The input stream to read the content from
- * @param dataLength
- * The length of the data input stream
- */
- public DirectFileEntry(String filename, String contentType, InputStream dataInputStream, long dataLength) {
- super(filename, contentType);
- this.dataInputStream = dataInputStream;
- this.dataLength = dataLength;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getName() {
- return "direct";
- }
-
- /**
- * Returns the input stream for the file's content.
- *
- * @return The input stream for the file's content
- */
- public InputStream getDataInputStream() {
- return dataInputStream;
- }
-
- /**
- * Returns the length of this file's content.
- *
- * @return The length of this file's content
- */
- public long getDataLength() {
- return dataLength;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * jSite - DiskFileEntry.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * A {@link FileEntry} that reads the content from a file on the disk.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class DiskFileEntry extends FileEntry {
-
- /** The local file name. */
- private final String localFilename;
-
- /**
- * Creates a new {@link FileEntry} with the specified name and content type
- * that is read from the file specified by <code>localFilename</code>.
- *
- * @param filename
- * The name of the file
- * @param contentType
- * The content type of the file
- * @param localFilename
- * The name of the local file that holds the content of the file
- * to insert
- */
- public DiskFileEntry(String filename, String contentType, String localFilename) {
- super(filename, contentType);
- this.localFilename = localFilename;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getName() {
- return "disk";
- }
-
- /**
- * Returns the name of the local file that holds the content for this file.
- *
- * @return The name of the local file
- */
- public String getLocalFilename() {
- return localFilename;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * jSite - FileEntry.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * Abstract base class of file entries that are used in the
- * {@link de.todesbaum.util.freenet.fcp2.ClientPutComplexDir} command to define
- * the files of an insert.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public abstract class FileEntry {
-
- /** The name of the file. */
- private final String filename;
-
- /** The content type of the file. */
- private final String contentType;
-
- /**
- * Creates a new file entry with the specified name and content type. The
- * content type should be a standard MIME type with an additional charset
- * specification for text-based types.
- *
- * @param filename
- * The name of the file
- * @param contentType
- * The content type of the file, e.g.
- * <code>"application/x-tar"</code> or
- * <code>"text/html; charset=iso8859-15"</code>
- */
- protected FileEntry(String filename, String contentType) {
- this.filename = filename;
- this.contentType = contentType;
- }
-
- /**
- * Returns the name of this entry's type. Can be one of <code>direct</code>,
- * <code>disk</code>, or <code>redirect</code>. This method is
- * implemented by the subclasses {@link DirectFileEntry},
- * {@link DiskFileEntry}, and {@link RedirectFileEntry}, respectively.
- *
- * @return The name of this entry's type
- */
- public abstract String getName();
-
- /**
- * Returns the content type of this file.
- *
- * @return The content type of this file
- */
- public String getContentType() {
- return contentType;
- }
-
- /**
- * Returns the name of this file.
- *
- * @return The name of this file
- */
- public String getFilename() {
- return filename;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * jSite - GenerateSSK.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * Implementation of the <code>GenerateSSK</code> command.
- * <p>
- * The node can answer with the following messages: <code>SSKKeypair</code>.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class GenerateSSK extends Command {
-
- /**
- * Creates a new <code>GenerateSSK</code> request.
- */
- public GenerateSSK() {
- super("GenerateSSK", null);
- }
-
-}
+++ /dev/null
-/*
- * jSite - Message.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- * Contains replies sent by the Freenet node. A message always has a name, and
- * most of the messages also have an identifier which binds it to a specific
- * command. Exceptions are among others <code>NodeHello</code>,
- * <code>SSKKeypair</code>, and <code>EndListPersistentRequests</code>.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- * @see de.todesbaum.util.freenet.fcp2.Client
- */
-public class Message {
-
- /** The name of this message. */
- private final String name;
-
- /** The identifier of this message. */
- private String identifier = "";
-
- /** The parameters of this message. */
- private Map<String, String> parameters = new HashMap<String, String>();
-
- /** The payload. */
- private InputStream payloadInputStream;
-
- /**
- * Creates a new message with the specified name.
- *
- * @param name
- * The name of this message
- */
- public Message(String name) {
- this.name = name;
- }
-
- /**
- * Returns the identifier of this message.
- *
- * @return The identifier
- */
- public String getIdentifier() {
- return identifier;
- }
-
- /**
- * Sets the identifier of this message.
- *
- * @param identifier
- * The identifier of this message
- */
- public void setIdentifier(String identifier) {
- this.identifier = identifier;
- }
-
- /**
- * Returns the name of this message.
- *
- * @return The name of this message
- */
- public String getName() {
- return name;
- }
-
- /**
- * Tests whether this message contains the parameter with the specified key.
- * Key names are compared ignoring case.
- *
- * @param key
- * The name of the parameter
- * @return <code>true</code> if this parameter exists in this message,
- * <code>false</code> otherwise
- */
- public boolean containsKey(String key) {
- return parameters.containsKey(key.toLowerCase());
- }
-
- /**
- * Returns all parameters of this message. The keys of the entries are all
- * lower case so if you want to match the parameter names you have to watch
- * out.
- *
- * @return All parameters of this message
- */
- public Set<Entry<String, String>> entrySet() {
- return parameters.entrySet();
- }
-
- /**
- * Returns the value of the parameter with the name specified by
- * <code>key</code>.
- *
- * @param key
- * The name of the parameter
- * @return The value of the parameter
- */
- public String get(String key) {
- return parameters.get(key.toLowerCase());
- }
-
- /**
- * Stores the specified value as parameter with the name specified by
- * <code>key</code>.
- *
- * @param key
- * The name of the parameter
- * @param value
- * The value of the parameter
- * @return The previous value, or <code>null</code> if there was no
- * previous value
- */
- public String put(String key, String value) {
- return parameters.put(key.toLowerCase(), value);
- }
-
- /**
- * Returns the number of parameters in this message.
- *
- * @return The number of parameters
- */
- public int size() {
- return parameters.size();
- }
-
- /**
- * @return Returns the payloadInputStream.
- */
- public InputStream getPayloadInputStream() {
- return payloadInputStream;
- }
-
- /**
- * @param payloadInputStream
- * The payloadInputStream to set.
- */
- public void setPayloadInputStream(InputStream payloadInputStream) {
- this.payloadInputStream = payloadInputStream;
- }
-
- /**
- * Returns a textual representation of this message, containing its name,
- * the identifier, and the parameters.
- *
- * @return A textual representation of this message
- */
- @Override
- public String toString() {
- return name + "[identifier=" + identifier + ",parameters=" + parameters.toString() + "]";
- }
-
-}
+++ /dev/null
-/*
- * jSite - Node.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * Contains the hostname and port number of the Freenet node.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class Node {
-
- /** The default port of FCPv2. */
- public static final int DEFAULT_PORT = 9481;
-
- /** The hostname of the node. */
- protected String hostname;
-
- /** The port number of the node. */
- protected int port;
-
- /**
- * Creates a new node with the specified hostname and the default port
- * number.
- *
- * @param hostname
- * The hostname of the node
- * @see #DEFAULT_PORT
- */
- public Node(String hostname) {
- this(hostname, DEFAULT_PORT);
- }
-
- /**
- * Creates a new node with the specified hostname and port number.
- *
- * @param hostname
- * The hostname of the node
- * @param port
- * The port number of the node
- */
- public Node(String hostname, int port) {
- this.hostname = hostname;
- this.port = port;
- }
-
- /**
- * Returns the hostname of the node.
- *
- * @return The hostname of the node
- */
- public String getHostname() {
- return hostname;
- }
-
- /**
- * Returns the port number of the node.
- *
- * @return The port number of the node
- */
- public int getPort() {
- return port;
- }
-
-}
+++ /dev/null
-/*
- * jSite - Persistence.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * The possible persistence options. This specify whether (and for how long) the
- * node remembers to execute a request and the results. Possible values are
- * <code>connection</code>, <code>reboot</code>, and <code>forever</code>.
- * <code>connection</code> means that a request is aborted as soon as the
- * connection to the node is severed. <code>reboot</code> means that a request
- * is remembered as long as the node is running but not after restarts.
- * <code>forever</code> finally means that a request persists until it is
- * explicitely deleted.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- * @see de.todesbaum.util.freenet.fcp2.ModifyPersistentRequest
- * @see de.todesbaum.util.freenet.fcp2.RemovePersistentRequest
- */
-public final class Persistence {
-
- /**
- * Denotes that a request should be terminated if the connection to the node
- * is severed.
- */
- public static final Persistence CONNECTION = new Persistence("connection");
-
- /** Denotes that a request should be remembered until the node is restarted. */
- public static final Persistence REBOOT = new Persistence("reboot");
-
- /**
- * Denotes that a request should be remembered until it is explicitely
- * deleted.
- */
- public static final Persistence FOREVER = new Persistence("forever");
-
- /** The name of this persistence option. */
- private String name;
-
- /**
- * Private constructor that creates a persistence option with the specified
- * name.
- *
- * @param name
- * The name of the persistence option.
- */
- private Persistence(String name) {
- this.name = name;
- }
-
- /**
- * Returns the name of this persistence option.
- *
- * @return The name of this persistence option
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns a textual representation of this persistence option. The result
- * is identical to calling {@link #getName()}.
- *
- * @return The name of this persistence option
- */
- @Override
- public String toString() {
- return name;
- }
-
-}
+++ /dev/null
-/*
- * jSite - PriorityClass.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * The possible priority classes. Possible values are, in order of descending
- * priority: <code>maximum</code> (anything more important than fproxy),
- * <code>interactive</code> (fproxy), <code>semi-interactive</code> (fproxy
- * immediate mode large file downloads, not to disk), <code>updatable</code>
- * (updatable site checks), <code>bulk</code> (large file downloads to disk),
- * <code>prefetch</code>, <code>minimum</code>.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public final class PriorityClass {
-
- /** Denotes <code>maximum</code> priority class. */
- public static final PriorityClass MAXIMUM = new PriorityClass("maximum", 0);
-
- /** Denotes <code>interactive</code> priority class. */
- public static final PriorityClass INTERACTIVE = new PriorityClass("interactive", 1);
-
- /** Denotes <code>semi-interactive</code> priority class. */
- public static final PriorityClass SEMI_INTERACTIVE = new PriorityClass("semiInteractive", 2);
-
- /** Denotes <code>updatable</code> priority class. */
- public static final PriorityClass UPDATABLE = new PriorityClass("updatable", 3);
-
- /** Denotes <code>bulk</code> priority class. */
- public static final PriorityClass BULK = new PriorityClass("bulk", 4);
-
- /** Denotes <code>prefetch</code> priority class. */
- public static final PriorityClass PREFETCH = new PriorityClass("prefetch", 5);
-
- /** Denotes <code>minimum</code> priority class. */
- public static final PriorityClass MINIMUM = new PriorityClass("minimum", 6);
-
- /** The name of the priority class. */
- private String name;
-
- /** The value of the priority class. */
- private int value;
-
- /**
- * Creates a new priority class with the specified name and value.
- *
- * @param name
- * The name of the priority class
- * @param value
- * The value of the priority class
- */
- private PriorityClass(String name, int value) {
- this.name = name;
- this.value = value;
- }
-
- /**
- * Returns the name of this priority class.
- *
- * @return The name of this priority class
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the value of this priority class.
- *
- * @return The value of this priority class
- */
- public int getValue() {
- return value;
- }
-
- //
- // STATIC METHODS
- //
-
- /**
- * Returns the priority class with the given name, matched case-insensitive.
- *
- * @param value
- * The name of the priority
- * @return The priority with the given name, or {@code null} if no priority
- * matches the given name
- */
- public static PriorityClass valueOf(String value) {
- for (PriorityClass priorityClass : new PriorityClass[] { MINIMUM, PREFETCH, BULK, UPDATABLE, SEMI_INTERACTIVE, INTERACTIVE, MAXIMUM }) {
- if (priorityClass.getName().equalsIgnoreCase(value)) {
- return priorityClass;
- }
- }
- return null;
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return name;
- }
-
-}
+++ /dev/null
-/*
- * jSite - RedirectFileEntry.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-public class RedirectFileEntry extends FileEntry {
-
- final String targetURI;
-
- public RedirectFileEntry(String filename, String contentType, String targetURI) {
- super(filename, contentType);
- this.targetURI = targetURI;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getName() {
- return "redirect";
- }
-
- /**
- * @return Returns the targetURI.
- */
- public String getTargetURI() {
- return targetURI;
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * jSite - ReturnType.java - Copyright © 2008–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * Enumeration for the different return types a {@link ClientGet} request can
- * have.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
-public enum ReturnType {
-
- /** The data is returned as payload. */
- direct,
-
- /** The data is written to disk. */
- disk,
-
- /** The data is not returned at all. */
- none
-
-}
+++ /dev/null
-/*
- * jSite - Verbosity.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.freenet.fcp2;
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public final class Verbosity {
-
- public static final Verbosity PROGRESS = new Verbosity(1);
- public static final Verbosity COMPRESSION = new Verbosity(512);
-
- public static final Verbosity NONE = new Verbosity(0);
- public static final Verbosity ALL = new Verbosity(PROGRESS, COMPRESSION);
-
- private final int value;
-
- private Verbosity(int value) {
- this.value = value;
- }
-
- private Verbosity(Verbosity verbosity1, Verbosity verbosity2) {
- this(verbosity1.value | verbosity2.value);
- }
-
- /**
- * @return Returns the value.
- */
- public int getValue() {
- return value;
- }
-
-}
+++ /dev/null
-/*
- * jSite - IconLoader.java - Copyright © 2006–2012 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 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.image;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-
-/**
- * @author <a href="mailto:droden@gmail.com">David Roden</a>
- * @version $Id$
- */
-public class IconLoader {
-
- public static Icon loadIcon(String resourceName) {
- try {
- InputStream resourceStream = IconLoader.class.getResourceAsStream(resourceName);
- if (resourceStream == null) {
- return null;
- }
- ByteArrayOutputStream imageOutput = new ByteArrayOutputStream();
- byte[] buffer = new byte[16384];
- int r = 0;
- while ((r = resourceStream.read(buffer)) != -1) {
- imageOutput.write(buffer, 0, r);
- }
- imageOutput.flush();
- return new ImageIcon(imageOutput.toByteArray());
- } catch (IOException e) {
- }
- return null;
- }
-
-}
+++ /dev/null
-/*
- * jSite - Closer.java - Copyright © 2006–2012 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 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-/**
- * Helper class that can close all kinds of resources without throwing exception
- * so that clean-up code can be written with less code. All methods check that
- * the given resource is not <code>null</code> before invoking the close()
- * method of the respective type.
- *
- * @author <a href="mailto:bombe@freenetproject.org">David ‘Bombe&squo;
- * Roden</a>
- * @version $Id$
- */
-public class Closer {
-
- /**
- * Closes the given result set.
- *
- * @param resultSet
- * The result set to close
- * @see ResultSet#close()
- */
- public static void close(ResultSet resultSet) {
- if (resultSet != null) {
- try {
- resultSet.close();
- } catch (SQLException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given statement.
- *
- * @param statement
- * The statement to close
- * @see Statement#close()
- */
- public static void close(Statement statement) {
- if (statement != null) {
- try {
- statement.close();
- } catch (SQLException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given connection.
- *
- * @param connection
- * The connection to close
- * @see Connection#close()
- */
- public static void close(Connection connection) {
- if (connection != null) {
- try {
- connection.close();
- } catch (SQLException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given server socket.
- *
- * @param serverSocket
- * The server socket to close
- * @see ServerSocket#close()
- */
- public static void close(ServerSocket serverSocket) {
- if (serverSocket != null) {
- try {
- serverSocket.close();
- } catch (IOException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given socket.
- *
- * @param socket
- * The socket to close
- * @see Socket#close()
- */
- public static void close(Socket socket) {
- if (socket != null) {
- try {
- socket.close();
- } catch (IOException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given input stream.
- *
- * @param inputStream
- * The input stream to close
- * @see InputStream#close()
- */
- public static void close(InputStream inputStream) {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given output stream.
- *
- * @param outputStream
- * The output stream to close
- * @see OutputStream#close()
- */
- public static void close(OutputStream outputStream) {
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given reader.
- *
- * @param reader
- * The reader to close
- * @see Reader#close()
- */
- public static void close(Reader reader) {
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException ioe1) {
- }
- }
- }
-
- /**
- * Closes the given writer.
- *
- * @param writer
- * The write to close
- * @see Writer#close()
- */
- public static void close(Writer writer) {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException ioe1) {
- }
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - LineInputStream.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.io;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class LineInputStream extends FilterInputStream {
-
- private boolean skipLinefeed = false;
- private StringBuffer lineBuffer = new StringBuffer();
-
- /**
- * @param in
- */
- public LineInputStream(InputStream in) {
- super(in);
- }
-
- public synchronized String readLine() throws IOException {
- lineBuffer.setLength(0);
- int c = 0;
- while (c != -1) {
- c = read();
- if ((c == -1) && lineBuffer.length() == 0)
- return null;
- if (skipLinefeed && (c == '\n')) {
- skipLinefeed = false;
- continue;
- }
- skipLinefeed = (c == '\r');
- if ((c == '\r') || (c == '\n')) {
- c = -1;
- } else {
- lineBuffer.append((char) c);
- }
- }
- return lineBuffer.toString();
- }
-
-}
+++ /dev/null
-/*
- * jSite - StreamCopier.java - Copyright © 2006–2012 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 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.io;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.EventListener;
-
-/**
- * Copies input from an {@link InputStream} to an {@link OutputStream}.
- *
- * @author <a href="mailto:droden@gmail.com">David Roden</a>
- * @version $Id$
- */
-public class StreamCopier {
-
- /**
- * The default size of the buffer.
- */
- private static final int BUFFER_SIZE = 64 * 1024;
-
- /**
- * The {@link InputStream} to read from.
- */
- private InputStream inputStream;
-
- /**
- * The {@link OutputStream} to write to.
- */
- private OutputStream outputStream;
-
- /**
- * The number of bytes to copy.
- */
- private long length;
-
- /**
- * The size of the buffer.
- */
- private int bufferSize;
-
- /**
- * Creates a new StreamCopier with the specified parameters and the default
- * buffer size.
- *
- * @param inputStream
- * The {@link InputStream} to read from
- * @param outputStream
- * The {@link OutputStream} to write to
- * @param length
- * The number of bytes to copy
- */
- public StreamCopier(InputStream inputStream, OutputStream outputStream, long length) {
- this(inputStream, outputStream, length, BUFFER_SIZE);
- }
-
- /**
- * Creates a new StreamCopier with the specified parameters and the default
- * buffer size.
- *
- * @param inputStream
- * The {@link InputStream} to read from
- * @param outputStream
- * The {@link OutputStream} to write to
- * @param length
- * The number of bytes to copy
- * @param bufferSize
- * The number of bytes to copy at a time
- */
- public StreamCopier(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) {
- this.inputStream = inputStream;
- this.outputStream = outputStream;
- this.length = length;
- this.bufferSize = bufferSize;
- }
-
- /**
- * Copies the stream data. If the input stream is depleted before the
- * requested number of bytes have been read an {@link EOFException} is
- * thrown.
- *
- * @throws EOFException
- * if the input stream is depleted before the requested number
- * of bytes has been read
- * @throws IOException
- * if an I/O error occurs
- */
- public void copy() throws EOFException, IOException {
- copy(inputStream, outputStream, length, bufferSize);
- }
-
- /**
- * Copies the stream data. If the input stream is depleted before the
- * requested number of bytes have been read an {@link EOFException} is
- * thrown.
- *
- * @param progressListener
- * The progress listener (may be {@code null})
- * @throws EOFException
- * if the input stream is depleted before the requested number
- * of bytes has been read
- * @throws IOException
- * if an I/O error occurs
- */
- public void copy(ProgressListener progressListener) throws EOFException, IOException {
- copy(inputStream, outputStream, length, bufferSize, progressListener);
- }
-
- /**
- * Copies <code>length</code> bytes from the <code>inputStream</code> to
- * the <code>outputStream</code>.
- *
- * @param inputStream
- * The input stream to read from
- * @param outputStream
- * The output stream to write to
- * @param length
- * The number of bytes to copy
- * @throws IOException
- * if an I/O exception occurs
- */
- public static void copy(InputStream inputStream, OutputStream outputStream, long length) throws IOException {
- copy(inputStream, outputStream, length, BUFFER_SIZE);
- }
-
- /**
- * Copies <code>length</code> bytes from the <code>inputStream</code> to
- * the <code>outputStream</code>.
- *
- * @param inputStream
- * The input stream to read from
- * @param outputStream
- * The output stream to write to
- * @param length
- * The number of bytes to copy
- * @param progressListener
- * The progress listener (may be {@code null})
- * @throws IOException
- * if an I/O exception occurs
- */
- public static void copy(InputStream inputStream, OutputStream outputStream, long length, ProgressListener progressListener) throws IOException {
- copy(inputStream, outputStream, length, BUFFER_SIZE, progressListener);
- }
-
- /**
- * Copies <code>length</code> bytes from the <code>inputStream</code> to
- * the <code>outputStream</code> using a buffer with the specified size
- *
- * @param inputStream
- * The input stream to read from
- * @param outputStream
- * The output stream to write to
- * @param length
- * The number of bytes to copy
- * @param bufferSize
- * The size of the copy buffer
- * @throws IOException
- * if an I/O exception occurs
- */
- public static void copy(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) throws IOException {
- copy(inputStream, outputStream, length, bufferSize, null);
- }
-
- /**
- * Copies <code>length</code> bytes from the <code>inputStream</code> to
- * the <code>outputStream</code> using a buffer with the specified size
- *
- * @param inputStream
- * The input stream to read from
- * @param outputStream
- * The output stream to write to
- * @param length
- * The number of bytes to copy
- * @param bufferSize
- * The size of the copy buffer
- * @param progressListener
- * The progress listener (may be {@code null})
- * @throws IOException
- * if an I/O exception occurs
- */
- public static void copy(InputStream inputStream, OutputStream outputStream, long length, int bufferSize, ProgressListener progressListener) throws IOException {
- long remaining = length;
- byte[] buffer = new byte[bufferSize];
- while (remaining > 0) {
- int read = inputStream.read(buffer, 0, (int) Math.min(Integer.MAX_VALUE, Math.min(bufferSize, remaining)));
- if (read == -1) {
- throw new EOFException();
- }
- outputStream.write(buffer, 0, read);
- remaining -= read;
- if (progressListener != null) {
- progressListener.onProgress(length - remaining, length);
- }
- }
- }
-
- /**
- * Interface for objects that want to be notified about the progress of a
- * {@link StreamCopier#copy()} operation.
- *
- * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
- */
- public static interface ProgressListener extends EventListener {
-
- /**
- * Notifiies a listener that a copy process made some progress.
- *
- * @param copied
- * The number of bytes that have already been copied
- * @param length
- * The total number of bytes that will be copied
- */
- public void onProgress(long copied, long length);
-
- }
-
-}
+++ /dev/null
-/*
- * jSite - TeeOutputStream.java - Copyright © 2010 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
- * the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-package de.todesbaum.util.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * {@link OutputStream} that sends all data it receives to multiple other output
- * streams. If an error occurs during a {@link #write(int)} to one of the
- * underlying output streams no guarantees are made about how much data is sent
- * to each stream, i.e. there is no good way to recover from such an error.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class TeeOutputStream extends OutputStream {
-
- /** The output streams. */
- private final OutputStream[] outputStreams;
-
- /**
- * Creates a new tee output stream that sends all to all given output
- * streams.
- *
- * @param outputStreams
- * The output streams to send all data to
- */
- public TeeOutputStream(OutputStream... outputStreams) {
- this.outputStreams = outputStreams;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * An effort is made to close all output streams. If multiple exceptions
- * occur, only the first exception is thrown after all output streams have
- * been tried to close.
- */
- @Override
- public void close() throws IOException {
- IOException occuredException = null;
- for (OutputStream outputStream : outputStreams) {
- try {
- outputStream.flush();
- } catch (IOException ioe1) {
- if (occuredException == null) {
- occuredException = ioe1;
- }
- }
- }
- if (occuredException != null) {
- throw occuredException;
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * An effort is made to flush all output streams. If multiple exceptions
- * occur, only the first exception is thrown after all output streams have
- * been tried to flush.
- */
- @Override
- public void flush() throws IOException {
- IOException occuredException = null;
- for (OutputStream outputStream : outputStreams) {
- try {
- outputStream.flush();
- } catch (IOException ioe1) {
- if (occuredException == null) {
- occuredException = ioe1;
- }
- }
- }
- if (occuredException != null) {
- throw occuredException;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(byte[] buffer) throws IOException {
- for (OutputStream outputStream : outputStreams) {
- outputStream.write(buffer);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(byte[] buffer, int offset, int length) throws IOException {
- for (OutputStream outputStream : outputStreams) {
- outputStream.write(buffer, offset, length);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(int data) throws IOException {
- for (OutputStream outputStream : outputStreams) {
- outputStream.write(data);
- }
- }
-
-}
+++ /dev/null
-/*
- * jSite - TempFileInputStream.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.io;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class TempFileInputStream extends FileInputStream {
-
- private File tempFile;
-
- /**
- * @param name
- * @throws FileNotFoundException
- */
- public TempFileInputStream(String name) throws FileNotFoundException {
- this(new File(name));
- }
-
- /**
- * @param file
- * @throws FileNotFoundException
- */
- public TempFileInputStream(File file) throws FileNotFoundException {
- super(file);
- tempFile = file;
- }
-
- @Override
- public void close() throws IOException {
- super.close();
- tempFile.delete();
- }
-
-}
+++ /dev/null
-/* taken from freenet (http://www.freenetproject.org/) */
-package de.todesbaum.util.mime;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Vector;
-
-/**
- * Holds the default MIME types.
- */
-public class DefaultMIMETypes {
-
- /** Default MIME type - what to set it to if we don't know any better */
- public static final String DEFAULT_MIME_TYPE = "application/octet-stream";
-
- /** MIME types: number -> name */
- private static List<String> mimeTypesByNumber = new Vector<String>();
-
- /** MIME types: name -> number */
- private static Map<String, Short> mimeTypesByName = new HashMap<String, Short>();
-
- /** MIME types by extension. One extension maps to one MIME type, but not necessarily
- * the other way around. */
- private static Map<String, Short> mimeTypesByExtension = new HashMap<String, Short>();
-
- /** Primary extension by MIME type number. */
- private static Map<Short, String> primaryExtensionByMimeNumber = new HashMap<Short, String>();
-
- /**
- * Add a MIME type, without any extensions.
- * @param number The number of the MIME type for compression. This *must not change*
- * for a given type, or the metadata format will be affected.
- * @param type The actual MIME type string. Do not include ;charset= etc; these are
- * parameters and there is a separate mechanism for them.
- */
- protected static synchronized void addMIMEType(short number, String type) {
- if(mimeTypesByNumber.size() > number) {
- String s = mimeTypesByNumber.get(number);
- if(s != null) throw new IllegalArgumentException("Already used: "+number);
- } else {
- mimeTypesByNumber.add(number, null);
- }
- mimeTypesByNumber.set(number, type);
- mimeTypesByName.put(type, new Short(number));
- }
-
- /**
- * Add a MIME type.
- * @param number The number of the MIME type for compression. This *must not change*
- * for a given type, or the metadata format will be affected.
- * @param type The actual MIME type string. Do not include ;charset= etc; these are
- * parameters and there is a separate mechanism for them.
- * @param extensions An array of common extensions for files of this type. Must be
- * unique for the type.
- */
- protected static synchronized void addMIMEType(short number, String type, String[] extensions, String outExtension) {
- addMIMEType(number, type);
- Short t = new Short(number);
- if(extensions != null) {
- for(int i=0;i<extensions.length;i++) {
- String ext = extensions[i].toLowerCase();
- if(mimeTypesByExtension.containsKey(ext)) {
- // No big deal
- //Short s = mimeTypesByExtension.get(ext);
- } else {
- // If only one, make it primary
- if(outExtension == null && extensions.length == 1)
- primaryExtensionByMimeNumber.put(t, ext);
- mimeTypesByExtension.put(ext, t);
- }
- }
- }
- if(outExtension != null)
- primaryExtensionByMimeNumber.put(t, outExtension);
-
- }
-
- /**
- * Add a MIME type, with extensions separated by spaces. This is more or less
- * the format in /etc/mime-types.
- */
- protected static synchronized void addMIMEType(short number, String type, String extensions) {
- addMIMEType(number, type, extensions.split(" "), null);
- }
-
- /**
- * Add a MIME type, with extensions separated by spaces. This is more or less
- * the format in /etc/mime-types.
- */
- protected static synchronized void addMIMEType(short number, String type, String extensions, String outExtension) {
- addMIMEType(number, type, extensions.split(" "), outExtension);
- }
-
- /**
- * Get a known MIME type by number.
- */
- public static String byNumber(short x) {
- if(x > mimeTypesByNumber.size() || x < 0)
- return null;
- return mimeTypesByNumber.get(x);
- }
-
- /**
- * Get the number of a MIME type, or -1 if it is not in the table of known MIME
- * types, in which case it will have to be sent uncompressed.
- */
- public static short byName(String s) {
- Short x = mimeTypesByName.get(s);
- if(x != null) return x.shortValue();
- return -1;
- }
-
- /* From toad's /etc/mime.types
- * cat /etc/mime.types | sed "/^$/d;/#/d" | tr --squeeze '\t' ' ' |
- * (y=0; while read x; do echo "$x" |
- * sed -n "s/^\([^ ]*\)$/addMIMEType\($y, \"\1\"\);/p;s/^\([^ (),]\+\) \(.*\)$/addMIMEType\($y, \"\1\", \"\2\"\);/p;"; y=$((y+1)); done)
- */
-
- static {
- addMIMEType((short) 0, "application/activemessage");
- addMIMEType((short) 1, "application/andrew-inset", "ez");
- addMIMEType((short) 2, "application/applefile");
- addMIMEType((short) 3, "application/atomicmail");
- addMIMEType((short) 4, "application/batch-SMTP");
- addMIMEType((short) 5, "application/beep+xml");
- addMIMEType((short) 6, "application/cals-1840");
- addMIMEType((short) 7, "application/commonground");
- addMIMEType((short) 8, "application/cu-seeme", "cu");
- addMIMEType((short) 9, "application/cybercash");
- addMIMEType((short) 10, "application/dca-rft");
- addMIMEType((short) 11, "application/dec-dx");
- addMIMEType((short) 12, "application/docbook+xml");
- addMIMEType((short) 13, "application/dsptype", "tsp");
- addMIMEType((short) 14, "application/dvcs");
- addMIMEType((short) 15, "application/edi-consent");
- addMIMEType((short) 16, "application/edi-x12");
- addMIMEType((short) 17, "application/edifact");
- addMIMEType((short) 18, "application/eshop");
- addMIMEType((short) 19, "application/font-tdpfr");
- addMIMEType((short) 20, "application/futuresplash", "spl");
- addMIMEType((short) 21, "application/ghostview");
- addMIMEType((short) 22, "application/hta", "hta");
- addMIMEType((short) 23, "application/http");
- addMIMEType((short) 24, "application/hyperstudio");
- addMIMEType((short) 25, "application/iges");
- addMIMEType((short) 26, "application/index");
- addMIMEType((short) 27, "application/index.cmd");
- addMIMEType((short) 28, "application/index.obj");
- addMIMEType((short) 29, "application/index.response");
- addMIMEType((short) 30, "application/index.vnd");
- addMIMEType((short) 31, "application/iotp");
- addMIMEType((short) 32, "application/ipp");
- addMIMEType((short) 33, "application/isup");
- addMIMEType((short) 34, "application/java-archive", "jar");
- addMIMEType((short) 35, "application/java-serialized-object", "ser");
- addMIMEType((short) 36, "application/java-vm", "class");
- addMIMEType((short) 37, "application/mac-binhex40", "hqx");
- addMIMEType((short) 38, "application/mac-compactpro", "cpt");
- addMIMEType((short) 39, "application/macwriteii");
- addMIMEType((short) 40, "application/marc");
- addMIMEType((short) 41, "application/mathematica", "nb");
- addMIMEType((short) 42, "application/mathematica-old");
- addMIMEType((short) 43, "application/msaccess", "mdb");
- addMIMEType((short) 44, "application/msword", "doc dot");
- addMIMEType((short) 45, "application/news-message-id");
- addMIMEType((short) 46, "application/news-transmission");
- addMIMEType((short) 47, "application/ocsp-request");
- addMIMEType((short) 48, "application/ocsp-response");
- addMIMEType((short) 49, "application/octet-stream", "bin");
- addMIMEType((short) 50, "application/oda", "oda");
- addMIMEType((short) 51, "application/ogg", "ogg");
- addMIMEType((short) 52, "application/parityfec");
- addMIMEType((short) 53, "application/pdf", "pdf");
- addMIMEType((short) 54, "application/pgp-encrypted");
- addMIMEType((short) 55, "application/pgp-keys", "key");
- addMIMEType((short) 56, "application/pgp-signature", "pgp");
- addMIMEType((short) 57, "application/pics-rules", "prf");
- addMIMEType((short) 58, "application/pkcs10");
- addMIMEType((short) 59, "application/pkcs7-mime");
- addMIMEType((short) 60, "application/pkcs7-signature");
- addMIMEType((short) 61, "application/pkix-cert");
- addMIMEType((short) 62, "application/pkix-crl");
- addMIMEType((short) 63, "application/pkixcmp");
- addMIMEType((short) 64, "application/postscript", "ps ai eps");
- addMIMEType((short) 65, "application/prs.alvestrand.titrax-sheet");
- addMIMEType((short) 66, "application/prs.cww");
- addMIMEType((short) 67, "application/prs.nprend");
- addMIMEType((short) 68, "application/qsig");
- addMIMEType((short) 69, "application/rar", "rar");
- addMIMEType((short) 70, "application/rdf+xml", "rdf");
- addMIMEType((short) 71, "application/remote-printing");
- addMIMEType((short) 72, "application/riscos");
- addMIMEType((short) 73, "application/rss+xml", "rss");
- addMIMEType((short) 74, "application/rtf");
- addMIMEType((short) 75, "application/sdp");
- addMIMEType((short) 76, "application/set-payment");
- addMIMEType((short) 77, "application/set-payment-initiation");
- addMIMEType((short) 78, "application/set-registration");
- addMIMEType((short) 79, "application/set-registration-initiation");
- addMIMEType((short) 80, "application/sgml");
- addMIMEType((short) 81, "application/sgml-open-catalog");
- addMIMEType((short) 82, "application/sieve");
- addMIMEType((short) 83, "application/slate");
- addMIMEType((short) 84, "application/smil", "smi smil");
- addMIMEType((short) 85, "application/timestamp-query");
- addMIMEType((short) 86, "application/timestamp-reply");
- addMIMEType((short) 87, "application/vemmi");
- addMIMEType((short) 88, "application/whoispp-query");
- addMIMEType((short) 89, "application/whoispp-response");
- addMIMEType((short) 90, "application/wita");
- addMIMEType((short) 91, "application/wordperfect", "wpd");
- addMIMEType((short) 92, "application/wordperfect5.1", "wp5");
- addMIMEType((short) 93, "application/x400-bp");
- addMIMEType((short) 94, "application/xhtml+xml", "xhtml xht");
- addMIMEType((short) 95, "application/xml", "xml xsl");
- addMIMEType((short) 96, "application/xml-dtd");
- addMIMEType((short) 97, "application/xml-external-parsed-entity");
- addMIMEType((short) 98, "application/zip", "zip");
- addMIMEType((short) 99, "application/vnd.3M.Post-it-Notes");
- addMIMEType((short) 100, "application/vnd.accpac.simply.aso");
- addMIMEType((short) 101, "application/vnd.accpac.simply.imp");
- addMIMEType((short) 102, "application/vnd.acucobol");
- addMIMEType((short) 103, "application/vnd.aether.imp");
- addMIMEType((short) 104, "application/vnd.anser-web-certificate-issue-initiation");
- addMIMEType((short) 105, "application/vnd.anser-web-funds-transfer-initiation");
- addMIMEType((short) 106, "application/vnd.audiograph");
- addMIMEType((short) 107, "application/vnd.bmi");
- addMIMEType((short) 108, "application/vnd.businessobjects");
- addMIMEType((short) 109, "application/vnd.canon-cpdl");
- addMIMEType((short) 110, "application/vnd.canon-lips");
- addMIMEType((short) 111, "application/vnd.cinderella", "cdy");
- addMIMEType((short) 112, "application/vnd.claymore");
- addMIMEType((short) 113, "application/vnd.commerce-battelle");
- addMIMEType((short) 114, "application/vnd.commonspace");
- addMIMEType((short) 115, "application/vnd.comsocaller");
- addMIMEType((short) 116, "application/vnd.contact.cmsg");
- addMIMEType((short) 117, "application/vnd.cosmocaller");
- addMIMEType((short) 118, "application/vnd.ctc-posml");
- addMIMEType((short) 119, "application/vnd.cups-postscript");
- addMIMEType((short) 120, "application/vnd.cups-raster");
- addMIMEType((short) 121, "application/vnd.cups-raw");
- addMIMEType((short) 122, "application/vnd.cybank");
- addMIMEType((short) 123, "application/vnd.dna");
- addMIMEType((short) 124, "application/vnd.dpgraph");
- addMIMEType((short) 125, "application/vnd.dxr");
- addMIMEType((short) 126, "application/vnd.ecdis-update");
- addMIMEType((short) 127, "application/vnd.ecowin.chart");
- addMIMEType((short) 128, "application/vnd.ecowin.filerequest");
- addMIMEType((short) 129, "application/vnd.ecowin.fileupdate");
- addMIMEType((short) 130, "application/vnd.ecowin.series");
- addMIMEType((short) 131, "application/vnd.ecowin.seriesrequest");
- addMIMEType((short) 132, "application/vnd.ecowin.seriesupdate");
- addMIMEType((short) 133, "application/vnd.enliven");
- addMIMEType((short) 134, "application/vnd.epson.esf");
- addMIMEType((short) 135, "application/vnd.epson.msf");
- addMIMEType((short) 136, "application/vnd.epson.quickanime");
- addMIMEType((short) 137, "application/vnd.epson.salt");
- addMIMEType((short) 138, "application/vnd.epson.ssf");
- addMIMEType((short) 139, "application/vnd.ericsson.quickcall");
- addMIMEType((short) 140, "application/vnd.eudora.data");
- addMIMEType((short) 141, "application/vnd.fdf");
- addMIMEType((short) 142, "application/vnd.ffsns");
- addMIMEType((short) 143, "application/vnd.flographit");
- addMIMEType((short) 144, "application/vnd.framemaker");
- addMIMEType((short) 145, "application/vnd.fsc.weblaunch");
- addMIMEType((short) 146, "application/vnd.fujitsu.oasys");
- addMIMEType((short) 147, "application/vnd.fujitsu.oasys2");
- addMIMEType((short) 148, "application/vnd.fujitsu.oasys3");
- addMIMEType((short) 149, "application/vnd.fujitsu.oasysgp");
- addMIMEType((short) 150, "application/vnd.fujitsu.oasysprs");
- addMIMEType((short) 151, "application/vnd.fujixerox.ddd");
- addMIMEType((short) 152, "application/vnd.fujixerox.docuworks");
- addMIMEType((short) 153, "application/vnd.fujixerox.docuworks.binder");
- addMIMEType((short) 154, "application/vnd.fut-misnet");
- addMIMEType((short) 155, "application/vnd.grafeq");
- addMIMEType((short) 156, "application/vnd.groove-account");
- addMIMEType((short) 157, "application/vnd.groove-identity-message");
- addMIMEType((short) 158, "application/vnd.groove-injector");
- addMIMEType((short) 159, "application/vnd.groove-tool-message");
- addMIMEType((short) 160, "application/vnd.groove-tool-template");
- addMIMEType((short) 161, "application/vnd.groove-vcard");
- addMIMEType((short) 162, "application/vnd.hhe.lesson-player");
- addMIMEType((short) 163, "application/vnd.hp-HPGL");
- addMIMEType((short) 164, "application/vnd.hp-PCL");
- addMIMEType((short) 165, "application/vnd.hp-PCLXL");
- addMIMEType((short) 166, "application/vnd.hp-hpid");
- addMIMEType((short) 167, "application/vnd.hp-hps");
- addMIMEType((short) 168, "application/vnd.httphone");
- addMIMEType((short) 169, "application/vnd.hzn-3d-crossword");
- addMIMEType((short) 170, "application/vnd.ibm.MiniPay");
- addMIMEType((short) 171, "application/vnd.ibm.afplinedata");
- addMIMEType((short) 172, "application/vnd.ibm.modcap");
- addMIMEType((short) 173, "application/vnd.informix-visionary");
- addMIMEType((short) 174, "application/vnd.intercon.formnet");
- addMIMEType((short) 175, "application/vnd.intertrust.digibox");
- addMIMEType((short) 176, "application/vnd.intertrust.nncp");
- addMIMEType((short) 177, "application/vnd.intu.qbo");
- addMIMEType((short) 178, "application/vnd.intu.qfx");
- addMIMEType((short) 179, "application/vnd.irepository.package+xml");
- addMIMEType((short) 180, "application/vnd.is-xpr");
- addMIMEType((short) 181, "application/vnd.japannet-directory-service");
- addMIMEType((short) 182, "application/vnd.japannet-jpnstore-wakeup");
- addMIMEType((short) 183, "application/vnd.japannet-payment-wakeup");
- addMIMEType((short) 184, "application/vnd.japannet-registration");
- addMIMEType((short) 185, "application/vnd.japannet-registration-wakeup");
- addMIMEType((short) 186, "application/vnd.japannet-setstore-wakeup");
- addMIMEType((short) 187, "application/vnd.japannet-verification");
- addMIMEType((short) 188, "application/vnd.japannet-verification-wakeup");
- addMIMEType((short) 189, "application/vnd.koan");
- addMIMEType((short) 190, "application/vnd.lotus-1-2-3");
- addMIMEType((short) 191, "application/vnd.lotus-approach");
- addMIMEType((short) 192, "application/vnd.lotus-freelance");
- addMIMEType((short) 193, "application/vnd.lotus-notes");
- addMIMEType((short) 194, "application/vnd.lotus-organizer");
- addMIMEType((short) 195, "application/vnd.lotus-screencam");
- addMIMEType((short) 196, "application/vnd.lotus-wordpro");
- addMIMEType((short) 197, "application/vnd.mcd");
- addMIMEType((short) 198, "application/vnd.mediastation.cdkey");
- addMIMEType((short) 199, "application/vnd.meridian-slingshot");
- addMIMEType((short) 200, "application/vnd.mif");
- addMIMEType((short) 201, "application/vnd.minisoft-hp3000-save");
- addMIMEType((short) 202, "application/vnd.mitsubishi.misty-guard.trustweb");
- addMIMEType((short) 203, "application/vnd.mobius.daf");
- addMIMEType((short) 204, "application/vnd.mobius.dis");
- addMIMEType((short) 205, "application/vnd.mobius.msl");
- addMIMEType((short) 206, "application/vnd.mobius.plc");
- addMIMEType((short) 207, "application/vnd.mobius.txf");
- addMIMEType((short) 208, "application/vnd.motorola.flexsuite");
- addMIMEType((short) 209, "application/vnd.motorola.flexsuite.adsi");
- addMIMEType((short) 210, "application/vnd.motorola.flexsuite.fis");
- addMIMEType((short) 211, "application/vnd.motorola.flexsuite.gotap");
- addMIMEType((short) 212, "application/vnd.motorola.flexsuite.kmr");
- addMIMEType((short) 213, "application/vnd.motorola.flexsuite.ttc");
- addMIMEType((short) 214, "application/vnd.motorola.flexsuite.wem");
- addMIMEType((short) 215, "application/vnd.mozilla.xul+xml", "xul");
- addMIMEType((short) 216, "application/vnd.ms-artgalry");
- addMIMEType((short) 217, "application/vnd.ms-asf");
- addMIMEType((short) 218, "application/vnd.ms-excel", "xls xlb xlt");
- addMIMEType((short) 219, "application/vnd.ms-lrm");
- addMIMEType((short) 220, "application/vnd.ms-pki.seccat", "cat");
- addMIMEType((short) 221, "application/vnd.ms-pki.stl", "stl");
- addMIMEType((short) 222, "application/vnd.ms-powerpoint", "ppt pps");
- addMIMEType((short) 223, "application/vnd.ms-project");
- addMIMEType((short) 224, "application/vnd.ms-tnef");
- addMIMEType((short) 225, "application/vnd.ms-works");
- addMIMEType((short) 226, "application/vnd.mseq");
- addMIMEType((short) 227, "application/vnd.msign");
- addMIMEType((short) 228, "application/vnd.music-niff");
- addMIMEType((short) 229, "application/vnd.musician");
- addMIMEType((short) 230, "application/vnd.netfpx");
- addMIMEType((short) 231, "application/vnd.noblenet-directory");
- addMIMEType((short) 232, "application/vnd.noblenet-sealer");
- addMIMEType((short) 233, "application/vnd.noblenet-web");
- addMIMEType((short) 234, "application/vnd.novadigm.EDM");
- addMIMEType((short) 235, "application/vnd.novadigm.EDX");
- addMIMEType((short) 236, "application/vnd.novadigm.EXT");
- addMIMEType((short) 237, "application/vnd.oasis.opendocument.chart", "odc");
- addMIMEType((short) 238, "application/vnd.oasis.opendocument.database", "odb");
- addMIMEType((short) 239, "application/vnd.oasis.opendocument.formula", "odf");
- addMIMEType((short) 240, "application/vnd.oasis.opendocument.graphics", "odg");
- addMIMEType((short) 241, "application/vnd.oasis.opendocument.graphics-template", "otg");
- addMIMEType((short) 242, "application/vnd.oasis.opendocument.image", "odi");
- addMIMEType((short) 243, "application/vnd.oasis.opendocument.presentation", "odp");
- addMIMEType((short) 244, "application/vnd.oasis.opendocument.presentation-template", "otp");
- addMIMEType((short) 245, "application/vnd.oasis.opendocument.spreadsheet", "ods");
- addMIMEType((short) 246, "application/vnd.oasis.opendocument.spreadsheet-template", "ots");
- addMIMEType((short) 247, "application/vnd.oasis.opendocument.text", "odt");
- addMIMEType((short) 248, "application/vnd.oasis.opendocument.text-master", "odm");
- addMIMEType((short) 249, "application/vnd.oasis.opendocument.text-template", "ott");
- addMIMEType((short) 250, "application/vnd.oasis.opendocument.text-web", "oth");
- addMIMEType((short) 251, "application/vnd.osa.netdeploy");
- addMIMEType((short) 252, "application/vnd.palm");
- addMIMEType((short) 253, "application/vnd.pg.format");
- addMIMEType((short) 254, "application/vnd.pg.osasli");
- addMIMEType((short) 255, "application/vnd.powerbuilder6");
- addMIMEType((short) 256, "application/vnd.powerbuilder6-s");
- addMIMEType((short) 257, "application/vnd.powerbuilder7");
- addMIMEType((short) 258, "application/vnd.powerbuilder7-s");
- addMIMEType((short) 259, "application/vnd.powerbuilder75");
- addMIMEType((short) 260, "application/vnd.powerbuilder75-s");
- addMIMEType((short) 261, "application/vnd.previewsystems.box");
- addMIMEType((short) 262, "application/vnd.publishare-delta-tree");
- addMIMEType((short) 263, "application/vnd.pvi.ptid1");
- addMIMEType((short) 264, "application/vnd.pwg-xhtml-print+xml");
- addMIMEType((short) 265, "application/vnd.rapid");
- addMIMEType((short) 266, "application/vnd.rim.cod", "cod");
- addMIMEType((short) 267, "application/vnd.s3sms");
- addMIMEType((short) 268, "application/vnd.seemail");
- addMIMEType((short) 269, "application/vnd.shana.informed.formdata");
- addMIMEType((short) 270, "application/vnd.shana.informed.formtemplate");
- addMIMEType((short) 271, "application/vnd.shana.informed.interchange");
- addMIMEType((short) 272, "application/vnd.shana.informed.package");
- addMIMEType((short) 273, "application/vnd.smaf", "mmf");
- addMIMEType((short) 274, "application/vnd.sss-cod");
- addMIMEType((short) 275, "application/vnd.sss-dtf");
- addMIMEType((short) 276, "application/vnd.sss-ntf");
- addMIMEType((short) 277, "application/vnd.stardivision.calc", "sdc");
- addMIMEType((short) 278, "application/vnd.stardivision.draw", "sda");
- addMIMEType((short) 279, "application/vnd.stardivision.impress", "sdd sdp");
- addMIMEType((short) 280, "application/vnd.stardivision.math", "smf");
- addMIMEType((short) 281, "application/vnd.stardivision.writer", "sdw vor");
- addMIMEType((short) 282, "application/vnd.stardivision.writer-global", "sgl");
- addMIMEType((short) 283, "application/vnd.street-stream");
- addMIMEType((short) 284, "application/vnd.sun.xml.calc", "sxc");
- addMIMEType((short) 285, "application/vnd.sun.xml.calc.template", "stc");
- addMIMEType((short) 286, "application/vnd.sun.xml.draw", "sxd");
- addMIMEType((short) 287, "application/vnd.sun.xml.draw.template", "std");
- addMIMEType((short) 288, "application/vnd.sun.xml.impress", "sxi");
- addMIMEType((short) 289, "application/vnd.sun.xml.impress.template", "sti");
- addMIMEType((short) 290, "application/vnd.sun.xml.math", "sxm");
- addMIMEType((short) 291, "application/vnd.sun.xml.writer", "sxw");
- addMIMEType((short) 292, "application/vnd.sun.xml.writer.global", "sxg");
- addMIMEType((short) 293, "application/vnd.sun.xml.writer.template", "stw");
- addMIMEType((short) 294, "application/vnd.svd");
- addMIMEType((short) 295, "application/vnd.swiftview-ics");
- addMIMEType((short) 296, "application/vnd.symbian.install", "sis");
- addMIMEType((short) 297, "application/vnd.triscape.mxs");
- addMIMEType((short) 298, "application/vnd.trueapp");
- addMIMEType((short) 299, "application/vnd.truedoc");
- addMIMEType((short) 300, "application/vnd.tve-trigger");
- addMIMEType((short) 301, "application/vnd.ufdl");
- addMIMEType((short) 302, "application/vnd.uplanet.alert");
- addMIMEType((short) 303, "application/vnd.uplanet.alert-wbxml");
- addMIMEType((short) 304, "application/vnd.uplanet.bearer-choice");
- addMIMEType((short) 305, "application/vnd.uplanet.bearer-choice-wbxml");
- addMIMEType((short) 306, "application/vnd.uplanet.cacheop");
- addMIMEType((short) 307, "application/vnd.uplanet.cacheop-wbxml");
- addMIMEType((short) 308, "application/vnd.uplanet.channel");
- addMIMEType((short) 309, "application/vnd.uplanet.channel-wbxml");
- addMIMEType((short) 310, "application/vnd.uplanet.list");
- addMIMEType((short) 311, "application/vnd.uplanet.list-wbxml");
- addMIMEType((short) 312, "application/vnd.uplanet.listcmd");
- addMIMEType((short) 313, "application/vnd.uplanet.listcmd-wbxml");
- addMIMEType((short) 314, "application/vnd.uplanet.signal");
- addMIMEType((short) 315, "application/vnd.vcx");
- addMIMEType((short) 316, "application/vnd.vectorworks");
- addMIMEType((short) 317, "application/vnd.vidsoft.vidconference");
- addMIMEType((short) 318, "application/vnd.visio", "vsd");
- addMIMEType((short) 319, "application/vnd.vividence.scriptfile");
- addMIMEType((short) 320, "application/vnd.wap.sic");
- addMIMEType((short) 321, "application/vnd.wap.slc");
- addMIMEType((short) 322, "application/vnd.wap.wbxml", "wbxml");
- addMIMEType((short) 323, "application/vnd.wap.wmlc", "wmlc");
- addMIMEType((short) 324, "application/vnd.wap.wmlscriptc", "wmlsc");
- addMIMEType((short) 325, "application/vnd.webturbo");
- addMIMEType((short) 326, "application/vnd.wrq-hp3000-labelled");
- addMIMEType((short) 327, "application/vnd.wt.stf");
- addMIMEType((short) 328, "application/vnd.xara");
- addMIMEType((short) 329, "application/vnd.xfdl");
- addMIMEType((short) 330, "application/vnd.yellowriver-custom-menu");
- addMIMEType((short) 331, "application/x-123", "wk");
- addMIMEType((short) 332, "application/x-abiword", "abw");
- addMIMEType((short) 333, "application/x-apple-diskimage", "dmg");
- addMIMEType((short) 334, "application/x-bcpio", "bcpio");
- addMIMEType((short) 335, "application/x-bittorrent", "torrent");
- addMIMEType((short) 336, "application/x-cdf", "cdf");
- addMIMEType((short) 337, "application/x-cdlink", "vcd");
- addMIMEType((short) 338, "application/x-chess-pgn", "pgn");
- addMIMEType((short) 339, "application/x-core");
- addMIMEType((short) 340, "application/x-cpio", "cpio");
- addMIMEType((short) 341, "application/x-csh", "csh");
- addMIMEType((short) 342, "application/x-debian-package", "deb udeb");
- addMIMEType((short) 343, "application/x-director", "dcr dir dxr");
- addMIMEType((short) 344, "application/x-dms", "dms");
- addMIMEType((short) 345, "application/x-doom", "wad");
- addMIMEType((short) 346, "application/x-dvi", "dvi");
- addMIMEType((short) 347, "application/x-executable");
- addMIMEType((short) 348, "application/x-flac", "flac");
- addMIMEType((short) 349, "application/x-font", "pfa pfb gsf pcf pcf.Z");
- addMIMEType((short) 350, "application/x-freemind", "mm");
- addMIMEType((short) 351, "application/x-futuresplash", "spl");
- addMIMEType((short) 352, "application/x-gnumeric", "gnumeric");
- addMIMEType((short) 353, "application/x-go-sgf", "sgf");
- addMIMEType((short) 354, "application/x-graphing-calculator", "gcf");
- addMIMEType((short) 355, "application/x-gtar", "gtar tgz taz");
- addMIMEType((short) 356, "application/x-hdf", "hdf");
- addMIMEType((short) 357, "application/x-httpd-php", "phtml pht php");
- addMIMEType((short) 358, "application/x-httpd-php-source", "phps");
- addMIMEType((short) 359, "application/x-httpd-php3", "php3");
- addMIMEType((short) 360, "application/x-httpd-php3-preprocessed", "php3p");
- addMIMEType((short) 361, "application/x-httpd-php4", "php4");
- addMIMEType((short) 362, "application/x-ica", "ica");
- addMIMEType((short) 363, "application/x-internet-signup", "ins isp");
- addMIMEType((short) 364, "application/x-iphone", "iii");
- addMIMEType((short) 365, "application/x-iso9660-image", "iso");
- addMIMEType((short) 366, "application/x-java-applet");
- addMIMEType((short) 367, "application/x-java-bean");
- addMIMEType((short) 368, "application/x-java-jnlp-file", "jnlp");
- addMIMEType((short) 369, "application/x-javascript", "js");
- addMIMEType((short) 370, "application/x-jmol", "jmz");
- addMIMEType((short) 371, "application/x-kchart", "chrt");
- addMIMEType((short) 372, "application/x-kdelnk");
- addMIMEType((short) 373, "application/x-killustrator", "kil");
- addMIMEType((short) 374, "application/x-koan", "skp skd skt skm");
- addMIMEType((short) 375, "application/x-kpresenter", "kpr kpt");
- addMIMEType((short) 376, "application/x-kspread", "ksp");
- addMIMEType((short) 377, "application/x-kword", "kwd kwt");
- addMIMEType((short) 378, "application/x-latex", "latex");
- addMIMEType((short) 379, "application/x-lha", "lha");
- addMIMEType((short) 380, "application/x-lzh", "lzh");
- addMIMEType((short) 381, "application/x-lzx", "lzx");
- addMIMEType((short) 382, "application/x-maker", "frm maker frame fm fb book fbdoc");
- addMIMEType((short) 383, "application/x-mif", "mif");
- addMIMEType((short) 384, "application/x-ms-wmd", "wmd");
- addMIMEType((short) 385, "application/x-ms-wmz", "wmz");
- addMIMEType((short) 386, "application/x-msdos-program", "com exe bat dll");
- addMIMEType((short) 387, "application/x-msi", "msi");
- addMIMEType((short) 388, "application/x-netcdf", "nc");
- addMIMEType((short) 389, "application/x-ns-proxy-autoconfig", "pac");
- addMIMEType((short) 390, "application/x-nwc", "nwc");
- addMIMEType((short) 391, "application/x-object", "o");
- addMIMEType((short) 392, "application/x-oz-application", "oza");
- addMIMEType((short) 393, "application/x-pkcs7-certreqresp", "p7r");
- addMIMEType((short) 394, "application/x-pkcs7-crl", "crl");
- addMIMEType((short) 395, "application/x-python-code", "pyc pyo");
- addMIMEType((short) 396, "application/x-quicktimeplayer", "qtl");
- addMIMEType((short) 397, "application/x-redhat-package-manager", "rpm");
- addMIMEType((short) 398, "application/x-rx");
- addMIMEType((short) 399, "application/x-sh", "sh");
- addMIMEType((short) 400, "application/x-shar", "shar");
- addMIMEType((short) 401, "application/x-shellscript");
- addMIMEType((short) 402, "application/x-shockwave-flash", "swf swfl");
- addMIMEType((short) 403, "application/x-stuffit", "sit");
- addMIMEType((short) 404, "application/x-sv4cpio", "sv4cpio");
- addMIMEType((short) 405, "application/x-sv4crc", "sv4crc");
- addMIMEType((short) 406, "application/x-tar", "tar");
- addMIMEType((short) 407, "application/x-tcl", "tcl");
- addMIMEType((short) 408, "application/x-tex-gf", "gf");
- addMIMEType((short) 409, "application/x-tex-pk", "pk");
- addMIMEType((short) 410, "application/x-texinfo", "texinfo texi");
- addMIMEType((short) 411, "application/x-trash", "~ % bak old sik");
- addMIMEType((short) 412, "application/x-troff", "t tr roff");
- addMIMEType((short) 413, "application/x-troff-man", "man");
- addMIMEType((short) 414, "application/x-troff-me", "me");
- addMIMEType((short) 415, "application/x-troff-ms", "ms");
- addMIMEType((short) 416, "application/x-ustar", "ustar");
- addMIMEType((short) 417, "application/x-videolan");
- addMIMEType((short) 418, "application/x-wais-source", "src");
- addMIMEType((short) 419, "application/x-wingz", "wz");
- addMIMEType((short) 420, "application/x-x509-ca-cert", "crt");
- addMIMEType((short) 421, "application/x-xcf", "xcf");
- addMIMEType((short) 422, "application/x-xfig", "fig");
- addMIMEType((short) 423, "application/x-xpinstall", "xpi");
- addMIMEType((short) 424, "audio/32kadpcm");
- addMIMEType((short) 425, "audio/basic", "au snd");
- addMIMEType((short) 426, "audio/g.722.1");
- addMIMEType((short) 427, "audio/l16");
- addMIMEType((short) 428, "audio/midi", "mid midi kar");
- addMIMEType((short) 429, "audio/mp4a-latm");
- addMIMEType((short) 430, "audio/mpa-robust");
- addMIMEType((short) 431, "audio/mpeg", "mpga mpega mp2 mp3 m4a");
- addMIMEType((short) 432, "audio/mpegurl", "m3u");
- addMIMEType((short) 433, "audio/parityfec");
- addMIMEType((short) 434, "audio/prs.sid", "sid");
- addMIMEType((short) 435, "audio/telephone-event");
- addMIMEType((short) 436, "audio/tone");
- addMIMEType((short) 437, "audio/vnd.cisco.nse");
- addMIMEType((short) 438, "audio/vnd.cns.anp1");
- addMIMEType((short) 439, "audio/vnd.cns.inf1");
- addMIMEType((short) 440, "audio/vnd.digital-winds");
- addMIMEType((short) 441, "audio/vnd.everad.plj");
- addMIMEType((short) 442, "audio/vnd.lucent.voice");
- addMIMEType((short) 443, "audio/vnd.nortel.vbk");
- addMIMEType((short) 444, "audio/vnd.nuera.ecelp4800");
- addMIMEType((short) 445, "audio/vnd.nuera.ecelp7470");
- addMIMEType((short) 446, "audio/vnd.nuera.ecelp9600");
- addMIMEType((short) 447, "audio/vnd.octel.sbc");
- addMIMEType((short) 448, "audio/vnd.qcelp");
- addMIMEType((short) 449, "audio/vnd.rhetorex.32kadpcm");
- addMIMEType((short) 450, "audio/vnd.vmx.cvsd");
- addMIMEType((short) 451, "audio/x-aiff", "aif aiff aifc");
- addMIMEType((short) 452, "audio/x-gsm", "gsm");
- addMIMEType((short) 453, "audio/x-mpegurl", "m3u");
- addMIMEType((short) 454, "audio/x-ms-wma", "wma");
- addMIMEType((short) 455, "audio/x-ms-wax", "wax");
- addMIMEType((short) 456, "audio/x-pn-realaudio-plugin");
- addMIMEType((short) 457, "audio/x-pn-realaudio", "ra rm ram");
- addMIMEType((short) 458, "audio/x-realaudio", "ra");
- addMIMEType((short) 459, "audio/x-scpls", "pls");
- addMIMEType((short) 460, "audio/x-sd2", "sd2");
- addMIMEType((short) 461, "audio/x-wav", "wav");
- addMIMEType((short) 462, "chemical/x-alchemy", "alc");
- addMIMEType((short) 463, "chemical/x-cache", "cac cache");
- addMIMEType((short) 464, "chemical/x-cache-csf", "csf");
- addMIMEType((short) 465, "chemical/x-cactvs-binary", "cbin cascii ctab");
- addMIMEType((short) 466, "chemical/x-cdx", "cdx");
- addMIMEType((short) 467, "chemical/x-cerius", "cer");
- addMIMEType((short) 468, "chemical/x-chem3d", "c3d");
- addMIMEType((short) 469, "chemical/x-chemdraw", "chm");
- addMIMEType((short) 470, "chemical/x-cif", "cif");
- addMIMEType((short) 471, "chemical/x-cmdf", "cmdf");
- addMIMEType((short) 472, "chemical/x-cml", "cml");
- addMIMEType((short) 473, "chemical/x-compass", "cpa");
- addMIMEType((short) 474, "chemical/x-crossfire", "bsd");
- addMIMEType((short) 475, "chemical/x-csml", "csml csm");
- addMIMEType((short) 476, "chemical/x-ctx", "ctx");
- addMIMEType((short) 477, "chemical/x-cxf", "cxf cef");
- addMIMEType((short) 478, "chemical/x-embl-dl-nucleotide", "emb embl");
- addMIMEType((short) 479, "chemical/x-galactic-spc", "spc");
- addMIMEType((short) 480, "chemical/x-gamess-input", "inp gam gamin");
- addMIMEType((short) 481, "chemical/x-gaussian-checkpoint", "fch fchk");
- addMIMEType((short) 482, "chemical/x-gaussian-cube", "cub");
- addMIMEType((short) 483, "chemical/x-gaussian-input", "gau gjc gjf");
- addMIMEType((short) 484, "chemical/x-gaussian-log", "gal");
- addMIMEType((short) 485, "chemical/x-gcg8-sequence", "gcg");
- addMIMEType((short) 486, "chemical/x-genbank", "gen");
- addMIMEType((short) 487, "chemical/x-hin", "hin");
- addMIMEType((short) 488, "chemical/x-isostar", "istr ist");
- addMIMEType((short) 489, "chemical/x-jcamp-dx", "jdx dx");
- addMIMEType((short) 490, "chemical/x-kinemage", "kin");
- addMIMEType((short) 491, "chemical/x-macmolecule", "mcm");
- addMIMEType((short) 492, "chemical/x-macromodel-input", "mmd mmod");
- addMIMEType((short) 493, "chemical/x-mdl-molfile", "mol");
- addMIMEType((short) 494, "chemical/x-mdl-rdfile", "rd");
- addMIMEType((short) 495, "chemical/x-mdl-rxnfile", "rxn");
- addMIMEType((short) 496, "chemical/x-mdl-sdfile", "sd sdf");
- addMIMEType((short) 497, "chemical/x-mdl-tgf", "tgf");
- addMIMEType((short) 498, "chemical/x-mmcif", "mcif");
- addMIMEType((short) 499, "chemical/x-mol2", "mol2");
- addMIMEType((short) 500, "chemical/x-molconn-Z", "b");
- addMIMEType((short) 501, "chemical/x-mopac-graph", "gpt");
- addMIMEType((short) 502, "chemical/x-mopac-input", "mop mopcrt mpc dat zmt");
- addMIMEType((short) 503, "chemical/x-mopac-out", "moo");
- addMIMEType((short) 504, "chemical/x-mopac-vib", "mvb");
- addMIMEType((short) 505, "chemical/x-ncbi-asn1", "asn");
- addMIMEType((short) 506, "chemical/x-ncbi-asn1-ascii", "prt ent");
- addMIMEType((short) 507, "chemical/x-ncbi-asn1-binary", "val aso");
- addMIMEType((short) 508, "chemical/x-ncbi-asn1-spec", "asn");
- addMIMEType((short) 509, "chemical/x-pdb", "pdb ent");
- addMIMEType((short) 510, "chemical/x-rosdal", "ros");
- addMIMEType((short) 511, "chemical/x-swissprot", "sw");
- addMIMEType((short) 512, "chemical/x-vamas-iso14976", "vms");
- addMIMEType((short) 513, "chemical/x-vmd", "vmd");
- addMIMEType((short) 514, "chemical/x-xtel", "xtel");
- addMIMEType((short) 515, "chemical/x-xyz", "xyz");
- addMIMEType((short) 516, "image/cgm");
- addMIMEType((short) 517, "image/g3fax");
- addMIMEType((short) 518, "image/gif", "gif");
- addMIMEType((short) 519, "image/ief", "ief");
- addMIMEType((short) 520, "image/jpeg", "jpeg jpg jpe");
- addMIMEType((short) 521, "image/naplps");
- addMIMEType((short) 522, "image/pcx", "pcx");
- addMIMEType((short) 523, "image/png", "png");
- addMIMEType((short) 524, "image/prs.btif");
- addMIMEType((short) 525, "image/prs.pti");
- addMIMEType((short) 526, "image/svg+xml", "svg svgz");
- addMIMEType((short) 527, "image/tiff", "tiff tif");
- addMIMEType((short) 528, "image/vnd.cns.inf2");
- addMIMEType((short) 529, "image/vnd.djvu", "djvu djv");
- addMIMEType((short) 530, "image/vnd.dwg");
- addMIMEType((short) 531, "image/vnd.dxf");
- addMIMEType((short) 532, "image/vnd.fastbidsheet");
- addMIMEType((short) 533, "image/vnd.fpx");
- addMIMEType((short) 534, "image/vnd.fst");
- addMIMEType((short) 535, "image/vnd.fujixerox.edmics-mmr");
- addMIMEType((short) 536, "image/vnd.fujixerox.edmics-rlc");
- addMIMEType((short) 537, "image/vnd.mix");
- addMIMEType((short) 538, "image/vnd.net-fpx");
- addMIMEType((short) 539, "image/vnd.svf");
- addMIMEType((short) 540, "image/vnd.wap.wbmp", "wbmp");
- addMIMEType((short) 541, "image/vnd.xiff");
- addMIMEType((short) 542, "image/x-cmu-raster", "ras");
- addMIMEType((short) 543, "image/x-coreldraw", "cdr");
- addMIMEType((short) 544, "image/x-coreldrawpattern", "pat");
- addMIMEType((short) 545, "image/x-coreldrawtemplate", "cdt");
- addMIMEType((short) 546, "image/x-corelphotopaint", "cpt");
- addMIMEType((short) 547, "image/x-icon", "ico");
- addMIMEType((short) 548, "image/x-jg", "art");
- addMIMEType((short) 549, "image/x-jng", "jng");
- addMIMEType((short) 550, "image/x-ms-bmp", "bmp");
- addMIMEType((short) 551, "image/x-photoshop", "psd");
- addMIMEType((short) 552, "image/x-portable-anymap", "pnm");
- addMIMEType((short) 553, "image/x-portable-bitmap", "pbm");
- addMIMEType((short) 554, "image/x-portable-graymap", "pgm");
- addMIMEType((short) 555, "image/x-portable-pixmap", "ppm");
- addMIMEType((short) 556, "image/x-rgb", "rgb");
- addMIMEType((short) 557, "image/x-xbitmap", "xbm");
- addMIMEType((short) 558, "image/x-xpixmap", "xpm");
- addMIMEType((short) 559, "image/x-xwindowdump", "xwd");
- addMIMEType((short) 560, "inode/chardevice");
- addMIMEType((short) 561, "inode/blockdevice");
- addMIMEType((short) 562, "inode/directory-locked");
- addMIMEType((short) 563, "inode/directory");
- addMIMEType((short) 564, "inode/fifo");
- addMIMEType((short) 565, "inode/socket");
- addMIMEType((short) 566, "message/delivery-status");
- addMIMEType((short) 567, "message/disposition-notification");
- addMIMEType((short) 568, "message/external-body");
- addMIMEType((short) 569, "message/http");
- addMIMEType((short) 570, "message/s-http");
- addMIMEType((short) 571, "message/news");
- addMIMEType((short) 572, "message/partial");
- addMIMEType((short) 573, "message/rfc822");
- addMIMEType((short) 574, "model/iges", "igs iges");
- addMIMEType((short) 575, "model/mesh", "msh mesh silo");
- addMIMEType((short) 576, "model/vnd.dwf");
- addMIMEType((short) 577, "model/vnd.flatland.3dml");
- addMIMEType((short) 578, "model/vnd.gdl");
- addMIMEType((short) 579, "model/vnd.gs-gdl");
- addMIMEType((short) 580, "model/vnd.gtw");
- addMIMEType((short) 581, "model/vnd.mts");
- addMIMEType((short) 582, "model/vnd.vtu");
- addMIMEType((short) 583, "model/vrml", "wrl vrml");
- addMIMEType((short) 584, "multipart/alternative");
- addMIMEType((short) 585, "multipart/appledouble");
- addMIMEType((short) 586, "multipart/byteranges");
- addMIMEType((short) 587, "multipart/digest");
- addMIMEType((short) 588, "multipart/encrypted");
- addMIMEType((short) 589, "multipart/form-data");
- addMIMEType((short) 590, "multipart/header-set");
- addMIMEType((short) 591, "multipart/mixed");
- addMIMEType((short) 592, "multipart/parallel");
- addMIMEType((short) 593, "multipart/related");
- addMIMEType((short) 594, "multipart/report");
- addMIMEType((short) 595, "multipart/signed");
- addMIMEType((short) 596, "multipart/voice-message");
- addMIMEType((short) 597, "text/calendar", "ics icz");
- addMIMEType((short) 598, "text/comma-separated-values", "csv");
- addMIMEType((short) 599, "text/css", "css");
- addMIMEType((short) 600, "text/directory");
- addMIMEType((short) 601, "text/english");
- addMIMEType((short) 602, "text/enriched");
- addMIMEType((short) 603, "text/h323", "323");
- addMIMEType((short) 604, "text/html", "html htm shtml");
- addMIMEType((short) 605, "text/iuls", "uls");
- addMIMEType((short) 606, "text/mathml", "mml");
- addMIMEType((short) 607, "text/parityfec");
- addMIMEType((short) 608, "text/plain", "asc txt text diff pot");
- addMIMEType((short) 609, "text/prs.lines.tag");
- addMIMEType((short) 610, "text/x-psp", "psp");
- addMIMEType((short) 611, "text/rfc822-headers");
- addMIMEType((short) 612, "text/richtext", "rtx");
- addMIMEType((short) 613, "text/rtf", "rtf");
- addMIMEType((short) 614, "text/scriptlet", "sct wsc");
- addMIMEType((short) 615, "text/t140");
- addMIMEType((short) 616, "text/texmacs", "tm ts");
- addMIMEType((short) 617, "text/tab-separated-values", "tsv");
- addMIMEType((short) 618, "text/uri-list");
- addMIMEType((short) 619, "text/vnd.abc");
- addMIMEType((short) 620, "text/vnd.curl");
- addMIMEType((short) 621, "text/vnd.DMClientScript");
- addMIMEType((short) 622, "text/vnd.flatland.3dml");
- addMIMEType((short) 623, "text/vnd.fly");
- addMIMEType((short) 624, "text/vnd.fmi.flexstor");
- addMIMEType((short) 625, "text/vnd.in3d.3dml");
- addMIMEType((short) 626, "text/vnd.in3d.spot");
- addMIMEType((short) 627, "text/vnd.IPTC.NewsML");
- addMIMEType((short) 628, "text/vnd.IPTC.NITF");
- addMIMEType((short) 629, "text/vnd.latex-z");
- addMIMEType((short) 630, "text/vnd.motorola.reflex");
- addMIMEType((short) 631, "text/vnd.ms-mediapackage");
- addMIMEType((short) 632, "text/vnd.sun.j2me.app-descriptor", "jad");
- addMIMEType((short) 633, "text/vnd.wap.si");
- addMIMEType((short) 634, "text/vnd.wap.sl");
- addMIMEType((short) 635, "text/vnd.wap.wml", "wml");
- addMIMEType((short) 636, "text/vnd.wap.wmlscript", "wmls");
- addMIMEType((short) 637, "text/x-bibtex", "bib");
- addMIMEType((short) 638, "text/x-c++hdr", "h++ hpp hxx hh");
- addMIMEType((short) 639, "text/x-c++src", "c++ cpp cxx cc");
- addMIMEType((short) 640, "text/x-chdr", "h");
- addMIMEType((short) 641, "text/x-crontab");
- addMIMEType((short) 642, "text/x-csh", "csh");
- addMIMEType((short) 643, "text/x-csrc", "c");
- addMIMEType((short) 644, "text/x-haskell", "hs");
- addMIMEType((short) 645, "text/x-java", "java");
- addMIMEType((short) 646, "text/x-literate-haskell", "lhs");
- addMIMEType((short) 647, "text/x-makefile");
- addMIMEType((short) 648, "text/x-moc", "moc");
- addMIMEType((short) 649, "text/x-pascal", "p pas");
- addMIMEType((short) 650, "text/x-pcs-gcd", "gcd");
- addMIMEType((short) 651, "text/x-perl", "pl pm");
- addMIMEType((short) 652, "text/x-python", "py");
- addMIMEType((short) 653, "text/x-server-parsed-html");
- addMIMEType((short) 654, "text/x-setext", "etx");
- addMIMEType((short) 655, "text/x-sh", "sh");
- addMIMEType((short) 656, "text/x-tcl", "tcl tk");
- addMIMEType((short) 657, "text/x-tex", "tex ltx sty cls");
- addMIMEType((short) 658, "text/x-vcalendar", "vcs");
- addMIMEType((short) 659, "text/x-vcard", "vcf");
- addMIMEType((short) 660, "video/dl", "dl");
- addMIMEType((short) 661, "video/dv", "dif dv");
- addMIMEType((short) 662, "video/fli", "fli");
- addMIMEType((short) 663, "video/gl", "gl");
- addMIMEType((short) 664, "video/mpeg", "mpeg mpg mpe");
- addMIMEType((short) 665, "video/mp4", "mp4");
- addMIMEType((short) 666, "video/quicktime", "qt mov");
- addMIMEType((short) 667, "video/mp4v-es");
- addMIMEType((short) 668, "video/parityfec");
- addMIMEType((short) 669, "video/pointer");
- addMIMEType((short) 670, "video/vnd.fvt");
- addMIMEType((short) 671, "video/vnd.motorola.video");
- addMIMEType((short) 672, "video/vnd.motorola.videop");
- addMIMEType((short) 673, "video/vnd.mpegurl", "mxu");
- addMIMEType((short) 674, "video/vnd.mts");
- addMIMEType((short) 675, "video/vnd.nokia.interleaved-multimedia");
- addMIMEType((short) 676, "video/vnd.vivo");
- addMIMEType((short) 677, "video/x-la-asf", "lsf lsx");
- addMIMEType((short) 678, "video/x-mng", "mng");
- addMIMEType((short) 679, "video/x-ms-asf", "asf asx");
- addMIMEType((short) 680, "video/x-ms-wm", "wm");
- addMIMEType((short) 681, "video/x-ms-wmv", "wmv");
- addMIMEType((short) 682, "video/x-ms-wmx", "wmx");
- addMIMEType((short) 683, "video/x-ms-wvx", "wvx");
- addMIMEType((short) 684, "video/x-msvideo", "avi");
- addMIMEType((short) 685, "video/x-sgi-movie", "movie");
- addMIMEType((short) 686, "x-conference/x-cooltalk", "ice");
- addMIMEType((short) 687, "x-world/x-vrml", "vrm vrml wrl");
- }
-
- /** Guess a MIME type from a filename */
- public static String guessMIMEType(String arg) {
- int x = arg.lastIndexOf('.');
- if(x == -1 || x == arg.length()-1)
- return DEFAULT_MIME_TYPE;
- String ext = arg.substring(x+1).toLowerCase();
- Short mimeIndexOb = mimeTypesByExtension.get(ext);
- if(mimeIndexOb != null) {
- return mimeTypesByNumber.get(mimeIndexOb.intValue());
- }
- return DEFAULT_MIME_TYPE;
- }
-
- public static String getExtension(String type) {
- short typeNumber = byName(type);
- if(typeNumber < 0) return null;
- return primaryExtensionByMimeNumber.get(typeNumber);
- }
-
- public static String[] getAllMIMETypes() {
- return mimeTypesByNumber.toArray(new String[mimeTypesByNumber.size()]);
- }
-
-}
+++ /dev/null
-/*
- * jSite - SortedListModel.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.swing;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-
-import javax.swing.AbstractListModel;
-
-/**
- * @param <T>
- * The type of the elements
- * @author David Roden <droden@gmail.com>
- */
-public class SortedListModel<T extends Comparable<T>> extends AbstractListModel implements List<T> {
-
- /** The elements. */
- private List<T> elements = new ArrayList<T>();
-
- /**
- * {@inheritDoc}
- */
- public int getSize() {
- return size();
- }
-
- /**
- * {@inheritDoc}
- */
- public Object getElementAt(int index) {
- return elements.get(index);
- }
-
- /**
- * {@inheritDoc}
- */
- public void add(int index, T element) {
- elements.add(index, element);
- Collections.sort(elements);
- fireContentsChanged(this, 0, size());
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean add(T o) {
- boolean result = elements.add(o);
- Collections.sort(elements);
- fireContentsChanged(this, 0, size());
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean addAll(Collection<? extends T> c) {
- boolean result = elements.addAll(c);
- Collections.sort(elements);
- fireContentsChanged(this, 0, size());
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean addAll(int index, Collection<? extends T> c) {
- boolean result = elements.addAll(index, c);
- Collections.sort(elements);
- fireContentsChanged(this, 0, size());
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public void clear() {
- elements.clear();
- fireContentsChanged(this, 0, size());
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean contains(Object o) {
- return elements.contains(o);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean containsAll(Collection<?> c) {
- return elements.containsAll(c);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object o) {
- return elements.equals(o);
- }
-
- /**
- * {@inheritDoc}
- */
- public T get(int index) {
- return elements.get(index);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return elements.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- public int indexOf(Object o) {
- return elements.indexOf(o);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isEmpty() {
- return elements.isEmpty();
- }
-
- /**
- * {@inheritDoc}
- */
- public Iterator<T> iterator() {
- return elements.iterator();
- }
-
- /**
- * {@inheritDoc}
- */
- public int lastIndexOf(Object o) {
- return elements.lastIndexOf(o);
- }
-
- /**
- * {@inheritDoc}
- */
- public ListIterator<T> listIterator() {
- return elements.listIterator();
- }
-
- /**
- * {@inheritDoc}
- */
- public ListIterator<T> listIterator(int index) {
- return elements.listIterator(index);
- }
-
- /**
- * {@inheritDoc}
- */
- public T remove(int index) {
- fireContentsChanged(this, 0, size());
- return elements.remove(index);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean remove(Object o) {
- fireContentsChanged(this, 0, size());
- return elements.remove(o);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean removeAll(Collection<?> c) {
- fireContentsChanged(this, 0, size());
- return elements.removeAll(c);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean retainAll(Collection<?> c) {
- fireContentsChanged(this, 0, size());
- return elements.retainAll(c);
- }
-
- /**
- * {@inheritDoc}
- */
- public T set(int index, T element) {
- T result = elements.set(index, element);
- Collections.sort(elements);
- fireContentsChanged(this, 0, size());
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public int size() {
- return elements.size();
- }
-
- /**
- * {@inheritDoc}
- */
- public List<T> subList(int fromIndex, int toIndex) {
- return elements.subList(fromIndex, toIndex);
- }
-
- /**
- * {@inheritDoc}
- */
- public Object[] toArray() {
- return elements.toArray();
- }
-
- /**
- * {@inheritDoc}
- */
- public <U extends Object> U[] toArray(U[] a) {
- return elements.toArray(a);
- }
-
-}
+++ /dev/null
-/*
- * jSite - TLabel.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.swing;
-
-import java.awt.Component;
-
-import javax.swing.Icon;
-import javax.swing.JLabel;
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class TLabel extends JLabel {
-
- public TLabel() {
- super();
- }
-
- public TLabel(int mnemonic, Component labelFor) {
- super();
- setDisplayedMnemonic(mnemonic);
- setLabelFor(labelFor);
- }
-
- public TLabel(Icon image) {
- super(image);
- }
-
- public TLabel(Icon image, int mnemonic, Component labelFor) {
- super(image);
- setDisplayedMnemonic(mnemonic);
- setLabelFor(labelFor);
- }
-
- public TLabel(Icon image, int horizontalAlignment) {
- super(image);
- }
-
- public TLabel(Icon image, int horizontalAlignment, int mnemonic, Component labelFor) {
- super(image);
- setDisplayedMnemonic(mnemonic);
- setLabelFor(labelFor);
- }
-
- public TLabel(String text) {
- super(text);
- }
-
- public TLabel(String text, int mnemonic, Component labelFor) {
- super(text);
- setDisplayedMnemonic(mnemonic);
- setLabelFor(labelFor);
- setAlignmentX(0.0f);
- }
-
- public TLabel(String text, Icon icon, int horizontalAlignment) {
- super(text, icon, horizontalAlignment);
- }
-
- public TLabel(String text, Icon icon, int horizontalAlignment, int mnemonic, Component labelFor) {
- super(text, icon, horizontalAlignment);
- setDisplayedMnemonic(mnemonic);
- setLabelFor(labelFor);
- }
-
- public TLabel(String text, int horizontalAlignment) {
- super(text, horizontalAlignment);
- }
-
- public TLabel(String text, int horizontalAlignment, int mnemonic, Component labelFor) {
- super(text, horizontalAlignment);
- setDisplayedMnemonic(mnemonic);
- setLabelFor(labelFor);
- }
-
-}
+++ /dev/null
-/*
- * jSite - TWizard.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.Font;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.SwingConstants;
-import javax.swing.border.EmptyBorder;
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class TWizard extends JFrame implements WindowListener {
-
- protected List<WizardListener> wizardListeners = new ArrayList<WizardListener>();
-
- private Action previousAction;
- private Action nextAction;
- private Action quitAction;
- private JLabel pageIcon;
- private JPanel pagePanel;
- private JLabel pageHeading;
- private JLabel pageDescription;
-
- @Override
- protected void frameInit() {
- super.frameInit();
- setResizable(false);
- addWindowListener(this);
- setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
- createActions();
-
- pageIcon = new JLabel();
- pageIcon.setVerticalAlignment(SwingConstants.TOP);
- pageHeading = new JLabel();
- pageHeading.setFont(pageHeading.getFont().deriveFont(pageHeading.getFont().getSize() * 2.0f).deriveFont(Font.BOLD));
- pageDescription = new JLabel();
-
- JPanel contentPane = new JPanel(new BorderLayout(12, 12));
- contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
-
- JPanel topPanel = new JPanel(new BorderLayout(12, 12));
- contentPane.add(topPanel, BorderLayout.PAGE_START);
-
- topPanel.add(pageIcon, BorderLayout.LINE_START);
-
- JPanel textPanel = new JPanel(new BorderLayout(12, 12));
- topPanel.add(textPanel, BorderLayout.CENTER);
- textPanel.add(pageHeading, BorderLayout.PAGE_START);
- textPanel.add(pageDescription, BorderLayout.CENTER);
-
- pagePanel = new JPanel(new BorderLayout(12, 12));
- contentPane.add(pagePanel, BorderLayout.CENTER);
-
- JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
- buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12));
- buttonPanel.add(new JButton(previousAction));
- buttonPanel.add(new JButton(nextAction));
- buttonPanel.add(new JButton(quitAction));
- contentPane.add(buttonPanel, BorderLayout.PAGE_END);
-
- setContentPane(contentPane);
- }
-
- @Override
- public void pack() {
- super.pack();
- Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
- setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2);
- // System.out.println("resized to: " + getWidth() + "x" + getHeight());
- }
-
- private void createActions() {
- previousAction = new AbstractAction("Previous") {
- public void actionPerformed(ActionEvent actionEvent) {
- actionPrevious();
- }
- };
-
- nextAction = new AbstractAction("Next") {
- public void actionPerformed(ActionEvent actionEvent) {
- actionNext();
- }
- };
-
- quitAction = new AbstractAction("Quit") {
- public void actionPerformed(ActionEvent actionEvent) {
- actionQuit();
- }
- };
- }
-
- public void addWizardListener(WizardListener wizardListener) {
- wizardListeners.add(wizardListener);
- }
-
- public void removeWizardListener(WizardListener wizardListener) {
- wizardListeners.remove(wizardListener);
- }
-
- protected void fireWizardPreviousPressed() {
- for (WizardListener wizardListener: wizardListeners) {
- wizardListener.wizardPreviousPressed(this);
- }
- }
-
- protected void fireWizardNextPressed() {
- for (WizardListener wizardListener: wizardListeners) {
- wizardListener.wizardNextPressed(this);
- }
- }
-
- protected void fireWizardQuitPressed() {
- for (WizardListener wizardListener: wizardListeners) {
- wizardListener.wizardQuitPressed(this);
- }
- }
-
- public void setIcon(Icon icon) {
- pageIcon.setIcon(icon);
- }
-
- public void setPage(TWizardPage page) {
- setVisible(false);
- pageHeading.setText(page.getHeading());
- pageDescription.setText(page.getDescription());
- if (pagePanel.getComponentCount() > 0) {
- if (pagePanel.getComponent(0) instanceof TWizardPage) {
- ((TWizardPage) pagePanel.getComponent(0)).pageDeleted(this);
- }
- }
- pagePanel.removeAll();
- pagePanel.add(page, BorderLayout.CENTER);
- page.pageAdded(this);
- pack();
- setTitle(page.getHeading());
- setVisible(true);
- }
-
- public TWizardPage getPage() {
- return (TWizardPage) pagePanel.getComponent(0);
- }
-
- public void setPreviousEnabled(boolean previousEnabled) {
- previousAction.setEnabled(previousEnabled);
- }
-
- public void setPreviousName(String previousName) {
- previousAction.putValue(Action.NAME, previousName);
- }
-
- public void setNextEnabled(boolean nextEnabled) {
- nextAction.setEnabled(nextEnabled);
- }
-
- public void setNextName(String nextName) {
- nextAction.putValue(Action.NAME, nextName);
- }
-
- public void setQuitEnabled(boolean quitEnabled) {
- quitAction.setEnabled(quitEnabled);
- }
-
- public void setQuitName(String quitName) {
- quitAction.putValue(Action.NAME, quitName);
- }
-
- protected void actionPrevious() {
- fireWizardPreviousPressed();
- }
-
- protected void actionNext() {
- fireWizardNextPressed();
- }
-
- protected void actionQuit() {
- fireWizardQuitPressed();
- }
-
- //
- // INTERFACE WindowListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void windowOpened(WindowEvent e) {
- }
-
- /**
- * {@inheritDoc}
- */
- public void windowClosing(WindowEvent e) {
- fireWizardQuitPressed();
- }
-
- /**
- * {@inheritDoc}
- */
- public void windowClosed(WindowEvent e) {
- }
-
- /**
- * {@inheritDoc}
- */
- public void windowIconified(WindowEvent e) {
- }
-
- /**
- * {@inheritDoc}
- */
- public void windowDeiconified(WindowEvent e) {
- }
-
- /**
- * {@inheritDoc}
- */
- public void windowActivated(WindowEvent e) {
- }
-
- /**
- * {@inheritDoc}
- */
- public void windowDeactivated(WindowEvent e) {
- }
-
-}
+++ /dev/null
-/*
- * jSite - TWizardPage.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.swing;
-
-import javax.swing.JPanel;
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class TWizardPage extends JPanel {
-
- protected final TWizard wizard;
- protected String heading;
- protected String description;
-
- public TWizardPage(final TWizard wizard) {
- this.wizard = wizard;
- }
-
- public TWizardPage(final TWizard wizard, String heading) {
- this.wizard = wizard;
- this.heading = heading;
- }
-
- public TWizardPage(final TWizard wizard, String heading, String description) {
- this(wizard, heading);
- this.description = description;
- }
-
- /**
- * @return Returns the description.
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * @param description
- * The description to set.
- */
- public void setDescription(String description) {
- this.description = description;
- }
-
- /**
- * @return Returns the heading.
- */
- public String getHeading() {
- return heading;
- }
-
- /**
- * @param heading
- * The heading to set.
- */
- public void setHeading(String heading) {
- this.heading = heading;
- }
-
- public void pageAdded(TWizard wizard) {
- }
-
- public void pageDeleted(TWizard wizard) {
- }
-
-}
+++ /dev/null
-/*
- * jSite - WizardListener.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.swing;
-
-import java.util.EventListener;
-
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public interface WizardListener extends EventListener {
-
- public void wizardNextPressed(TWizard wizard);
- public void wizardPreviousPressed(TWizard wizard);
- public void wizardQuitPressed(TWizard wizard);
-
-}
+++ /dev/null
-/*
- * jSite - SimpleXML.java - Copyright © 2006–2012 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
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.xml;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.w3c.dom.Text;
-
-/**
- * SimpleXML is a helper class to construct XML trees in a fast and simple way.
- * Construct a new XML tree by calling {@link #SimpleXML(String)} and append new
- * nodes by calling {@link #append(String)}.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id:SimpleXML.java 221 2006-03-06 14:46:49Z bombe $
- */
-public class SimpleXML {
-
- /**
- * A {@link List} containing all child nodes of this node.
- */
- private List<SimpleXML> children = new ArrayList<SimpleXML>();
-
- /**
- * The name of this node.
- */
- private String name = null;
-
- /**
- * The value of this node.
- */
- private String value = null;
-
- /**
- * Constructs a new XML node without a name.
- */
- public SimpleXML() {
- super();
- }
-
- /**
- * Constructs a new XML node with the specified name.
- *
- * @param name
- * The name of the new node
- */
- public SimpleXML(String name) {
- this.name = name;
- }
-
- /**
- * Returns the child node of this node with the specified name. If there are
- * several child nodes with the specified name only the first node is
- * returned.
- *
- * @param nodeName
- * The name of the child node
- * @return The child node, or <code>null</code> if there is no child node
- * with the specified name
- */
- public SimpleXML getNode(String nodeName) {
- for (int index = 0, count = children.size(); index < count; index++) {
- if (children.get(index).name.equals(nodeName)) {
- return children.get(index);
- }
- }
- return null;
- }
-
- /**
- * Returns the child node that is specified by the names. The first element
- * of <code>nodeNames</code> is the name of the child node of this node, the
- * second element of <code>nodeNames</code> is the name of a child node's
- * child node, and so on. By using this method you can descend into an XML
- * tree pretty fast.
- *
- * <pre>
- *
- * SimpleXML deepNode = topNode.getNodes(new String[] { "person", "address", "number" });
- * </pre>
- *
- * @param nodeNames
- * @return A node that is a deep child of this node, or <code>null</code> if
- * the specified node does not eixst
- */
- public SimpleXML getNode(String[] nodeNames) {
- SimpleXML node = this;
- for (String nodeName : nodeNames) {
- node = node.getNode(nodeName);
- }
- return node;
- }
-
- /**
- * Returns all child nodes of this node.
- *
- * @return All child nodes of this node
- */
- public SimpleXML[] getNodes() {
- return getNodes(null);
- }
-
- /**
- * Returns all child nodes of this node with the specified name. If there
- * are no child nodes with the specified name an empty array is returned.
- *
- * @param nodeName
- * The name of the nodes to retrieve, or <code>null</code> to
- * retrieve all nodes
- * @return All child nodes with the specified name
- */
- public SimpleXML[] getNodes(String nodeName) {
- List<SimpleXML> resultList = new ArrayList<SimpleXML>();
- for (SimpleXML child : children) {
- if ((nodeName == null) || child.name.equals(nodeName)) {
- resultList.add(child);
- }
- }
- return resultList.toArray(new SimpleXML[resultList.size()]);
- }
-
- /**
- * Appends a new XML node with the specified name and returns the new node.
- * With this method you can create deep structures very fast.
- *
- * <pre>
- *
- * SimpleXML mouseNode = topNode.append("computer").append("bus").append("usb").append("mouse");
- * </pre>
- *
- * @param nodeName
- * The name of the node to append as a child to this node
- * @return The new node
- */
- public SimpleXML append(String nodeName) {
- return append(new SimpleXML(nodeName));
- }
-
- /**
- * Appends a new XML node with the specified name and value and returns the
- * new node.
- *
- * @param nodeName
- * The name of the node to append
- * @param nodeValue
- * The value of the node to append
- * @return The newly appended node
- */
- public SimpleXML append(String nodeName, String nodeValue) {
- return append(nodeName).setValue(nodeValue);
- }
-
- /**
- * Appends the node with all its child nodes to this node and returns the
- * child node.
- *
- * @param newChild
- * The node to append as a child
- * @return The child node that was appended
- */
- public SimpleXML append(SimpleXML newChild) {
- children.add(newChild);
- return newChild;
- }
-
- public void remove(SimpleXML child) {
- children.remove(child);
- }
-
- public void remove(String childName) {
- SimpleXML child = getNode(childName);
- if (child != null) {
- remove(child);
- }
- }
-
- public void replace(String childName, String value) {
- remove(childName);
- append(childName, value);
- }
-
- public void replace(SimpleXML childNode) {
- remove(childNode.getName());
- append(childNode);
- }
-
- public void removeAll() {
- children.clear();
- }
-
- /**
- * Sets the value of this node.
- *
- * @param nodeValue
- * The new value of this node
- * @return This node
- */
- public SimpleXML setValue(String nodeValue) {
- value = nodeValue;
- return this;
- }
-
- /**
- * Returns the name of this node.
- *
- * @return The name of this node
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the value of this node.
- *
- * @return The value of this node
- */
- public String getValue() {
- return value;
- }
-
- /**
- * Returns the value of this node. If the node does not have a value, the
- * given default value is returned.
- *
- *@param defaultValue
- * The default value to return if the node does not have a value
- * @return The value of this node
- */
- public String getValue(String defaultValue) {
- return (value == null) ? defaultValue : value;
- }
-
- /**
- * Creates a {@link Document} from this node and all its child nodes.
- *
- * @return The {@link Document} created from this node
- */
- public Document getDocument() {
- DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
- try {
- DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
- Document document = documentBuilder.newDocument();
- Element rootElement = document.createElement(name);
- document.appendChild(rootElement);
- addChildren(rootElement);
- return document;
- } catch (ParserConfigurationException e) {
- }
- return null;
- }
-
- /**
- * Appends all children of this node to the specified {@link Element}. If a
- * node has a value that is not <code>null</code> the value is appended as a
- * text node.
- *
- * @param rootElement
- * The element to attach this node's children to
- */
- private void addChildren(Element rootElement) {
- for (SimpleXML child : children) {
- Element childElement = rootElement.getOwnerDocument().createElement(child.name);
- rootElement.appendChild(childElement);
- if (child.value != null) {
- Text childText = rootElement.getOwnerDocument().createTextNode(child.value);
- childElement.appendChild(childText);
- } else {
- child.addChildren(childElement);
- }
- }
- }
-
- /**
- * Creates a SimpleXML node from the specified {@link Document}. The
- * SimpleXML node of the document's top-level node is returned.
- *
- * @param document
- * The {@link Document} to create a SimpleXML node from
- * @return The SimpleXML node created from the document's top-level node
- */
- public static SimpleXML fromDocument(Document document) {
- SimpleXML xmlDocument = new SimpleXML(document.getFirstChild().getNodeName());
- document.normalizeDocument();
- return addDocumentChildren(xmlDocument, document.getFirstChild());
- }
-
- /**
- * Appends the child nodes of the specified {@link Document} to this node.
- * Text nodes are converted into a node's value.
- *
- * @param xmlDocument
- * The SimpleXML node to append the child nodes to
- * @param document
- * The document whose child nodes to append
- * @return The SimpleXML node the child nodes were appended to
- */
- private static SimpleXML addDocumentChildren(SimpleXML xmlDocument, Node document) {
- NodeList childNodes = document.getChildNodes();
- for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; childIndex++) {
- Node childNode = childNodes.item(childIndex);
- if ((childNode.getChildNodes().getLength() == 1) && (childNode.getFirstChild().getNodeName().equals("#text"))) {
- xmlDocument.append(childNode.getNodeName(), childNode.getFirstChild().getNodeValue());
- } else {
- if (!childNode.getNodeName().equals("#text") || (childNode.getChildNodes().getLength() != 0)) {
- SimpleXML newXML = xmlDocument.append(childNode.getNodeName());
- addDocumentChildren(newXML, childNode);
- }
- }
- }
- return xmlDocument;
- }
-
-}
+++ /dev/null
-/*
- * jSite - XML.java - Copyright © 2006–2012 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 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-package de.todesbaum.util.xml;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMResult;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-
-import org.w3c.dom.Document;
-
-
-/**
- * Contains method to transform DOM XML trees to byte arrays and vice versa.
- *
- * @author David Roden <droden@gmail.com>
- * @version $Id:XML.java 221 2006-03-06 14:46:49Z bombe $
- */
-public class XML {
-
- /** Cached document builder factory. */
- private static DocumentBuilderFactory documentBuilderFactory = null;
-
- /** Cached document builder. */
- private static DocumentBuilder documentBuilder = null;
-
- /** Cached transformer factory. */
- private static TransformerFactory transformerFactory = null;
-
- /** Does nothing. */
- private XML() {
- }
-
- /**
- * Returns a document builder factory. If possible the cached instance will be returned.
- *
- * @return A document builder factory
- */
- private static DocumentBuilderFactory getDocumentBuilderFactory() {
- if (documentBuilderFactory != null) {
- return documentBuilderFactory;
- }
- documentBuilderFactory = DocumentBuilderFactory.newInstance();
- return documentBuilderFactory;
- }
-
- /**
- * Returns a document builder. If possible the cached instance will be returned.
- *
- * @return A document builder
- */
- private static DocumentBuilder getDocumentBuilder() {
- if (documentBuilder != null) {
- return documentBuilder;
- }
- try {
- documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
- } catch (ParserConfigurationException e) {
- }
- return documentBuilder;
- }
-
- /**
- * Returns a transformer factory. If possible the cached instance will be returned.
- *
- * @return A transformer factory
- */
- private static TransformerFactory getTransformerFactory() {
- if (transformerFactory != null) {
- return transformerFactory;
- }
- transformerFactory = TransformerFactory.newInstance();
- return transformerFactory;
- }
-
- /**
- * Creates a new XML document.
- *
- * @return A new XML document
- */
- public static Document createDocument() {
- return getDocumentBuilder().newDocument();
- }
-
- /**
- * Transforms the DOM XML document into a byte array.
- *
- * @param document
- * The document to transform
- * @return The byte array containing the XML representation
- */
- public static byte[] transformToByteArray(Document document) {
- ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
- OutputStreamWriter converter = new OutputStreamWriter(byteOutput, Charset.forName("UTF-8"));
- Result transformResult = new StreamResult(converter);
- Source documentSource = new DOMSource(document);
- try {
- Transformer transformer = getTransformerFactory().newTransformer();
- transformer.transform(documentSource, transformResult);
- byteOutput.close();
- return byteOutput.toByteArray();
- } catch (IOException ioe1) {
- } catch (TransformerConfigurationException tce1) {
- } catch (TransformerException te1) {
- } finally {
- try {
- byteOutput.close();
- } catch (IOException ioe1) {
- }
- }
- return null;
- }
-
- /**
- * Transforms the byte array into a DOM XML document.
- *
- * @param data
- * The byte array to parse
- * @return The DOM XML document
- */
- public static Document transformToDocument(byte[] data) {
- ByteArrayInputStream byteInput = new ByteArrayInputStream(data);
- InputStreamReader converter = new InputStreamReader(byteInput, Charset.forName("UTF-8"));
- Source xmlSource = new StreamSource(converter);
- Result xmlResult = new DOMResult();
- try {
- Transformer transformer = getTransformerFactory().newTransformer();
- transformer.transform(xmlSource, xmlResult);
- return (Document) ((DOMResult) xmlResult).getNode();
- } catch (TransformerConfigurationException tce1) {
- } catch (TransformerException te1) {
- } finally {
- if (byteInput != null)
- try {
- byteInput.close();
- } catch (IOException ioe1) {
- }
- if (converter != null)
- try {
- converter.close();
- } catch (IOException ioe1) {
- }
- }
- return null;
- }
-
-}
--- /dev/null
+/*
+ * jSite - AbortedException.java - Copyright © 2010–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+/**
+ * Marker exception that signals that the user aborted an insert.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class AbortedException extends Exception {
+
+ /* nothing here. */
+
+}
--- /dev/null
+/*
+ * jSite - FileOption.java - Copyright © 2006–2012 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 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+/**
+ * Container for various file options.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class FileOption {
+
+ /** The default for the insert state. */
+ private static final boolean DEFAULT_INSERT = true;
+
+ /** The default for the insert redirect state. */
+ private static final boolean DEFAULT_INSERT_REDIRECT = true;
+
+ /** The default for the custom key. */
+ private static final String DEFAULT_CUSTOM_KEY = "CHK@";
+
+ /** The default changed name. */
+ private static final String DEFAULT_CHANGED_NAME = null;
+
+ /** The insert state. */
+ private boolean insert;
+
+ /** Whether to force an insert. */
+ private boolean forceInsert;
+
+ /** Whether to insert a redirect. */
+ private boolean insertRedirect;
+
+ /** The hash of the last insert. */
+ private String lastInsertHash;
+
+ /** The edition of the last insert. */
+ private int lastInsertEdition;
+
+ /** The filename of the last insert. */
+ private String lastInsertFilename;
+
+ /** The current hash of the file. */
+ private String currentHash;
+
+ /** The custom key. */
+ private String customKey;
+
+ /** The changed name. */
+ private String changedName;
+
+ /** The default MIME type. */
+ private final String defaultMimeType;
+
+ /** The current MIME type. */
+ private String mimeType;
+
+ /**
+ * Creates new file options.
+ *
+ * @param defaultMimeType
+ * The default MIME type of the file
+ */
+ public FileOption(String defaultMimeType) {
+ insert = DEFAULT_INSERT;
+ insertRedirect = DEFAULT_INSERT_REDIRECT;
+ customKey = DEFAULT_CUSTOM_KEY;
+ changedName = DEFAULT_CHANGED_NAME;
+ this.defaultMimeType = defaultMimeType;
+ mimeType = defaultMimeType;
+ }
+
+ /**
+ * Returns the custom key. The custom key is only used when
+ * {@link #isInsert()} and {@link #isInsertRedirect()} both return {@code
+ * true}.
+ *
+ * @return The custom key
+ */
+ public String getCustomKey() {
+ return customKey;
+ }
+
+ /**
+ * Sets the custom key. The custom key is only used when {@link #isInsert()}
+ * and {@link #isInsertRedirect()} both return {@code true}.
+ *
+ * @param customKey
+ * The custom key
+ */
+ public void setCustomKey(String customKey) {
+ if (customKey == null) {
+ this.customKey = "";
+ } else {
+ this.customKey = customKey;
+ }
+ }
+
+ /**
+ * Returns whether the file should be inserted. If a file is not inserted
+ * and {@link #isInsertRedirect()} is also {@code false}, the file will not
+ * be inserted at all.
+ *
+ * @see #setCustomKey(String)
+ * @return <code>true</code> if the file should be inserted,
+ * <code>false</code> otherwise
+ */
+ public boolean isInsert() {
+ return insert;
+ }
+
+ /**
+ * Sets whether the file should be inserted. If a file is not inserted and
+ * {@link #isInsertRedirect()} is also {@code false}, the file will not be
+ * inserted at all.
+ *
+ * @param insert
+ * <code>true</code> if the file should be inserted,
+ * <code>false</code> otherwise
+ */
+ public void setInsert(boolean insert) {
+ this.insert = insert;
+ }
+
+ /**
+ * Returns whether the insert of this file should be forced, even if its
+ * current hash matches the last insert hash.
+ *
+ * @return {@code true} to force the insert of this file, {@code false}
+ * otherwise
+ */
+ public boolean isForceInsert() {
+ return forceInsert;
+ }
+
+ /**
+ * Sets whether to force the insert of this file, even if its current hash
+ * matches the last insert hash.
+ *
+ * @param forceInsert
+ * {@code true} to force the insert of this file, {@code false}
+ * otherwise
+ * @return These file options
+ */
+ public FileOption setForceInsert(boolean forceInsert) {
+ this.forceInsert = forceInsert;
+ return this;
+ }
+
+ /**
+ * Returns whether a redirect to a different key should be inserted. This
+ * will only matter if {@link #isInsert()} returns {@code false}. The key
+ * that should be redirected to still needs to be specified via
+ * {@link #setCustomKey(String)}.
+ *
+ * @return {@code true} if a redirect should be inserted, {@code false}
+ * otherwise
+ */
+ public boolean isInsertRedirect() {
+ return insertRedirect;
+ }
+
+ /**
+ * Sets whether a redirect should be inserted. This will only matter if
+ * {@link #isInsert()} returns {@code false}, i.e. it has been
+ * {@link #setInsert(boolean)} to {@code false}. The key that should be
+ * redirected to still needs to be specified via
+ * {@link #setCustomKey(String)}.
+ *
+ * @param insertRedirect
+ * {@code true} if a redirect should be inserted, {@code false}
+ * otherwise
+ */
+ public void setInsertRedirect(boolean insertRedirect) {
+ this.insertRedirect = insertRedirect;
+ }
+
+ /**
+ * Returns the hash of the file when it was last inserted
+ *
+ * @return The last hash of the file
+ */
+ public String getLastInsertHash() {
+ return lastInsertHash;
+ }
+
+ /**
+ * Sets the hash of the file when it was last inserted.
+ *
+ * @param lastInsertHash
+ * The last hash of the file
+ * @return These file options
+ */
+ public FileOption setLastInsertHash(String lastInsertHash) {
+ this.lastInsertHash = lastInsertHash;
+ return this;
+ }
+
+ /**
+ * Returns the last edition at which this file was inserted.
+ *
+ * @return The last insert edition of this file
+ */
+ public int getLastInsertEdition() {
+ return lastInsertEdition;
+ }
+
+ /**
+ * Sets the last insert edition of this file.
+ *
+ * @param lastInsertEdition
+ * The last insert edition of this file
+ * @return These file options
+ */
+ public FileOption setLastInsertEdition(int lastInsertEdition) {
+ this.lastInsertEdition = lastInsertEdition;
+ return this;
+ }
+
+ /**
+ * Returns the name of the file when it was last inserted.
+ *
+ * @return The name of the file at the last insert
+ */
+ public String getLastInsertFilename() {
+ return lastInsertFilename;
+ }
+
+ /**
+ * Sets the name of the file when it was last inserted.
+ *
+ * @param lastInsertFilename
+ * The name of the file at the last insert.
+ * @return These file options
+ */
+ public FileOption setLastInsertFilename(String lastInsertFilename) {
+ this.lastInsertFilename = lastInsertFilename;
+ return this;
+ }
+
+ /**
+ * Returns the current hash of the file. This value is ony a temporary value
+ * that is copied to {@link #getLastInsertHash()} when a project has
+ * finished inserting.
+ *
+ * @see Project#onSuccessfulInsert()
+ * @return The current hash of the file
+ */
+ public String getCurrentHash() {
+ return currentHash;
+ }
+
+ /**
+ * Sets the current hash of the file.
+ *
+ * @param currentHash
+ * The current hash of the file
+ * @return These file options
+ */
+ public FileOption setCurrentHash(String currentHash) {
+ this.currentHash = currentHash;
+ return this;
+ }
+
+ /**
+ * Returns whether this file has a changed name. Use
+ * {@link #getChangedName()} is this method returns {@code true}.
+ *
+ * @return {@code true} if this file has a changed name, {@code false}
+ * otherwise
+ */
+ public boolean hasChangedName() {
+ return (changedName != null) && (changedName.length() > 0);
+ }
+
+ /**
+ * Returns the changed name for this file. This method will return {@code
+ * null} or an empty {@link String} if this file should not be renamed.
+ *
+ * @return The changed name, or {@code null} if this file should not be
+ * renamed
+ */
+ public String getChangedName() {
+ return changedName;
+ }
+
+ /**
+ * Sets the changed name for this file. Setting the changed file to {@code
+ * null} or an empty {@link String} will disable renaming.
+ *
+ * @param changedName
+ * The new changed name for this file
+ */
+ public void setChangedName(String changedName) {
+ this.changedName = changedName;
+ }
+
+ /**
+ * Sets the MIME type of the file. Setting the MIME type to
+ * <code>null</code> will set the MIME type to the default MIME type.
+ *
+ * @param mimeType
+ * The MIME type of the file
+ */
+ public void setMimeType(String mimeType) {
+ if (mimeType == null) {
+ this.mimeType = defaultMimeType;
+ } else {
+ this.mimeType = mimeType;
+ }
+ }
+
+ /**
+ * Returns the MIME type of the file. If no custom MIME type has been set,
+ * the default MIME type is returned.
+ *
+ * @return The MIME type of the file
+ */
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ /**
+ * Returns whether the options for this file have been modified, i.e. are
+ * not at their default values.
+ *
+ * @return <code>true</code> if the options have been modified,
+ * <code>false</code> if they are at default values
+ */
+ public boolean isCustom() {
+ if (insert != DEFAULT_INSERT) {
+ return true;
+ }
+ if (!customKey.equals(DEFAULT_CUSTOM_KEY)) {
+ return true;
+ }
+ if (((changedName != null) && !changedName.equals(DEFAULT_CHANGED_NAME)) || ((DEFAULT_CHANGED_NAME != null) && !DEFAULT_CHANGED_NAME.equals(changedName))) {
+ return true;
+ }
+ if (!defaultMimeType.equals(mimeType)) {
+ return true;
+ }
+ if (insertRedirect != DEFAULT_INSERT_REDIRECT) {
+ return true;
+ }
+ return false;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Freenet7Interface.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.io.IOException;
+
+import de.todesbaum.util.freenet.fcp2.Client;
+import de.todesbaum.util.freenet.fcp2.Connection;
+import de.todesbaum.util.freenet.fcp2.GenerateSSK;
+import de.todesbaum.util.freenet.fcp2.Message;
+import de.todesbaum.util.freenet.fcp2.Node;
+
+/**
+ * Interface for freenet-related operations.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class Freenet7Interface {
+
+ /** Random number to differentiate several jSites. */
+ private static final int number = (int) (Math.random() * Integer.MAX_VALUE);
+
+ /** Counter. */
+ private static int counter = 0;
+
+ /** The node to connect to. */
+ private Node node;
+
+ /** The connection to the node. */
+ private Connection connection;
+
+ /**
+ * Sets the hostname of the node. The default port for FCP2 connections ({@link Node#DEFAULT_PORT})
+ * is used.
+ *
+ * @param hostname
+ * The hostname of the node
+ */
+ public void setNodeAddress(String hostname) {
+ node = new Node(hostname);
+ connection = new Connection(node, "jSite-" + number + "-connection-" + counter++);
+ }
+
+ /**
+ * Sets the hostname and the port of the node.
+ *
+ * @param hostname
+ * The hostname of the node
+ * @param port
+ * The port number of the node
+ */
+ public void setNodeAddress(String hostname, int port) {
+ node = new Node(hostname, port);
+ connection = new Connection(node, "jSite-" + number + "-connection-" + counter++);
+ }
+
+ /**
+ * Sets hostname and port from the given node.
+ *
+ * @param node
+ * The node to get the hostname and port from
+ */
+ public void setNode(de.todesbaum.jsite.application.Node node) {
+ if (node != null) {
+ this.node = new Node(node.getHostname(), node.getPort());
+ connection = new Connection(node, "jSite-" + number + "-connection-" + counter++);
+ } else {
+ this.node = null;
+ connection = null;
+ }
+ }
+
+ /**
+ * Removes the current node from the interface.
+ */
+ public void removeNode() {
+ node = null;
+ connection = null;
+ }
+
+ /**
+ * Returns the node this interface is connecting to.
+ *
+ * @return The node
+ */
+ public Node getNode() {
+ return node;
+ }
+
+ /**
+ * Creates a new connection to the current node with the given identifier.
+ *
+ * @param identifier
+ * The identifier of the connection
+ * @return The connection to the node
+ */
+ public Connection getConnection(String identifier) {
+ return new Connection(node, identifier);
+ }
+
+ /**
+ * Checks whether the current node is connected. If the node is not
+ * connected, a connection will be tried.
+ *
+ * @return <code>true</code> if the node is connected, <code>false</code>
+ * otherwise
+ * @throws IOException
+ * if an I/O error occurs communicating with the node
+ */
+ public boolean isNodePresent() throws IOException {
+ if (!connection.isConnected()) {
+ return connection.connect();
+ }
+ return true;
+ }
+
+ /**
+ * Generates an SSK key pair.
+ *
+ * @return An array of strings, the first one being the generated private
+ * (insert) URI and the second one being the generated public
+ * (request) URI
+ * @throws IOException
+ * if an I/O error occurs communicating with the node
+ */
+ public String[] generateKeyPair() throws IOException {
+ if (!isNodePresent()) {
+ throw new IOException("Node is offline.");
+ }
+ GenerateSSK generateSSK = new GenerateSSK();
+ Client client = new Client(connection, generateSSK);
+ Message keypairMessage = client.readMessage();
+ return new String[] { keypairMessage.get("InsertURI"), keypairMessage.get("RequestURI") };
+ }
+
+ /**
+ * Checks whether the interface has already been configured with a node.
+ *
+ * @return <code>true</code> if this interface already has a node set,
+ * <code>false</code> otherwise
+ */
+ public boolean hasNode() {
+ return (node != null) && (connection != null);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - InsertListener.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.util.EventListener;
+
+/**
+ * Interface for objects that want to be notified abount insert events.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public interface InsertListener extends EventListener {
+
+ /**
+ * Enumeration for the different error situations.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+ public static enum ErrorType {
+
+ /** The key does already exist. */
+ KEY_COLLISION,
+
+ /** The route to the key was not found. */
+ ROUTE_NOT_FOUND,
+
+ /** The data was not found. */
+ DATA_NOT_FOUND,
+
+ /** Error in the FCP communication. */
+ FCP_ERROR,
+
+ /** General error in the communication. */
+ IO_ERROR
+ }
+
+ /**
+ * Notifies a listener that an insert has started.
+ *
+ * @param project
+ * The project that is now being inserted
+ */
+ public void projectInsertStarted(Project project);
+
+ /**
+ * Notifies a listener that the upload of a project has finished and the
+ * inserting will start now.
+ *
+ * @param project
+ * The project that has been uploaded
+ */
+ public void projectUploadFinished(Project project);
+
+ /**
+ * Notifies a listener that a project insert has generated a URI.
+ *
+ * @param project
+ * The project being inserted
+ * @param uri
+ * The generated URI
+ */
+ public void projectURIGenerated(Project project, String uri);
+
+ /**
+ * Notifies a listener that an insert has made some progress.
+ *
+ * @param project
+ * The project being inserted
+ * @param succeeded
+ * The number of succeeded blocks
+ * @param failed
+ * The number of failed blocks
+ * @param fatal
+ * The number of fatally failed blocks
+ * @param total
+ * The total number of blocks
+ * @param finalized
+ * <code>true</code> if the total number of blocks has been
+ * finalized, <code>false</code> otherwise
+ */
+ public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized);
+
+ /**
+ * Notifies a listener that a project insert has finished.
+ *
+ * @param project
+ * The project being inserted
+ * @param success
+ * <code>true</code> if the insert succeeded, <code>false</code>
+ * otherwise
+ * @param cause
+ * The cause of a failure, if any (may be <code>null</code>)
+ */
+ public void projectInsertFinished(Project project, boolean success, Throwable cause);
+
+}
--- /dev/null
+/*
+ * jSite - KeyDialog.java - Copyright © 2010–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.SwingConstants;
+
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.jsite.i18n.I18nContainer;
+
+/**
+ * A dialog that lets the user edit the private and public key for a project.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class KeyDialog extends JDialog {
+
+ /** Interface to the freenet node. */
+ private final Freenet7Interface freenetInterface;
+
+ /** The public key. */
+ private String publicKey;
+
+ /** The private key. */
+ private String privateKey;
+
+ /** The “OK” button’s action. */
+ private Action okAction;
+
+ /** The “Cancel” button’s action. */
+ private Action cancelAction;
+
+ /** The “Regenerate” button’s action. */
+ private Action generateAction;
+
+ /** The text field for the private key. */
+ private JTextField privateKeyTextField;
+
+ /** The text field for the public key. */
+ private JTextField publicKeyTextField;
+
+ /** Whether the dialog was cancelled. */
+ private boolean cancelled;
+
+ /**
+ * Creates a new key dialog.
+ *
+ * @param freenetInterface
+ * Interface to the freenet node
+ * @param parent
+ * The parent frame
+ */
+ public KeyDialog(Freenet7Interface freenetInterface, JFrame parent) {
+ super(parent, I18n.getMessage("jsite.key-dialog.title"), true);
+ this.freenetInterface = freenetInterface;
+ addWindowListener(new WindowAdapter() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void windowClosing(WindowEvent windowEvent) {
+ actionCancel();
+ }
+ });
+ initDialog();
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns whether the dialog was cancelled.
+ *
+ * @return {@code true} if the dialog was cancelled, {@code false} otherwise
+ */
+ public boolean wasCancelled() {
+ return cancelled;
+ }
+
+ /**
+ * Returns the public key.
+ *
+ * @return The public key
+ */
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ /**
+ * Sets the public key.
+ *
+ * @param publicKey
+ * The public key
+ */
+ public void setPublicKey(String publicKey) {
+ this.publicKey = publicKey;
+ publicKeyTextField.setText(publicKey);
+ pack();
+ }
+
+ /**
+ * Returns the private key.
+ *
+ * @return The private key
+ */
+ public String getPrivateKey() {
+ return privateKey;
+ }
+
+ /**
+ * Sets the private key.
+ *
+ * @param privateKey
+ * The private key
+ */
+ public void setPrivateKey(String privateKey) {
+ this.privateKey = privateKey;
+ privateKeyTextField.setText(privateKey);
+ pack();
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pack() {
+ super.pack();
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2);
+ }
+
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Creates all necessary actions.
+ */
+ private void createActions() {
+ okAction = new AbstractAction(I18n.getMessage("jsite.general.ok")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionOk();
+ }
+ };
+ okAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.ok.tooltip"));
+ okAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_ENTER);
+
+ cancelAction = new AbstractAction(I18n.getMessage("jsite.general.cancel")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionCancel();
+ }
+ };
+ cancelAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.cancel.tooltip"));
+ cancelAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_ESCAPE);
+
+ generateAction = new AbstractAction(I18n.getMessage("jsite.key-dialog.button.generate")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionGenerate();
+ }
+ };
+ generateAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.generate.tooltip"));
+ generateAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
+ }
+
+ /**
+ * Initializes the dialog and all its components.
+ */
+ private void initDialog() {
+ createActions();
+ JPanel dialogPanel = new JPanel(new BorderLayout(12, 12));
+ dialogPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
+
+ JPanel contentPanel = new JPanel(new GridBagLayout());
+ dialogPanel.add(contentPanel, BorderLayout.CENTER);
+
+ final JLabel keysLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.keys"));
+ contentPanel.add(keysLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+
+ final JLabel privateKeyLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.private-key"));
+ contentPanel.add(privateKeyLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0));
+
+ privateKeyTextField = new JTextField();
+ contentPanel.add(privateKeyTextField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0));
+
+ final JLabel publicKeyLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.public-key"));
+ contentPanel.add(publicKeyLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+
+ publicKeyTextField = new JTextField();
+ contentPanel.add(publicKeyTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0));
+
+ final JLabel actionsLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.actions"));
+ contentPanel.add(actionsLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
+
+ JPanel actionButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
+ actionButtonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
+ contentPanel.add(actionButtonPanel, new GridBagConstraints(0, 4, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0));
+
+ actionButtonPanel.add(new JButton(generateAction));
+
+ JPanel separatorPanel = new JPanel(new BorderLayout(12, 12));
+ dialogPanel.add(separatorPanel, BorderLayout.PAGE_END);
+ separatorPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.PAGE_START);
+
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
+ buttonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
+ separatorPanel.add(buttonPanel, BorderLayout.CENTER);
+ buttonPanel.add(new JButton(okAction));
+ buttonPanel.add(new JButton(cancelAction));
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ keysLabel.setText(I18n.getMessage("jsite.key-dialog.label.keys"));
+ privateKeyLabel.setText(I18n.getMessage("jsite.key-dialog.label.private-key"));
+ publicKeyLabel.setText(I18n.getMessage("jsite.key-dialog.label.public-key"));
+ actionsLabel.setText(I18n.getMessage("jsite.key-dialog.label.actions"));
+ }
+ });
+
+ getContentPane().add(dialogPanel, BorderLayout.CENTER);
+ pack();
+ setResizable(false);
+ }
+
+ //
+ // PRIVATE ACTIONS
+ //
+
+ /**
+ * Quits the dialog, accepting all changes.
+ */
+ private void actionOk() {
+ publicKey = publicKeyTextField.getText();
+ privateKey = privateKeyTextField.getText();
+ cancelled = false;
+ setVisible(false);
+ }
+
+ /**
+ * Quits the dialog, discarding all changes.
+ */
+ private void actionCancel() {
+ cancelled = true;
+ setVisible(false);
+ }
+
+ /**
+ * Generates a new key pair.
+ */
+ private void actionGenerate() {
+ if (JOptionPane.showConfirmDialog(this, I18n.getMessage("jsite.project.warning.generate-new-key"), null, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
+ return;
+ }
+ String[] keyPair = null;
+ try {
+ keyPair = freenetInterface.generateKeyPair();
+ } catch (IOException ioe1) {
+ JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ publicKeyTextField.setText(keyPair[1].substring(keyPair[1].indexOf('@') + 1, keyPair[1].lastIndexOf('/')));
+ privateKeyTextField.setText(keyPair[0].substring(keyPair[0].indexOf('@') + 1, keyPair[0].lastIndexOf('/')));
+ pack();
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Node.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+/**
+ * Container for node information.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class Node extends de.todesbaum.util.freenet.fcp2.Node {
+
+ /** The name of the node. */
+ protected String name;
+
+ /**
+ * Creates a new node with the given hostname and the default port.
+ *
+ * @see de.todesbaum.util.freenet.fcp2.Node#DEFAULT_PORT
+ * @param hostname
+ * The hostname of the new node
+ */
+ public Node(String hostname) {
+ this(hostname, DEFAULT_PORT);
+ }
+
+ /**
+ * Creates a new node with the given hostname and port.
+ *
+ * @param hostname
+ * The hostname of the new node
+ * @param port
+ * The port of the new node
+ */
+ public Node(String hostname, int port) {
+ this(hostname, port, "");
+ }
+
+ /**
+ * Creates a new node with the given hostname, port, and name.
+ *
+ * @param hostname
+ * The hostname of the new node
+ * @param port
+ * The port of the new node
+ * @param name
+ * The name of the node
+ */
+ public Node(String hostname, int port, String name) {
+ super(hostname, port);
+ this.name = name;
+ }
+
+ /**
+ * Creates a new node that gets its settings from the given node.
+ *
+ * @param node
+ * The node to copy
+ */
+ public Node(Node node) {
+ this(node.getHostname(), node.getPort());
+ }
+
+ /**
+ * Creates a new node from the given node, overwriting the name.
+ *
+ * @param node
+ * The node to copy from
+ * @param name
+ * The new name of the node
+ */
+ public Node(Node node, String name) {
+ this(node.getHostname(), node.getPort(), name);
+ }
+
+ /**
+ * Sets the name of the node.
+ *
+ * @param name
+ * The name of the node
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of the node.
+ *
+ * @return The name of the node
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the hostname of the node.
+ *
+ * @param hostname
+ * The hostname of the node
+ */
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ /**
+ * Sets the port of the node.
+ *
+ * @param port
+ * The port of the node
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * A node is considered as being equal to this node its name, hostname, and
+ * port equal their counterparts in this node.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof Node)) {
+ return false;
+ }
+ Node node = (Node) o;
+ return name.equals(node.name) && hostname.equals(node.hostname) && (port == node.port);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The hashcode for a node is created from its name, its hostname, and its
+ * port.
+ */
+ @Override
+ public int hashCode() {
+ return name.hashCode() ^ hostname.hashCode() ^ port;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Creates a textual representation of this node.
+ */
+ @Override
+ public String toString() {
+ return name + " (" + hostname + ":" + port + ")";
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Project.java - Copyright © 2006–2012 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 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import de.todesbaum.util.mime.DefaultMIMETypes;
+
+/**
+ * Container for project information.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class Project implements Comparable<Project> {
+
+ /** The name of the project. */
+ protected String name;
+
+ /** The description of the project. */
+ protected String description;
+
+ /** The insert URI of the project. */
+ protected String insertURI;
+
+ /** The request URI of the project. */
+ protected String requestURI;
+
+ /** The index file of the project. */
+ protected String indexFile;
+
+ /** The local path of the project. */
+ protected String localPath;
+
+ /** The remote path of the URI. */
+ protected String path;
+
+ /** The time of the last insertion. */
+ protected long lastInsertionTime;
+
+ /** The edition to insert to. */
+ protected int edition;
+
+ /** Whether to ignore hidden directory. */
+ private boolean ignoreHiddenFiles;
+
+ /** Options for files. */
+ protected Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
+
+ /**
+ * Empty constructor.
+ */
+ public Project() {
+ /* do nothing. */
+ }
+
+ /**
+ * Creates a new project from an existing one.
+ *
+ * @param project
+ * The project to clone
+ */
+ public Project(Project project) {
+ name = project.name;
+ description = project.description;
+ insertURI = project.insertURI;
+ requestURI = project.requestURI;
+ path = project.path;
+ edition = project.edition;
+ localPath = project.localPath;
+ indexFile = project.indexFile;
+ lastInsertionTime = project.lastInsertionTime;
+ ignoreHiddenFiles = project.ignoreHiddenFiles;
+ fileOptions = new HashMap<String, FileOption>(project.fileOptions);
+ }
+
+ /**
+ * Returns the name of the project.
+ *
+ * @return The name of the project
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the project.
+ *
+ * @param name
+ * The name of the project
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the description of the project.
+ *
+ * @return The description of the project
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets the description of the project.
+ *
+ * @param description
+ * The description of the project
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Returns the local path of the project.
+ *
+ * @return The local path of the project
+ */
+ public String getLocalPath() {
+ return localPath;
+ }
+
+ /**
+ * Sets the local path of the project.
+ *
+ * @param localPath
+ * The local path of the project
+ */
+ public void setLocalPath(String localPath) {
+ this.localPath = localPath;
+ }
+
+ /**
+ * Returns the name of the index file of the project, relative to the
+ * project’s local path.
+ *
+ * @return The name of the index file of the project
+ */
+ public String getIndexFile() {
+ return indexFile;
+ }
+
+ /**
+ * Sets the name of the index file of the project, relative to the project’s
+ * local path.
+ *
+ * @param indexFile
+ * The name of the index file of the project
+ */
+ public void setIndexFile(String indexFile) {
+ this.indexFile = indexFile;
+ }
+
+ /**
+ * Returns the time the project was last inserted, in milliseconds since the
+ * epoch.
+ *
+ * @return The time of the last insertion
+ */
+ public long getLastInsertionTime() {
+ return lastInsertionTime;
+ }
+
+ /**
+ * Sets the time the project was last inserted, in milliseconds since the
+ * last epoch.
+ *
+ * @param lastInserted
+ * The time of the last insertion
+ */
+ public void setLastInsertionTime(long lastInserted) {
+ lastInsertionTime = lastInserted;
+ }
+
+ /**
+ * Returns the remote path of the project. The remote path is the path that
+ * directly follows the request URI of the project.
+ *
+ * @return The remote path of the project
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * Sets the remote path of the project. The remote path is the path that
+ * directly follows the request URI of the project.
+ *
+ * @param path
+ * The remote path of the project
+ */
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ /**
+ * Returns the insert URI of the project.
+ *
+ * @return The insert URI of the project
+ */
+ public String getInsertURI() {
+ return insertURI;
+ }
+
+ /**
+ * Sets the insert URI of the project.
+ *
+ * @param insertURI
+ * The insert URI of the project
+ */
+ public void setInsertURI(String insertURI) {
+ this.insertURI = shortenURI(insertURI);
+ }
+
+ /**
+ * Returns the request URI of the project.
+ *
+ * @return The request URI of the project
+ */
+ public String getRequestURI() {
+ return requestURI;
+ }
+
+ /**
+ * Sets the request URI of the project.
+ *
+ * @param requestURI
+ * The request URI of the project
+ */
+ public void setRequestURI(String requestURI) {
+ this.requestURI = shortenURI(requestURI);
+ }
+
+ /**
+ * Returns whether hidden files are ignored, i.e. not inserted.
+ *
+ * @return {@code true} if hidden files are not inserted, {@code false}
+ * otherwise
+ */
+ public boolean isIgnoreHiddenFiles() {
+ return ignoreHiddenFiles;
+ }
+
+ /**
+ * Sets whether hidden files are ignored, i.e. not inserted.
+ *
+ * @param ignoreHiddenFiles
+ * {@code true} if hidden files are not inserted, {@code false}
+ * otherwise
+ */
+ public void setIgnoreHiddenFiles(boolean ignoreHiddenFiles) {
+ this.ignoreHiddenFiles = ignoreHiddenFiles;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This method returns the name of the project.
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ /**
+ * Shortens the given URI by removing scheme and key-type prefixes.
+ *
+ * @param uri
+ * The URI to shorten
+ * @return The shortened URI
+ */
+ private String shortenURI(String uri) {
+ String shortUri = uri;
+ if (shortUri.startsWith("freenet:")) {
+ shortUri = shortUri.substring("freenet:".length());
+ }
+ if (shortUri.startsWith("SSK@")) {
+ shortUri = shortUri.substring("SSK@".length());
+ }
+ if (shortUri.startsWith("USK@")) {
+ shortUri = shortUri.substring("USK@".length());
+ }
+ if (shortUri.endsWith("/")) {
+ shortUri = shortUri.substring(0, shortUri.length() - 1);
+ }
+ return shortUri;
+ }
+
+ /**
+ * Shortens the name of the given file by removing the local path of the
+ * project and leading file separators.
+ *
+ * @param file
+ * The file whose name should be shortened
+ * @return The shortened name of the file
+ */
+ public String shortenFilename(File file) {
+ String filename = file.getPath();
+ if (filename.startsWith(localPath)) {
+ filename = filename.substring(localPath.length());
+ if (filename.startsWith(File.separator)) {
+ filename = filename.substring(1);
+ }
+ }
+ return filename;
+ }
+
+ /**
+ * Returns the options for the file with the given name. If the file does
+ * not yet have any options, a new set of default options is created and
+ * returned.
+ *
+ * @param filename
+ * The name of the file, relative to the project root
+ * @return The options for the file
+ */
+ public FileOption getFileOption(String filename) {
+ FileOption fileOption = fileOptions.get(filename);
+ if (fileOption == null) {
+ fileOption = new FileOption(DefaultMIMETypes.guessMIMEType(filename));
+ fileOptions.put(filename, fileOption);
+ }
+ return fileOption;
+ }
+
+ /**
+ * Sets options for a file.
+ *
+ * @param filename
+ * The filename to set the options for, relative to the project
+ * root
+ * @param fileOption
+ * The options to set for the file, or <code>null</code> to
+ * remove the options for the file
+ */
+ public void setFileOption(String filename, FileOption fileOption) {
+ if (fileOption != null) {
+ fileOptions.put(filename, fileOption);
+ } else {
+ fileOptions.remove(filename);
+ }
+ }
+
+ /**
+ * Returns all file options.
+ *
+ * @return All file options
+ */
+ public Map<String, FileOption> getFileOptions() {
+ return Collections.unmodifiableMap(fileOptions);
+ }
+
+ /**
+ * Sets all file options.
+ *
+ * @param fileOptions
+ * The file options
+ */
+ public void setFileOptions(Map<String, FileOption> fileOptions) {
+ this.fileOptions.clear();
+ this.fileOptions.putAll(fileOptions);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Projects are compared by their name only.
+ */
+ public int compareTo(Project project) {
+ return name.compareToIgnoreCase(project.name);
+ }
+
+ /**
+ * Returns the edition of the project.
+ *
+ * @return The edition of the project
+ */
+ public int getEdition() {
+ return edition;
+ }
+
+ /**
+ * Sets the edition of the project.
+ *
+ * @param edition
+ * The edition to set
+ */
+ public void setEdition(int edition) {
+ this.edition = edition;
+ }
+
+ /**
+ * Constructs the final request URI including the edition number.
+ *
+ * @param offset
+ * The offset for the edition number
+ * @return The final request URI
+ */
+ public String getFinalRequestURI(int offset) {
+ return "USK@" + requestURI + "/" + path + "/" + (edition + offset) + "/";
+ }
+
+ /**
+ * Performs some post-processing on the project after it was inserted
+ * successfully. At the moment it copies the current hashes of all file
+ * options to the last insert hashes, updating the hashes for the next
+ * insert.
+ */
+ public void onSuccessfulInsert() {
+ for (Entry<String, FileOption> fileOptionEntry : fileOptions.entrySet()) {
+ FileOption fileOption = fileOptionEntry.getValue();
+ if ((fileOption.getCurrentHash() != null) && (fileOption.getCurrentHash().length() > 0) && (!fileOption.getCurrentHash().equals(fileOption.getLastInsertHash()) || fileOption.isForceInsert())) {
+ fileOption.setLastInsertEdition(edition);
+ fileOption.setLastInsertHash(fileOption.getCurrentHash());
+ fileOption.setLastInsertFilename(fileOption.hasChangedName() ? fileOption.getChangedName() : fileOptionEntry.getKey());
+ }
+ fileOption.setForceInsert(false);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ProjectInserter.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import de.todesbaum.jsite.gui.FileScanner;
+import de.todesbaum.jsite.gui.FileScanner.ScannedFile;
+import de.todesbaum.jsite.gui.FileScannerListener;
+import de.todesbaum.util.freenet.fcp2.Client;
+import de.todesbaum.util.freenet.fcp2.ClientPutComplexDir;
+import de.todesbaum.util.freenet.fcp2.ClientPutDir.ManifestPutter;
+import de.todesbaum.util.freenet.fcp2.Connection;
+import de.todesbaum.util.freenet.fcp2.DirectFileEntry;
+import de.todesbaum.util.freenet.fcp2.FileEntry;
+import de.todesbaum.util.freenet.fcp2.Message;
+import de.todesbaum.util.freenet.fcp2.PriorityClass;
+import de.todesbaum.util.freenet.fcp2.RedirectFileEntry;
+import de.todesbaum.util.freenet.fcp2.Verbosity;
+import de.todesbaum.util.io.StreamCopier.ProgressListener;
+
+/**
+ * Manages project inserts.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class ProjectInserter implements FileScannerListener, Runnable {
+
+ /** The logger. */
+ private static final Logger logger = Logger.getLogger(ProjectInserter.class.getName());
+
+ /** Random number for FCP instances. */
+ private static final int random = (int) (Math.random() * Integer.MAX_VALUE);
+
+ /** Counter for FCP connection identifier. */
+ private static int counter = 0;
+
+ /** The list of insert listeners. */
+ private List<InsertListener> insertListeners = new ArrayList<InsertListener>();
+
+ /** The freenet interface. */
+ protected Freenet7Interface freenetInterface;
+
+ /** The project to insert. */
+ protected Project project;
+
+ /** The file scanner. */
+ private FileScanner fileScanner;
+
+ /** Object used for synchronization. */
+ protected final Object lockObject = new Object();
+
+ /** The temp directory. */
+ private String tempDirectory;
+
+ /** The current connection. */
+ private Connection connection;
+
+ /** Whether the insert is cancelled. */
+ private volatile boolean cancelled = false;
+
+ /** Progress listener for payload transfers. */
+ private ProgressListener progressListener;
+
+ /** Whether to use “early encode.” */
+ private boolean useEarlyEncode;
+
+ /** The insert priority. */
+ private PriorityClass priority;
+
+ /** The manifest putter. */
+ private ManifestPutter manifestPutter;
+
+ /**
+ * Adds a listener to the list of registered listeners.
+ *
+ * @param insertListener
+ * The listener to add
+ */
+ public void addInsertListener(InsertListener insertListener) {
+ insertListeners.add(insertListener);
+ }
+
+ /**
+ * Removes a listener from the list of registered listeners.
+ *
+ * @param insertListener
+ * The listener to remove
+ */
+ public void removeInsertListener(InsertListener insertListener) {
+ insertListeners.remove(insertListener);
+ }
+
+ /**
+ * Notifies all listeners that the project insert has started.
+ *
+ * @see InsertListener#projectInsertStarted(Project)
+ */
+ protected void fireProjectInsertStarted() {
+ for (InsertListener insertListener : insertListeners) {
+ insertListener.projectInsertStarted(project);
+ }
+ }
+
+ /**
+ * Notifies all listeners that the insert has generated a URI.
+ *
+ * @see InsertListener#projectURIGenerated(Project, String)
+ * @param uri
+ * The generated URI
+ */
+ protected void fireProjectURIGenerated(String uri) {
+ for (InsertListener insertListener : insertListeners) {
+ insertListener.projectURIGenerated(project, uri);
+ }
+ }
+
+ /**
+ * Notifies all listeners that the insert has made some progress.
+ *
+ * @see InsertListener#projectUploadFinished(Project)
+ */
+ protected void fireProjectUploadFinished() {
+ for (InsertListener insertListener : insertListeners) {
+ insertListener.projectUploadFinished(project);
+ }
+ }
+
+ /**
+ * Notifies all listeners that the insert has made some progress.
+ *
+ * @see InsertListener#projectInsertProgress(Project, int, int, int, int,
+ * boolean)
+ * @param succeeded
+ * The number of succeeded blocks
+ * @param failed
+ * The number of failed blocks
+ * @param fatal
+ * The number of fatally failed blocks
+ * @param total
+ * The total number of blocks
+ * @param finalized
+ * <code>true</code> if the total number of blocks has already
+ * been finalized, <code>false</code> otherwise
+ */
+ protected void fireProjectInsertProgress(int succeeded, int failed, int fatal, int total, boolean finalized) {
+ for (InsertListener insertListener : insertListeners) {
+ insertListener.projectInsertProgress(project, succeeded, failed, fatal, total, finalized);
+ }
+ }
+
+ /**
+ * Notifies all listeners the project insert has finished.
+ *
+ * @see InsertListener#projectInsertFinished(Project, boolean, Throwable)
+ * @param success
+ * <code>true</code> if the project was inserted successfully,
+ * <code>false</code> if it failed
+ * @param cause
+ * The cause of the failure, if any
+ */
+ protected void fireProjectInsertFinished(boolean success, Throwable cause) {
+ for (InsertListener insertListener : insertListeners) {
+ insertListener.projectInsertFinished(project, success, cause);
+ }
+ }
+
+ /**
+ * Sets the project to insert.
+ *
+ * @param project
+ * The project to insert
+ */
+ public void setProject(Project project) {
+ this.project = project;
+ }
+
+ /**
+ * Sets the freenet interface to use.
+ *
+ * @param freenetInterface
+ * The freenet interface to use
+ */
+ public void setFreenetInterface(Freenet7Interface freenetInterface) {
+ this.freenetInterface = freenetInterface;
+ }
+
+ /**
+ * Sets the temp directory to use.
+ *
+ * @param tempDirectory
+ * The temp directory to use, or {@code null} to use the system
+ * default
+ */
+ public void setTempDirectory(String tempDirectory) {
+ this.tempDirectory = tempDirectory;
+ }
+
+ /**
+ * Sets whether to use the “early encode“ flag for the insert.
+ *
+ * @param useEarlyEncode
+ * {@code true} to set the “early encode” flag for the insert,
+ * {@code false} otherwise
+ */
+ public void setUseEarlyEncode(boolean useEarlyEncode) {
+ this.useEarlyEncode = useEarlyEncode;
+ }
+
+ /**
+ * Sets the insert priority.
+ *
+ * @param priority
+ * The insert priority
+ */
+ public void setPriority(PriorityClass priority) {
+ this.priority = priority;
+ }
+
+ /**
+ * Sets the manifest putter to use for inserts.
+ *
+ * @param manifestPutter
+ * The manifest putter to use
+ */
+ public void setManifestPutter(ManifestPutter manifestPutter) {
+ this.manifestPutter = manifestPutter;
+ }
+
+ /**
+ * Starts the insert.
+ *
+ * @param progressListener
+ * Listener to notify on progress events
+ */
+ public void start(ProgressListener progressListener) {
+ cancelled = false;
+ this.progressListener = progressListener;
+ fileScanner = new FileScanner(project);
+ fileScanner.addFileScannerListener(this);
+ new Thread(fileScanner).start();
+ }
+
+ /**
+ * Stops the current insert.
+ */
+ public void stop() {
+ cancelled = true;
+ synchronized (lockObject) {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ }
+
+ /**
+ * Creates an input stream that delivers the given file, replacing edition
+ * tokens in the file’s content, if necessary.
+ *
+ * @param filename
+ * The name of the file
+ * @param fileOption
+ * The file options
+ * @param edition
+ * The current edition
+ * @param length
+ * An array containing a single long which is used to
+ * <em>return</em> the final length of the file, after all
+ * replacements
+ * @return The input stream for the file
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ private InputStream createFileInputStream(String filename, FileOption fileOption, int edition, long[] length) throws IOException {
+ File file = new File(project.getLocalPath(), filename);
+ length[0] = file.length();
+ return new FileInputStream(file);
+ }
+
+ /**
+ * Creates a file entry suitable for handing in to
+ * {@link ClientPutComplexDir#addFileEntry(FileEntry)}.
+ *
+ * @param file
+ * The name and hash of the file to insert
+ * @param edition
+ * The current edition
+ * @return A file entry for the given file
+ */
+ private FileEntry createFileEntry(ScannedFile file, int edition) {
+ FileEntry fileEntry = null;
+ String filename = file.getFilename();
+ FileOption fileOption = project.getFileOption(filename);
+ if (fileOption.isInsert()) {
+ fileOption.setCurrentHash(file.getHash());
+ /* check if file was modified. */
+ if (!fileOption.isForceInsert() && file.getHash().equals(fileOption.getLastInsertHash())) {
+ /* only insert a redirect. */
+ logger.log(Level.FINE, String.format("Inserting redirect to edition %d for %s.", fileOption.getLastInsertEdition(), filename));
+ return new RedirectFileEntry(fileOption.hasChangedName() ? fileOption.getChangedName() : filename, fileOption.getMimeType(), "SSK@" + project.getRequestURI() + "/" + project.getPath() + "-" + fileOption.getLastInsertEdition() + "/" + fileOption.getLastInsertFilename());
+ }
+ try {
+ long[] fileLength = new long[1];
+ InputStream fileEntryInputStream = createFileInputStream(filename, fileOption, edition, fileLength);
+ fileEntry = new DirectFileEntry(fileOption.hasChangedName() ? fileOption.getChangedName() : filename, fileOption.getMimeType(), fileEntryInputStream, fileLength[0]);
+ } catch (IOException ioe1) {
+ /* ignore, null is returned. */
+ }
+ } else {
+ if (fileOption.isInsertRedirect()) {
+ fileEntry = new RedirectFileEntry(fileOption.hasChangedName() ? fileOption.getChangedName() : filename, fileOption.getMimeType(), fileOption.getCustomKey());
+ }
+ }
+ return fileEntry;
+ }
+
+ /**
+ * 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) && (indexFile.length() > 0);
+ 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 = fileOptionEntries.isEmpty();
+ 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);
+ }
+ Set<String> fileNames = new HashSet<String>();
+ for (Entry<String, FileOption> fileOptionEntry : fileOptionEntries) {
+ FileOption fileOption = fileOptionEntry.getValue();
+ if (!fileOption.isInsert() && !fileOption.isInsertRedirect()) {
+ logger.log(Level.FINEST, "Ignoring {0}.", fileOptionEntry.getKey());
+ continue;
+ }
+ String fileName = fileOptionEntry.getKey();
+ if (fileOption.hasChangedName()) {
+ fileName = fileOption.getChangedName();
+ }
+ logger.log(Level.FINEST, "Adding “{0}” for {1}.", new Object[] { fileName, fileOptionEntry.getKey() });
+ if (!fileNames.add(fileName)) {
+ checkReport.addIssue("error.duplicate-file", true, fileName);
+ }
+ }
+ long totalSize = 0;
+ FileScanner fileScanner = new FileScanner(project);
+ final CountDownLatch completionLatch = new CountDownLatch(1);
+ fileScanner.addFileScannerListener(new FileScannerListener() {
+
+ @Override
+ public void fileScannerFinished(FileScanner fileScanner) {
+ completionLatch.countDown();
+ }
+ });
+ new Thread(fileScanner).start();
+ while (completionLatch.getCount() > 0) {
+ try {
+ completionLatch.await();
+ } catch (InterruptedException ie1) {
+ /* TODO: logging */
+ }
+ }
+ for (ScannedFile scannedFile : fileScanner.getFiles()) {
+ String fileName = scannedFile.getFilename();
+ FileOption fileOption = project.getFileOption(fileName);
+ if ((fileOption != null) && !fileOption.isInsert()) {
+ continue;
+ }
+ totalSize += new File(project.getLocalPath(), fileName).length();
+ }
+ if (totalSize > 2 * 1024 * 1024) {
+ checkReport.addIssue("warning.site-larger-than-2-mib", false);
+ }
+ return checkReport;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ fireProjectInsertStarted();
+ List<ScannedFile> files = fileScanner.getFiles();
+
+ /* create connection to node */
+ synchronized (lockObject) {
+ connection = freenetInterface.getConnection("project-insert-" + random + counter++);
+ }
+ connection.setTempDirectory(tempDirectory);
+ boolean connected = false;
+ Throwable cause = null;
+ try {
+ connected = connection.connect();
+ } catch (IOException e1) {
+ cause = e1;
+ }
+
+ if (!connected || cancelled) {
+ fireProjectInsertFinished(false, cancelled ? new AbortedException() : cause);
+ return;
+ }
+
+ Client client = new Client(connection);
+
+ /* collect files */
+ int edition = project.getEdition();
+ String dirURI = "USK@" + project.getInsertURI() + "/" + project.getPath() + "/" + edition + "/";
+ ClientPutComplexDir putDir = new ClientPutComplexDir("dir-" + counter++, dirURI, tempDirectory);
+ if ((project.getIndexFile() != null) && (project.getIndexFile().length() > 0)) {
+ putDir.setDefaultName(project.getIndexFile());
+ }
+ putDir.setVerbosity(Verbosity.ALL);
+ putDir.setMaxRetries(-1);
+ putDir.setEarlyEncode(useEarlyEncode);
+ putDir.setPriorityClass(priority);
+ putDir.setManifestPutter(manifestPutter);
+ for (ScannedFile file : files) {
+ FileEntry fileEntry = createFileEntry(file, edition);
+ if (fileEntry != null) {
+ try {
+ putDir.addFileEntry(fileEntry);
+ } catch (IOException ioe1) {
+ fireProjectInsertFinished(false, ioe1);
+ return;
+ }
+ }
+ }
+
+ /* start request */
+ try {
+ client.execute(putDir, progressListener);
+ fireProjectUploadFinished();
+ } catch (IOException ioe1) {
+ fireProjectInsertFinished(false, ioe1);
+ return;
+ }
+
+ /* parse progress and success messages */
+ String finalURI = null;
+ boolean success = false;
+ boolean finished = false;
+ boolean disconnected = false;
+ while (!finished && !cancelled) {
+ Message message = client.readMessage();
+ finished = (message == null) || (disconnected = client.isDisconnected());
+ logger.log(Level.FINE, "Received message: " + message);
+ if (!finished) {
+ @SuppressWarnings("null")
+ String messageName = message.getName();
+ if ("URIGenerated".equals(messageName)) {
+ finalURI = message.get("URI");
+ fireProjectURIGenerated(finalURI);
+ }
+ if ("SimpleProgress".equals(messageName)) {
+ int total = Integer.parseInt(message.get("Total"));
+ int succeeded = Integer.parseInt(message.get("Succeeded"));
+ int fatal = Integer.parseInt(message.get("FatallyFailed"));
+ int failed = Integer.parseInt(message.get("Failed"));
+ boolean finalized = Boolean.parseBoolean(message.get("FinalizedTotal"));
+ fireProjectInsertProgress(succeeded, failed, fatal, total, finalized);
+ }
+ success |= "PutSuccessful".equals(messageName);
+ finished = (success && (finalURI != null)) || "PutFailed".equals(messageName) || messageName.endsWith("Error");
+ }
+ }
+
+ /* post-insert work */
+ if (success) {
+ @SuppressWarnings("null")
+ String editionPart = finalURI.substring(finalURI.lastIndexOf('/') + 1);
+ int newEdition = Integer.parseInt(editionPart);
+ project.setEdition(newEdition);
+ project.setLastInsertionTime(System.currentTimeMillis());
+ project.onSuccessfulInsert();
+ }
+ fireProjectInsertFinished(success, cancelled ? new AbortedException() : (disconnected ? new IOException("Connection terminated") : null));
+ }
+
+ //
+ // INTERFACE FileScannerListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void fileScannerFinished(FileScanner fileScanner) {
+ if (!fileScanner.isError()) {
+ new Thread(this).start();
+ } else {
+ fireProjectInsertFinished(false, null);
+ }
+ 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;
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * jSite - UpdateChecker.java - Copyright © 2008–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import de.todesbaum.jsite.main.Main;
+import de.todesbaum.jsite.main.Version;
+import de.todesbaum.util.freenet.fcp2.Client;
+import de.todesbaum.util.freenet.fcp2.ClientGet;
+import de.todesbaum.util.freenet.fcp2.Connection;
+import de.todesbaum.util.freenet.fcp2.Message;
+import de.todesbaum.util.freenet.fcp2.Persistence;
+import de.todesbaum.util.freenet.fcp2.ReturnType;
+import de.todesbaum.util.freenet.fcp2.Verbosity;
+import de.todesbaum.util.io.Closer;
+
+/**
+ * Checks for newer versions of jSite.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class UpdateChecker implements Runnable {
+
+ /** The logger. */
+ private static final Logger logger = Logger.getLogger(UpdateChecker.class.getName());
+
+ /** Counter for connection names. */
+ private static int counter = 0;
+
+ /** The edition for the update check URL. */
+ private static final int UPDATE_EDITION = 17;
+
+ /** The URL for update checks. */
+ private static final String UPDATE_KEY = "USK@e3myoFyp5avg6WYN16ImHri6J7Nj8980Fm~aQe4EX1U,QvbWT0ImE0TwLODTl7EoJx2NBnwDxTbLTE6zkB-eGPs,AQACAAE";
+
+ /** Object used for synchronization. */
+ private final Object syncObject = new Object();
+
+ /** Update listeners. */
+ private final List<UpdateListener> updateListeners = new ArrayList<UpdateListener>();
+
+ /** Whether the main thread should stop. */
+ private boolean shouldStop = false;
+
+ /** Current last found edition of update key. */
+ private int lastUpdateEdition = UPDATE_EDITION;
+
+ /** Last found version. */
+ private Version lastVersion = Main.getVersion();
+
+ /** The freenet interface. */
+ private final Freenet7Interface freenetInterface;
+
+ /**
+ * Creates a new update checker that uses the given frame as its parent and
+ * communications via the given freenet interface.
+ *
+ * @param freenetInterface
+ * The freenet interface
+ */
+ public UpdateChecker(Freenet7Interface freenetInterface) {
+ this.freenetInterface = freenetInterface;
+ }
+
+ //
+ // EVENT LISTENER MANAGEMENT
+ //
+
+ /**
+ * Adds an update listener to the list of registered listeners.
+ *
+ * @param updateListener
+ * The update listener to add
+ */
+ public void addUpdateListener(UpdateListener updateListener) {
+ updateListeners.add(updateListener);
+ }
+
+ /**
+ * Removes the given listener from the list of registered listeners.
+ *
+ * @param updateListener
+ * The update listener to remove
+ */
+ public void removeUpdateListener(UpdateListener updateListener) {
+ updateListeners.remove(updateListener);
+ }
+
+ /**
+ * Notifies all listeners that a version was found.
+ *
+ * @param foundVersion
+ * The version that was found
+ * @param versionTimestamp
+ * The timestamp of the version
+ */
+ protected void fireUpdateFound(Version foundVersion, long versionTimestamp) {
+ for (UpdateListener updateListener : updateListeners) {
+ updateListener.foundUpdateData(foundVersion, versionTimestamp);
+ }
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the latest version that was found.
+ *
+ * @return The latest found version
+ */
+ public Version getLatestVersion() {
+ return lastVersion;
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Starts the update checker.
+ */
+ public void start() {
+ new Thread(this).start();
+ }
+
+ /**
+ * Stops the update checker.
+ */
+ public void stop() {
+ synchronized (syncObject) {
+ shouldStop = true;
+ syncObject.notifyAll();
+ }
+ }
+
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Returns whether the update checker should stop.
+ *
+ * @return <code>true</code> if the update checker should stop,
+ * <code>false</code> otherwise
+ */
+ private boolean shouldStop() {
+ synchronized (syncObject) {
+ return shouldStop;
+ }
+ }
+
+ /**
+ * Creates the URI of the update file for the given edition.
+ *
+ * @param edition
+ * The edition number
+ * @return The URI for the update file for the given edition
+ */
+ private String constructUpdateKey(int edition) {
+ return UPDATE_KEY + "/jSite/" + edition + "/jSite.properties";
+ }
+
+ //
+ // INTERFACE Runnable
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ Connection connection = freenetInterface.getConnection("jSite-" + ++counter + "-UpdateChecker");
+ try {
+ connection.connect();
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+ Client client = new Client(connection);
+ boolean checkNow = false;
+ int currentEdition = lastUpdateEdition;
+ while (!shouldStop()) {
+ checkNow = false;
+ logger.log(Level.FINE, "Trying " + constructUpdateKey(currentEdition));
+ ClientGet clientGet = new ClientGet("get-update-key");
+ clientGet.setUri(constructUpdateKey(currentEdition));
+ clientGet.setPersistence(Persistence.CONNECTION);
+ clientGet.setReturnType(ReturnType.direct);
+ clientGet.setVerbosity(Verbosity.ALL);
+ try {
+ client.execute(clientGet);
+ boolean stop = false;
+ while (!stop) {
+ Message message = client.readMessage();
+ logger.log(Level.FINEST, "Received message: " + message);
+ if (message == null) {
+ break;
+ }
+ if ("GetFailed".equals(message.getName())) {
+ if ("27".equals(message.get("code"))) {
+ String editionString = message.get("redirecturi").split("/")[2];
+ int editionNumber = -1;
+ try {
+ editionNumber = Integer.parseInt(editionString);
+ } catch (NumberFormatException nfe1) {
+ /* ignore. */
+ }
+ if (editionNumber != -1) {
+ logger.log(Level.INFO, "Found new edition " + editionNumber);
+ currentEdition = editionNumber;
+ lastUpdateEdition = editionNumber;
+ checkNow = true;
+ break;
+ }
+ }
+ }
+ if ("AllData".equals(message.getName())) {
+ logger.log(Level.FINE, "Update data found.");
+ InputStream dataInputStream = null;
+ Properties properties = new Properties();
+ try {
+ dataInputStream = message.getPayloadInputStream();
+ properties.load(dataInputStream);
+ } finally {
+ Closer.close(dataInputStream);
+ }
+
+ String foundVersionString = properties.getProperty("jSite.Version");
+ if (foundVersionString != null) {
+ Version foundVersion = Version.parse(foundVersionString);
+ if (foundVersion != null) {
+ lastVersion = foundVersion;
+ String versionTimestampString = properties.getProperty("jSite.Date");
+ logger.log(Level.FINEST, "Version timestamp: " + versionTimestampString);
+ long versionTimestamp = -1;
+ try {
+ versionTimestamp = Long.parseLong(versionTimestampString);
+ } catch (NumberFormatException nfe1) {
+ /* ignore. */
+ }
+ fireUpdateFound(foundVersion, versionTimestamp);
+ stop = true;
+ checkNow = true;
+ ++currentEdition;
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ logger.log(Level.INFO, "Got IOException: " + e.getMessage());
+ e.printStackTrace();
+ }
+ if (!checkNow && !shouldStop()) {
+ synchronized (syncObject) {
+ try {
+ syncObject.wait(15 * 60 * 1000);
+ } catch (InterruptedException ie1) {
+ /* ignore. */
+ }
+ }
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - UpdateListener.java - Copyright © 2008–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.application;
+
+import java.util.EventListener;
+
+import de.todesbaum.jsite.main.Version;
+
+/**
+ * Listener interface for objects that want to be notified when update data was
+ * found.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public interface UpdateListener extends EventListener {
+
+ /**
+ * Notifies a listener that data for the given version was found.
+ *
+ * @param foundVersion
+ * The version that was found
+ * @param versionTimestamp
+ * The timestamp of the version, or <code>-1</code> if the
+ * timestamp is unknown
+ */
+ public void foundUpdateData(Version foundVersion, long versionTimestamp);
+
+}
--- /dev/null
+/*
+ * jSite - FileScanner.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.util.io.Closer;
+import de.todesbaum.util.io.StreamCopier;
+
+/**
+ * Scans the local path of a project anychronously and returns the list of found
+ * files as an event.
+ *
+ * @see Project#getLocalPath()
+ * @see FileScannerListener#fileScannerFinished(FileScanner)
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class FileScanner implements Runnable {
+
+ /** The logger. */
+ private final static Logger logger = Logger.getLogger(FileScanner.class.getName());
+
+ /** The list of listeners. */
+ private final List<FileScannerListener> fileScannerListeners = new ArrayList<FileScannerListener>();
+
+ /** The project to scan. */
+ private final Project project;
+
+ /** The list of found files. */
+ private List<ScannedFile> files;
+
+ /** Wether there was an error. */
+ private boolean error = false;
+
+ /**
+ * Creates a new file scanner for the given project.
+ *
+ * @param project
+ * The project whose files to scan
+ */
+ public FileScanner(Project project) {
+ this.project = project;
+ }
+
+ /**
+ * Adds the given listener to the list of listeners.
+ *
+ * @param fileScannerListener
+ * The listener to add
+ */
+ public void addFileScannerListener(FileScannerListener fileScannerListener) {
+ fileScannerListeners.add(fileScannerListener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners.
+ *
+ * @param fileScannerListener
+ * The listener to remove
+ */
+ public void removeFileScannerListener(FileScannerListener fileScannerListener) {
+ fileScannerListeners.remove(fileScannerListener);
+ }
+
+ /**
+ * Notifies all listeners that the file scan finished.
+ */
+ protected void fireFileScannerFinished() {
+ for (FileScannerListener fileScannerListener : new ArrayList<FileScannerListener>(fileScannerListeners)) {
+ fileScannerListener.fileScannerFinished(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Scans all available files in the project’s local path and emits an event
+ * when finished.
+ *
+ * @see FileScannerListener#fileScannerFinished(FileScanner)
+ */
+ public void run() {
+ files = new ArrayList<ScannedFile>();
+ error = false;
+ try {
+ scanFiles(new File(project.getLocalPath()), files);
+ Collections.sort(files);
+ } catch (IOException ioe1) {
+ error = true;
+ }
+ fireFileScannerFinished();
+ }
+
+ /**
+ * Returns whether there was an error scanning for files.
+ *
+ * @return <code>true</code> if there was an error, <code>false</code>
+ * otherwise
+ */
+ public boolean isError() {
+ return error;
+ }
+
+ /**
+ * Returns the list of found files.
+ *
+ * @return The list of found files
+ */
+ public List<ScannedFile> getFiles() {
+ return files;
+ }
+
+ /**
+ * Recursively scans a directory and adds all found files to the given list.
+ *
+ * @param rootDir
+ * The directory to scan
+ * @param fileList
+ * The list to which to add the found files
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ private void scanFiles(File rootDir, List<ScannedFile> fileList) throws IOException {
+ File[] files = rootDir.listFiles(new FileFilter() {
+
+ @SuppressWarnings("synthetic-access")
+ public boolean accept(File file) {
+ return !project.isIgnoreHiddenFiles() || !file.isHidden();
+ }
+ });
+ if (files == null) {
+ throw new IOException(I18n.getMessage("jsite.file-scanner.can-not-read-directory"));
+ }
+ for (File file : files) {
+ if (file.isDirectory()) {
+ scanFiles(file, fileList);
+ continue;
+ }
+ String filename = project.shortenFilename(file).replace('\\', '/');
+ String hash = hashFile(project.getLocalPath(), filename);
+ fileList.add(new ScannedFile(filename, hash));
+ }
+ }
+
+ /**
+ * Hashes the given file.
+ *
+ * @param path
+ * The path of the project
+ * @param filename
+ * The name of the file, relative to the project path
+ * @return The hash of the file
+ */
+ @SuppressWarnings("synthetic-access")
+ private static String hashFile(String path, String filename) {
+ InputStream fileInputStream = null;
+ DigestOutputStream digestOutputStream = null;
+ File file = new File(path, filename);
+ try {
+ fileInputStream = new FileInputStream(file);
+ digestOutputStream = new DigestOutputStream(new NullOutputStream(), MessageDigest.getInstance("SHA-256"));
+ StreamCopier.copy(fileInputStream, digestOutputStream, file.length());
+ return toHex(digestOutputStream.getMessageDigest().digest());
+ } catch (NoSuchAlgorithmException nsae1) {
+ logger.log(Level.WARNING, "Could not get SHA-256 digest!", nsae1);
+ } catch (IOException ioe1) {
+ logger.log(Level.WARNING, "Could not read file!", ioe1);
+ } finally {
+ Closer.close(digestOutputStream);
+ Closer.close(fileInputStream);
+ }
+ return toHex(new byte[32]);
+ }
+
+ /**
+ * Converts the given byte array into a hexadecimal string.
+ *
+ * @param array
+ * The array to convert
+ * @return The hexadecimal string
+ */
+ private static String toHex(byte[] array) {
+ StringBuilder hexString = new StringBuilder(array.length * 2);
+ for (byte b : array) {
+ hexString.append("0123456789abcdef".charAt((b >>> 4) & 0x0f)).append("0123456789abcdef".charAt(b & 0xf));
+ }
+ return hexString.toString();
+ }
+
+ /**
+ * {@link OutputStream} that discards all written bytes.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+ private static class NullOutputStream extends OutputStream {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(int b) {
+ /* do nothing. */
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(byte[] b) {
+ /* do nothing. */
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(byte[] b, int off, int len) {
+ /* do nothing. */
+ }
+
+ }
+
+ /**
+ * Container for a scanned file, consisting of the name of the file and its
+ * hash.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+ public static class ScannedFile implements Comparable<ScannedFile> {
+
+ /** The name of the file. */
+ private final String filename;
+
+ /** The hash of the file. */
+ private final String hash;
+
+ /**
+ * Creates a new scanned file.
+ *
+ * @param filename
+ * The name of the file
+ * @param hash
+ * The hash of the file
+ */
+ public ScannedFile(String filename, String hash) {
+ this.filename = filename;
+ this.hash = hash;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the name of the file.
+ *
+ * @return The name of the file
+ */
+ public String getFilename() {
+ return filename;
+ }
+
+ /**
+ * Returns the hash of the file.
+ *
+ * @return The hash of the file
+ */
+ public String getHash() {
+ return hash;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return filename.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return filename.equals(obj);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return filename;
+ }
+
+ //
+ // COMPARABLE METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(ScannedFile scannedFile) {
+ return filename.compareTo(scannedFile.filename);
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * jSite - FileScannerListener.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.util.EventListener;
+
+/**
+ * Listener interface for objects that want to be notified when scanning a
+ * project’s local path has finished.
+ *
+ * @see FileScanner
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public interface FileScannerListener extends EventListener {
+
+ /**
+ * Notifies a listener that scanning a project’s local path has finished.
+ *
+ * @param fileScanner
+ * The file scanner that finished
+ */
+ public void fileScannerFinished(FileScanner fileScanner);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite - NodeManagerListener.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.util.EventListener;
+
+import de.todesbaum.jsite.application.Node;
+
+/**
+ * Listener interface for objects that want to be notified if the node
+ * configuration changes.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public interface NodeManagerListener extends EventListener {
+
+ /**
+ * Notifies a listener that the node configuration was changed.
+ *
+ * @param nodes
+ * The new list of nodes
+ */
+ public void nodesUpdated(Node[] nodes);
+
+ /**
+ * Notifies a listener that the selected node has changed.
+ *
+ * @param node
+ * The new selected node
+ */
+ public void nodeSelected(Node node);
+
+}
--- /dev/null
+/*
+ * jSite - NodeManagerPage.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import de.todesbaum.jsite.application.Node;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.jsite.i18n.I18nContainer;
+import de.todesbaum.util.swing.TLabel;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * Wizard page that lets the user edit his nodes.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class NodeManagerPage extends TWizardPage implements ListSelectionListener, DocumentListener, ChangeListener {
+
+ /** List of node manager listeners. */
+ private List<NodeManagerListener> nodeManagerListeners = new ArrayList<NodeManagerListener>();
+
+ /** The “add node” action. */
+ protected Action addNodeAction;
+
+ /** The “delete node” action. */
+ protected Action deleteNodeAction;
+
+ /** The node list model. */
+ private DefaultListModel nodeListModel;
+
+ /** The node list. */
+ private JList nodeList;
+
+ /** The node name textfield. */
+ private JTextField nodeNameTextField;
+
+ /** The node hostname textfield. */
+ private JTextField nodeHostnameTextField;
+
+ /** The spinner for the node port. */
+ private JSpinner nodePortSpinner;
+
+ /**
+ * Creates a new node manager wizard page.
+ *
+ * @param wizard
+ * The wizard this page belongs to
+ */
+ public NodeManagerPage(final TWizard wizard) {
+ super(wizard);
+ pageInit();
+ setHeading(I18n.getMessage("jsite.node-manager.heading"));
+ setDescription(I18n.getMessage("jsite.node-manager.description"));
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ setHeading(I18n.getMessage("jsite.node-manager.heading"));
+ setDescription(I18n.getMessage("jsite.node-manager.description"));
+ }
+ });
+ }
+
+ /**
+ * Adds a listener for node manager events.
+ *
+ * @param nodeManagerListener
+ * The listener to add
+ */
+ public void addNodeManagerListener(NodeManagerListener nodeManagerListener) {
+ nodeManagerListeners.add(nodeManagerListener);
+ }
+
+ /**
+ * Removes a listener for node manager events.
+ *
+ * @param nodeManagerListener
+ * The listener to remove
+ */
+ public void removeNodeManagerListener(NodeManagerListener nodeManagerListener) {
+ nodeManagerListeners.remove(nodeManagerListener);
+ }
+
+ /**
+ * Notifies all listeners that the node configuration has changed.
+ *
+ * @param nodes
+ * The new list of nodes
+ */
+ protected void fireNodesUpdated(Node[] nodes) {
+ for (NodeManagerListener nodeManagerListener : nodeManagerListeners) {
+ nodeManagerListener.nodesUpdated(nodes);
+ }
+ }
+
+ /**
+ * Notifies all listeners that a new node was selected.
+ *
+ * @param node
+ * The newly selected node
+ */
+ protected void fireNodeSelected(Node node) {
+ for (NodeManagerListener nodeManagerListener : nodeManagerListeners) {
+ nodeManagerListener.nodeSelected(node);
+ }
+ }
+
+ /**
+ * Creates all actions.
+ */
+ private void createActions() {
+ addNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.add-node")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ addNode();
+ }
+ };
+
+ deleteNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.delete-node")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ deleteNode();
+ }
+ };
+ deleteNodeAction.setEnabled(false);
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ addNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.node-manager.add-node"));
+ deleteNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.node-manager.delete-node"));
+ }
+ });
+ }
+
+ /**
+ * Initializes the page and all components in it.
+ */
+ private void pageInit() {
+ createActions();
+ nodeListModel = new DefaultListModel();
+ nodeList = new JList(nodeListModel);
+ nodeList.setName("node-list");
+ nodeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ nodeList.addListSelectionListener(this);
+ nodeList.setPreferredSize(new Dimension(250, -1));
+
+ nodeNameTextField = new JTextField("");
+ nodeNameTextField.getDocument().putProperty("Name", "node-name");
+ nodeNameTextField.getDocument().addDocumentListener(this);
+ nodeNameTextField.setEnabled(false);
+
+ nodeHostnameTextField = new JTextField("localhost");
+ nodeHostnameTextField.getDocument().putProperty("Name", "node-hostname");
+ nodeHostnameTextField.getDocument().addDocumentListener(this);
+ nodeHostnameTextField.setEnabled(false);
+
+ nodePortSpinner = new JSpinner(new SpinnerNumberModel(9481, 1, 65535, 1));
+ nodePortSpinner.setName("node-port");
+ nodePortSpinner.addChangeListener(this);
+ nodePortSpinner.setEnabled(false);
+
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
+ buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12));
+ buttonPanel.add(new JButton(addNodeAction));
+ buttonPanel.add(new JButton(deleteNodeAction));
+
+ JPanel centerPanel = new JPanel(new BorderLayout());
+ JPanel nodeInformationPanel = new JPanel(new GridBagLayout());
+ centerPanel.add(nodeInformationPanel, BorderLayout.PAGE_START);
+ nodeInformationPanel.add(buttonPanel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ final JLabel nodeInformationLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.node-manager.node-information") + "</b></html>");
+ nodeInformationPanel.add(nodeInformationLabel, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0));
+ final TLabel nodeNameLabel = new TLabel(I18n.getMessage("jsite.node-manager.name") + ":", KeyEvent.VK_N, nodeNameTextField);
+ nodeInformationPanel.add(nodeNameLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ nodeInformationPanel.add(nodeNameTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ final TLabel nodeHostnameLabel = new TLabel(I18n.getMessage("jsite.node-manager.hostname") + ":", KeyEvent.VK_H, nodeHostnameTextField);
+ nodeInformationPanel.add(nodeHostnameLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ nodeInformationPanel.add(nodeHostnameTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ final TLabel nodePortLabel = new TLabel(I18n.getMessage("jsite.node-manager.port") + ":", KeyEvent.VK_P, nodePortSpinner);
+ nodeInformationPanel.add(nodePortLabel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ nodeInformationPanel.add(nodePortSpinner, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0));
+
+ setLayout(new BorderLayout(12, 12));
+ add(new JScrollPane(nodeList), BorderLayout.LINE_START);
+ add(centerPanel, BorderLayout.CENTER);
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ nodeInformationLabel.setText("<html><b>" + I18n.getMessage("jsite.node-manager.node-information") + "</b></html>");
+ nodeNameLabel.setText(I18n.getMessage("jsite.node-manager.name") + ":");
+ nodeHostnameLabel.setText(I18n.getMessage("jsite.node-manager.hostname") + ":");
+ nodePortLabel.setText(I18n.getMessage("jsite.node-manager.port") + ":");
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ this.wizard.setNextEnabled(nodeListModel.getSize() > 0);
+ this.wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
+ this.wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
+ this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
+ }
+
+ /**
+ * Sets the node list.
+ *
+ * @param nodes
+ * The list of nodes
+ */
+ public void setNodes(Node[] nodes) {
+ nodeListModel.clear();
+ for (Node node : nodes) {
+ nodeListModel.addElement(node);
+ }
+ nodeList.repaint();
+ fireNodesUpdated(nodes);
+ }
+
+ /**
+ * Returns the node list.
+ *
+ * @return The list of nodes
+ */
+ public Node[] getNodes() {
+ Node[] returnNodes = new Node[nodeListModel.getSize()];
+ for (int nodeIndex = 0, nodeCount = nodeListModel.getSize(); nodeIndex < nodeCount; nodeIndex++) {
+ returnNodes[nodeIndex] = (Node) nodeListModel.get(nodeIndex);
+ }
+ return returnNodes;
+ }
+
+ /**
+ * Returns the currently selected node.
+ *
+ * @return The selected node, or <code>null</code> if no node is selected
+ */
+ private Node getSelectedNode() {
+ return (Node) nodeList.getSelectedValue();
+ }
+
+ /**
+ * Updates node name or hostname when the user types into the textfields.
+ *
+ * @see #insertUpdate(DocumentEvent)
+ * @see #removeUpdate(DocumentEvent)
+ * @see #changedUpdate(DocumentEvent)
+ * @see DocumentListener
+ * @param documentEvent
+ * The document event
+ */
+ private void updateTextField(DocumentEvent documentEvent) {
+ Node node = getSelectedNode();
+ if (node == null) {
+ return;
+ }
+ Document document = documentEvent.getDocument();
+ String documentText = null;
+ try {
+ documentText = document.getText(0, document.getLength());
+ } catch (BadLocationException ble1) {
+ /* ignore. */
+ }
+ if (documentText == null) {
+ return;
+ }
+ String documentName = (String) document.getProperty("Name");
+ if ("node-name".equals(documentName)) {
+ node.setName(documentText);
+ nodeList.repaint();
+ fireNodesUpdated(getNodes());
+ } else if ("node-hostname".equals(documentName)) {
+ node.setHostname(documentText);
+ nodeList.repaint();
+ fireNodesUpdated(getNodes());
+ }
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Adds a new node to the list of nodes.
+ */
+ private void addNode() {
+ Node node = new Node("localhost", 9481, I18n.getMessage("jsite.node-manager.new-node"));
+ nodeListModel.addElement(node);
+ deleteNodeAction.setEnabled(nodeListModel.size() > 1);
+ wizard.setNextEnabled(true);
+ fireNodesUpdated(getNodes());
+ }
+
+ /**
+ * Deletes the currently selected node from the list of nodes.
+ */
+ private void deleteNode() {
+ Node node = getSelectedNode();
+ if (node == null) {
+ return;
+ }
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.node-manager.delete-node.warning"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) {
+ return;
+ }
+ int nodeIndex = nodeListModel.indexOf(node);
+ nodeListModel.removeElement(node);
+ nodeList.repaint();
+ fireNodeSelected((Node) nodeListModel.get(Math.min(nodeIndex, nodeListModel.size() - 1)));
+ fireNodesUpdated(getNodes());
+ deleteNodeAction.setEnabled(nodeListModel.size() > 1);
+ wizard.setNextEnabled(nodeListModel.size() > 0);
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("null")
+ public void valueChanged(ListSelectionEvent e) {
+ Object source = e.getSource();
+ if (source instanceof JList) {
+ JList sourceList = (JList) source;
+ if ("node-list".equals(sourceList.getName())) {
+ Node node = (Node) sourceList.getSelectedValue();
+ boolean enabled = (node != null);
+ nodeNameTextField.setEnabled(enabled);
+ nodeHostnameTextField.setEnabled(enabled);
+ nodePortSpinner.setEnabled(enabled);
+ deleteNodeAction.setEnabled(enabled && (nodeListModel.size() > 1));
+ if (enabled) {
+ nodeNameTextField.setText(node.getName());
+ nodeHostnameTextField.setText(node.getHostname());
+ nodePortSpinner.setValue(node.getPort());
+ } else {
+ nodeNameTextField.setText("");
+ nodeHostnameTextField.setText("localhost");
+ nodePortSpinner.setValue(9481);
+ }
+ }
+ }
+ }
+
+ //
+ // INTERFACE DocumentListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void insertUpdate(DocumentEvent e) {
+ updateTextField(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeUpdate(DocumentEvent e) {
+ updateTextField(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changedUpdate(DocumentEvent e) {
+ updateTextField(e);
+ }
+
+ //
+ // INTERFACE ChangeListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateChanged(ChangeEvent e) {
+ Object source = e.getSource();
+ Node selectedNode = getSelectedNode();
+ if (selectedNode == null) {
+ return;
+ }
+ if (source instanceof JSpinner) {
+ JSpinner sourceSpinner = (JSpinner) source;
+ if ("node-port".equals(sourceSpinner.getName())) {
+ selectedNode.setPort((Integer) sourceSpinner.getValue());
+ fireNodeSelected(selectedNode);
+ nodeList.repaint();
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - PreferencesPage.java - Copyright © 2009–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.jsite.i18n.I18nContainer;
+import de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation;
+import de.todesbaum.util.freenet.fcp2.ClientPutDir.ManifestPutter;
+import de.todesbaum.util.freenet.fcp2.PriorityClass;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * Page that shows some preferences that are valid for the complete application.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class PreferencesPage extends TWizardPage {
+
+ /** Select default temp directory action. */
+ private Action selectDefaultTempDirectoryAction;
+
+ /** Select custom temp directory action. */
+ private Action selectCustomTempDirectoryAction;
+
+ /** Action that chooses a new temp directory. */
+ private Action chooseTempDirectoryAction;
+
+ /** Action when selecting “next to JAR file.” */
+ private Action nextToJarFileAction;
+
+ /** Action when selecting “home directory.” */
+ private Action homeDirectoryAction;
+
+ /** Action when selecting “custom directory.” */
+ private Action customDirectoryAction;
+
+ /** Action when selecting “use early encode.” */
+ private Action useEarlyEncodeAction;
+
+ /** Action when a priority was selected. */
+ private Action priorityAction;
+
+ /** The text field containing the directory. */
+ private JTextField tempDirectoryTextField;
+
+ /** The temp directory. */
+ private String tempDirectory;
+
+ /** The configuration location. */
+ private ConfigurationLocation configurationLocation;
+
+ /** Whether to use “early encode.” */
+ private boolean useEarlyEncode;
+
+ /** The prioriy for inserts. */
+ private PriorityClass priority;
+
+ /** The “default” button. */
+ private JRadioButton defaultTempDirectory;
+
+ /** The “custom” button. */
+ private JRadioButton customTempDirectory;
+
+ /** The “next to JAR file” checkbox. */
+ private JRadioButton nextToJarFile;
+
+ /** The “home directory” checkbox. */
+ private JRadioButton homeDirectory;
+
+ /** The “custom directory” checkbox. */
+ private JRadioButton customDirectory;
+
+ /** The “use early encode” checkbox. */
+ private JCheckBox useEarlyEncodeCheckBox;
+
+ /** The insert priority select box. */
+ private JComboBox insertPriorityComboBox;
+
+ /** The manifest putter select box. */
+ private JComboBox manifestPutterComboBox;
+
+ /**
+ * Creates a new “preferences” page.
+ *
+ * @param wizard
+ * The wizard this page belongs to
+ */
+ public PreferencesPage(TWizard wizard) {
+ super(wizard);
+ pageInit();
+ setHeading(I18n.getMessage("jsite.preferences.heading"));
+ setDescription(I18n.getMessage("jsite.preferences.description"));
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ setHeading(I18n.getMessage("jsite.preferences.heading"));
+ setDescription(I18n.getMessage("jsite.preferences.description"));
+ }
+ });
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the temp directory.
+ *
+ * @return The temp directory, or {@code null} to use the default temp
+ * directory
+ */
+ public String getTempDirectory() {
+ return tempDirectory;
+ }
+
+ /**
+ * Sets the temp directory.
+ *
+ * @param tempDirectory
+ * The temp directory, or {@code null} to use the default temp
+ * directory
+ */
+ public void setTempDirectory(String tempDirectory) {
+ this.tempDirectory = tempDirectory;
+ tempDirectoryTextField.setText((tempDirectory != null) ? tempDirectory : "");
+ if (tempDirectory != null) {
+ customTempDirectory.setSelected(true);
+ chooseTempDirectoryAction.setEnabled(true);
+ } else {
+ defaultTempDirectory.setSelected(true);
+ }
+ }
+
+ /**
+ * Returns the configuration location.
+ *
+ * @return The configuration location
+ */
+ public ConfigurationLocation getConfigurationLocation() {
+ return configurationLocation;
+ }
+
+ /**
+ * Sets the configuration location.
+ *
+ * @param configurationLocation
+ * The configuration location
+ */
+ 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);
+ }
+
+ /**
+ * Returns whether to use the “early encode“ flag for the insert.
+ *
+ * @return {@code true} to set the “early encode” flag for the insert,
+ * {@code false} otherwise
+ */
+ public boolean useEarlyEncode() {
+ return useEarlyEncode;
+ }
+
+ /**
+ * Sets whether to use the “early encode“ flag for the insert.
+ *
+ * @param useEarlyEncode
+ * {@code true} to set the “early encode” flag for the insert,
+ * {@code false} otherwise
+ */
+ public void setUseEarlyEncode(boolean useEarlyEncode) {
+ useEarlyEncodeCheckBox.setSelected(useEarlyEncode);
+ }
+
+ /**
+ * Returns the configured insert priority.
+ *
+ * @return The insert priority
+ */
+ public PriorityClass getPriority() {
+ return priority;
+ }
+
+ /**
+ * Sets the insert priority.
+ *
+ * @param priority
+ * The insert priority
+ */
+ public void setPriority(PriorityClass priority) {
+ insertPriorityComboBox.setSelectedItem(priority);
+ }
+
+ /**
+ * Returns the selected manifest putter.
+ *
+ * @return The selected manifest putter
+ */
+ public ManifestPutter getManifestPutter() {
+ return (ManifestPutter) manifestPutterComboBox.getSelectedItem();
+ }
+
+ /**
+ * Sets the manifest putter.
+ *
+ * @param manifestPutter
+ * The manifest putter
+ */
+ public void setManifestPutter(ManifestPutter manifestPutter) {
+ manifestPutterComboBox.setSelectedItem(manifestPutter);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ super.pageAdded(wizard);
+ this.wizard.setPreviousName(I18n.getMessage("jsite.menu.nodes.manage-nodes"));
+ this.wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
+ this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
+ this.wizard.setNextEnabled(false);
+ }
+
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Initializes this page.
+ */
+ private void pageInit() {
+ createActions();
+ setLayout(new BorderLayout(12, 12));
+ add(createPreferencesPanel(), BorderLayout.CENTER);
+ }
+
+ /**
+ * Creates all actions.
+ */
+ private void createActions() {
+ selectDefaultTempDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.temp-directory.default")) {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ selectDefaultTempDirectory();
+ }
+ };
+ selectCustomTempDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.temp-directory.custom")) {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ selectCustomTempDirectory();
+ }
+ };
+ chooseTempDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.temp-directory.choose")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent e) {
+ chooseTempDirectory();
+ }
+ };
+ nextToJarFileAction = new AbstractAction(I18n.getMessage("jsite.preferences.config-directory.jar")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionevent) {
+ configurationLocation = ConfigurationLocation.NEXT_TO_JAR_FILE;
+ }
+ };
+ homeDirectoryAction = new AbstractAction(I18n.getMessage("jsite.preferences.config-directory.home")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionevent) {
+ 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;
+ }
+ };
+ useEarlyEncodeAction = new AbstractAction(I18n.getMessage("jsite.preferences.insert-options.use-early-encode")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ useEarlyEncode = useEarlyEncodeCheckBox.isSelected();
+ }
+ };
+ priorityAction = new AbstractAction(I18n.getMessage("jsite.preferences.insert-options.priority")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ priority = (PriorityClass) insertPriorityComboBox.getSelectedItem();
+ }
+ };
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ selectDefaultTempDirectoryAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.temp-directory.default"));
+ selectCustomTempDirectoryAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.temp-directory.custom"));
+ 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"));
+ useEarlyEncodeAction.putValue(Action.NAME, I18n.getMessage("jsite.preferences.insert-options.use-early-encode"));
+ }
+ });
+ }
+
+ /**
+ * Creates the panel containing all preferences.
+ *
+ * @return The preferences panel
+ */
+ private JPanel createPreferencesPanel() {
+ JPanel preferencesPanel = new JPanel(new GridBagLayout());
+ preferencesPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
+
+ final JLabel tempDirectoryLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.preferences.temp-directory") + "</b></html>");
+ preferencesPanel.add(tempDirectoryLabel, new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
+
+ defaultTempDirectory = new JRadioButton(selectDefaultTempDirectoryAction);
+ preferencesPanel.add(defaultTempDirectory, new GridBagConstraints(0, 1, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 18, 0, 0), 0, 0));
+
+ customTempDirectory = new JRadioButton(selectCustomTempDirectoryAction);
+ preferencesPanel.add(customTempDirectory, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 18, 0, 0), 0, 0));
+
+ ButtonGroup tempDirectoryButtonGroup = new ButtonGroup();
+ defaultTempDirectory.getModel().setGroup(tempDirectoryButtonGroup);
+ customTempDirectory.getModel().setGroup(tempDirectoryButtonGroup);
+
+ tempDirectoryTextField = new JTextField();
+ tempDirectoryTextField.setEditable(false);
+ if (tempDirectory != null) {
+ tempDirectoryTextField.setText(tempDirectory);
+ customTempDirectory.setSelected(true);
+ } else {
+ defaultTempDirectory.setSelected(true);
+ }
+ chooseTempDirectoryAction.setEnabled(tempDirectory != null);
+ preferencesPanel.add(tempDirectoryTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 6, 0, 0), 0, 0));
+
+ JButton chooseButton = new JButton(chooseTempDirectoryAction);
+ preferencesPanel.add(chooseButton, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.BOTH, new Insets(0, 6, 0, 0), 0, 0));
+
+ final JLabel configurationDirectoryLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.preferences.config-directory") + "</b></html>");
+ preferencesPanel.add(configurationDirectoryLabel, new GridBagConstraints(0, 3, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(12, 0, 0, 0), 0, 0));
+
+ nextToJarFile = new JRadioButton(nextToJarFileAction);
+ preferencesPanel.add(nextToJarFile, new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 18, 0, 0), 0, 0));
+
+ 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(homeDirectory);
+ configurationDirectoryButtonGroup.add(customDirectory);
+
+ final JLabel insertOptionsLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.preferences.insert-options") + "</b></html>");
+ preferencesPanel.add(insertOptionsLabel, new GridBagConstraints(0, 7, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
+
+ useEarlyEncodeCheckBox = new JCheckBox(useEarlyEncodeAction);
+ preferencesPanel.add(useEarlyEncodeCheckBox, new GridBagConstraints(0, 8, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+
+ final JLabel insertPriorityLabel = new JLabel(I18n.getMessage("jsite.preferences.insert-options.priority"));
+ preferencesPanel.add(insertPriorityLabel, new GridBagConstraints(0, 9, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+
+ insertPriorityComboBox = new JComboBox(new PriorityClass[] { PriorityClass.MINIMUM, PriorityClass.PREFETCH, PriorityClass.BULK, PriorityClass.UPDATABLE, PriorityClass.SEMI_INTERACTIVE, PriorityClass.INTERACTIVE, PriorityClass.MAXIMUM });
+ insertPriorityComboBox.setAction(priorityAction);
+ preferencesPanel.add(insertPriorityComboBox, new GridBagConstraints(1, 9, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 18, 0, 0), 0, 0));
+
+ final JLabel manifestPutterLabel = new JLabel(I18n.getMessage("jsite.preferences.insert-options.manifest-putter"));
+ preferencesPanel.add(manifestPutterLabel, new GridBagConstraints(0, 10, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+
+ manifestPutterComboBox = new JComboBox(ManifestPutter.values());
+ preferencesPanel.add(manifestPutterComboBox, new GridBagConstraints(1, 10, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 18, 0, 0), 0, 0));
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ tempDirectoryLabel.setText("<html><b>" + I18n.getMessage("jsite.preferences.temp-directory") + "</b></html>");
+ configurationDirectoryLabel.setText("<html><b>" + I18n.getMessage("jsite.preferences.config-directory") + "</b></html>");
+ insertOptionsLabel.setText("<html><b>" + I18n.getMessage("jsite.preferences.insert-options") + "</b></html>");
+ insertPriorityLabel.setText(I18n.getMessage("jsite.preferences.insert-options.priority"));
+ manifestPutterLabel.setText(I18n.getMessage("jsite.preferences.insert-options.manifest-putter"));
+ }
+ });
+
+ return preferencesPanel;
+ }
+
+ /**
+ * Activates the default temp directory radio button.
+ */
+ private void selectDefaultTempDirectory() {
+ tempDirectoryTextField.setEnabled(false);
+ chooseTempDirectoryAction.setEnabled(false);
+ tempDirectory = null;
+ }
+
+ /**
+ * Activates the custom temp directory radio button.
+ */
+ private void selectCustomTempDirectory() {
+ tempDirectoryTextField.setEnabled(true);
+ chooseTempDirectoryAction.setEnabled(true);
+ if (tempDirectoryTextField.getText().length() == 0) {
+ chooseTempDirectory();
+ if (tempDirectoryTextField.getText().length() == 0) {
+ defaultTempDirectory.setSelected(true);
+ }
+ }
+ }
+
+ /**
+ * Lets the user choose a new temp directory.
+ */
+ private void chooseTempDirectory() {
+ JFileChooser fileChooser = new JFileChooser(tempDirectory);
+ fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ int returnValue = fileChooser.showDialog(wizard, I18n.getMessage("jsite.preferences.temp-directory.choose.approve"));
+ if (returnValue == JFileChooser.CANCEL_OPTION) {
+ return;
+ }
+ tempDirectory = fileChooser.getSelectedFile().getPath();
+ tempDirectoryTextField.setText(tempDirectory);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ProjectFilesPage.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.text.MessageFormat;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import de.todesbaum.jsite.application.FileOption;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.gui.FileScanner.ScannedFile;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.jsite.i18n.I18nContainer;
+import de.todesbaum.util.mime.DefaultMIMETypes;
+import de.todesbaum.util.swing.TLabel;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * Wizard page that lets the user manage the files of a project.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class ProjectFilesPage extends TWizardPage implements ActionListener, ListSelectionListener, DocumentListener, FileScannerListener {
+
+ /** The project. */
+ private Project project;
+
+ /** The “scan files” action. */
+ private Action scanAction;
+
+ /** The “ignore hidden files” checkbox. */
+ private JCheckBox ignoreHiddenFilesCheckBox;
+
+ /** The list of project files. */
+ private JList projectFileList;
+
+ /** The “default file” checkbox. */
+ private JCheckBox defaultFileCheckBox;
+
+ /** The “insert” checkbox. */
+ private JCheckBox fileOptionsInsertCheckBox;
+
+ /** The “force insert” checkbox. */
+ private JCheckBox fileOptionsForceInsertCheckBox;
+
+ /** The “insert redirect” checkbox. */
+ private JCheckBox fileOptionsInsertRedirectCheckBox;
+
+ /** The “custom key” textfield. */
+ private JTextField fileOptionsCustomKeyTextField;
+
+ /** The “rename” check box. */
+ private JCheckBox fileOptionsRenameCheckBox;
+
+ /** The “new name” text field. */
+ private JTextField fileOptionsRenameTextField;
+
+ /** The “mime type” combo box. */
+ private JComboBox fileOptionsMIMETypeComboBox;
+
+ /**
+ * Creates a new project file page.
+ *
+ * @param wizard
+ * The wizard the page belongs to
+ */
+ public ProjectFilesPage(final TWizard wizard) {
+ super(wizard);
+ pageInit();
+ }
+
+ /**
+ * Initializes the page and all its actions and components.
+ */
+ private void pageInit() {
+ createActions();
+ setLayout(new BorderLayout(12, 12));
+ add(createProjectFilesPanel(), BorderLayout.CENTER);
+ }
+
+ /**
+ * Creates all actions.
+ */
+ private void createActions() {
+ scanAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.rescan")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionScan();
+ }
+ };
+ scanAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
+ scanAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.rescan.tooltip"));
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ scanAction.putValue(Action.NAME, I18n.getMessage("jsite.project-files.action.rescan"));
+ scanAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.rescan.tooltip"));
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ actionScan();
+ this.wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
+ this.wizard.setNextName(I18n.getMessage("jsite.project-files.insert-now"));
+ this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
+ }
+
+ /**
+ * Creates the panel contains the project file list and options.
+ *
+ * @return The created panel
+ */
+ private JComponent createProjectFilesPanel() {
+ JPanel projectFilesPanel = new JPanel(new BorderLayout(12, 12));
+
+ projectFileList = new JList();
+ projectFileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ projectFileList.setMinimumSize(new Dimension(250, projectFileList.getPreferredSize().height));
+ projectFileList.addListSelectionListener(this);
+
+ projectFilesPanel.add(new JScrollPane(projectFileList), BorderLayout.CENTER);
+
+ JPanel fileOptionsAlignmentPanel = new JPanel(new BorderLayout(12, 12));
+ projectFilesPanel.add(fileOptionsAlignmentPanel, BorderLayout.PAGE_END);
+ JPanel fileOptionsPanel = new JPanel(new GridBagLayout());
+ fileOptionsAlignmentPanel.add(fileOptionsPanel, BorderLayout.PAGE_START);
+
+ ignoreHiddenFilesCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.ignore-hidden-files"));
+ ignoreHiddenFilesCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.ignore-hidden-files.tooltip"));
+ ignoreHiddenFilesCheckBox.setName("ignore-hidden-files");
+ ignoreHiddenFilesCheckBox.addActionListener(this);
+ fileOptionsPanel.add(ignoreHiddenFilesCheckBox, new GridBagConstraints(0, 0, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+
+ fileOptionsPanel.add(new JButton(scanAction), new GridBagConstraints(0, 1, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
+
+ final JLabel fileOptionsLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project-files.file-options") + "</b></html>");
+ fileOptionsPanel.add(fileOptionsLabel, new GridBagConstraints(0, 2, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
+
+ defaultFileCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.default"));
+ defaultFileCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.default.tooltip"));
+ defaultFileCheckBox.setName("default-file");
+ defaultFileCheckBox.addActionListener(this);
+ defaultFileCheckBox.setEnabled(false);
+
+ fileOptionsPanel.add(defaultFileCheckBox, new GridBagConstraints(0, 3, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+
+ fileOptionsInsertCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.insert"), true);
+ fileOptionsInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert.tooltip"));
+ fileOptionsInsertCheckBox.setName("insert");
+ fileOptionsInsertCheckBox.setMnemonic(KeyEvent.VK_I);
+ fileOptionsInsertCheckBox.addActionListener(this);
+ fileOptionsInsertCheckBox.setEnabled(false);
+
+ fileOptionsPanel.add(fileOptionsInsertCheckBox, new GridBagConstraints(0, 4, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+
+ fileOptionsForceInsertCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.force-insert"));
+ fileOptionsForceInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.force-insert.tooltip"));
+ fileOptionsForceInsertCheckBox.setName("force-insert");
+ fileOptionsForceInsertCheckBox.setMnemonic(KeyEvent.VK_F);
+ fileOptionsForceInsertCheckBox.addActionListener(this);
+ fileOptionsForceInsertCheckBox.setEnabled(false);
+
+ fileOptionsPanel.add(fileOptionsForceInsertCheckBox, new GridBagConstraints(0, 5, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+
+ fileOptionsCustomKeyTextField = new JTextField(45);
+ fileOptionsCustomKeyTextField.setToolTipText(I18n.getMessage("jsite.project-files.custom-key.tooltip"));
+ fileOptionsCustomKeyTextField.setEnabled(false);
+ fileOptionsCustomKeyTextField.getDocument().addDocumentListener(this);
+
+ fileOptionsInsertRedirectCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.insert-redirect"), false);
+ fileOptionsInsertRedirectCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert-redirect.tooltip"));
+ fileOptionsInsertRedirectCheckBox.setName("insert-redirect");
+ fileOptionsInsertRedirectCheckBox.setMnemonic(KeyEvent.VK_R);
+ fileOptionsInsertRedirectCheckBox.addActionListener(this);
+ fileOptionsInsertRedirectCheckBox.setEnabled(false);
+
+ final TLabel customKeyLabel = new TLabel(I18n.getMessage("jsite.project-files.custom-key") + ":", KeyEvent.VK_K, fileOptionsCustomKeyTextField);
+ fileOptionsPanel.add(fileOptionsInsertRedirectCheckBox, new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ fileOptionsPanel.add(customKeyLabel, new GridBagConstraints(1, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0));
+ fileOptionsPanel.add(fileOptionsCustomKeyTextField, new GridBagConstraints(2, 6, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ fileOptionsRenameCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.rename"), false);
+ fileOptionsRenameCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.rename.tooltip"));
+ fileOptionsRenameCheckBox.setName("rename");
+ fileOptionsRenameCheckBox.setMnemonic(KeyEvent.VK_N);
+ fileOptionsRenameCheckBox.addActionListener(this);
+ fileOptionsRenameCheckBox.setEnabled(false);
+
+ fileOptionsRenameTextField = new JTextField();
+ fileOptionsRenameTextField.setEnabled(false);
+ fileOptionsRenameTextField.getDocument().addDocumentListener(new DocumentListener() {
+
+ @SuppressWarnings("synthetic-access")
+ private void storeText(DocumentEvent documentEvent) {
+ FileOption fileOption = getSelectedFile();
+ if (fileOption == null) {
+ /* no file selected. */
+ return;
+ }
+ Document document = documentEvent.getDocument();
+ int documentLength = document.getLength();
+ try {
+ fileOption.setChangedName(document.getText(0, documentLength).trim());
+ } catch (BadLocationException ble1) {
+ /* ignore, it should never happen. */
+ }
+ }
+
+ public void changedUpdate(DocumentEvent documentEvent) {
+ storeText(documentEvent);
+ }
+
+ public void insertUpdate(DocumentEvent documentEvent) {
+ storeText(documentEvent);
+ }
+
+ public void removeUpdate(DocumentEvent documentEvent) {
+ storeText(documentEvent);
+ }
+
+ });
+
+ fileOptionsPanel.add(fileOptionsRenameCheckBox, new GridBagConstraints(0, 7, 2, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ fileOptionsPanel.add(fileOptionsRenameTextField, new GridBagConstraints(2, 7, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ fileOptionsMIMETypeComboBox = new JComboBox(DefaultMIMETypes.getAllMIMETypes());
+ fileOptionsMIMETypeComboBox.setToolTipText(I18n.getMessage("jsite.project-files.mime-type.tooltip"));
+ fileOptionsMIMETypeComboBox.setName("project-files.mime-type");
+ fileOptionsMIMETypeComboBox.addActionListener(this);
+ fileOptionsMIMETypeComboBox.setEditable(true);
+ fileOptionsMIMETypeComboBox.setEnabled(false);
+
+ final TLabel mimeTypeLabel = new TLabel(I18n.getMessage("jsite.project-files.mime-type") + ":", KeyEvent.VK_M, fileOptionsMIMETypeComboBox);
+ fileOptionsPanel.add(mimeTypeLabel, new GridBagConstraints(0, 8, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ fileOptionsPanel.add(fileOptionsMIMETypeComboBox, new GridBagConstraints(1, 8, 4, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ ignoreHiddenFilesCheckBox.setText(I18n.getMessage("jsite.project-files.ignore-hidden-files"));
+ ignoreHiddenFilesCheckBox.setToolTipText(I18n.getMessage("jsite.projet-files.ignore-hidden-files.tooltip"));
+ fileOptionsLabel.setText("<html><b>" + I18n.getMessage("jsite.project-files.file-options") + "</b></html>");
+ defaultFileCheckBox.setText(I18n.getMessage("jsite.project-files.default"));
+ defaultFileCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.default.tooltip"));
+ fileOptionsInsertCheckBox.setText(I18n.getMessage("jsite.project-files.insert"));
+ fileOptionsInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert.tooltip"));
+ fileOptionsForceInsertCheckBox.setText(I18n.getMessage("jsite.project-files.force-insert"));
+ fileOptionsForceInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.force-insert.tooltip"));
+ fileOptionsInsertRedirectCheckBox.setText(I18n.getMessage("jsite.project-files.insert-redirect"));
+ fileOptionsInsertRedirectCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert-redirect.tooltip"));
+ fileOptionsCustomKeyTextField.setToolTipText(I18n.getMessage("jsite.project-files.custom-key.tooltip"));
+ customKeyLabel.setText(I18n.getMessage("jsite.project-files.custom-key") + ":");
+ fileOptionsRenameCheckBox.setText("jsite.project-files.rename");
+ fileOptionsRenameCheckBox.setToolTipText("jsite.project-files.rename.tooltip");
+ fileOptionsMIMETypeComboBox.setToolTipText(I18n.getMessage("jsite.project-files.mime-type.tooltip"));
+ mimeTypeLabel.setText(I18n.getMessage("jsite.project-files.mime-type") + ":");
+ }
+ });
+
+ return projectFilesPanel;
+ }
+
+ /**
+ * Sets the project whose files to manage.
+ *
+ * @param project
+ * The project whose files to manage
+ */
+ public void setProject(final Project project) {
+ this.project = project;
+ setHeading(MessageFormat.format(I18n.getMessage("jsite.project-files.heading"), project.getName()));
+ setDescription(I18n.getMessage("jsite.project-files.description"));
+ ignoreHiddenFilesCheckBox.setSelected(project.isIgnoreHiddenFiles());
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ setHeading(MessageFormat.format(I18n.getMessage("jsite.project-files.heading"), project.getName()));
+ setDescription(I18n.getMessage("jsite.project-files.description"));
+ }
+ });
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Rescans the project’s files.
+ */
+ private void actionScan() {
+ projectFileList.clearSelection();
+ projectFileList.setListData(new Object[0]);
+
+ wizard.setNextEnabled(false);
+ wizard.setPreviousEnabled(false);
+ wizard.setQuitEnabled(false);
+
+ FileScanner fileScanner = new FileScanner(project);
+ fileScanner.addFileScannerListener(this);
+ new Thread(fileScanner).start();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Updates the file list.
+ */
+ public void fileScannerFinished(FileScanner fileScanner) {
+ final boolean error = fileScanner.isError();
+ if (!error) {
+ final List<ScannedFile> files = fileScanner.getFiles();
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ projectFileList.setListData(files.toArray());
+ projectFileList.clearSelection();
+ }
+ });
+ Set<String> entriesToRemove = new HashSet<String>();
+ Iterator<String> filenames = new HashSet<String>(project.getFileOptions().keySet()).iterator();
+ while (filenames.hasNext()) {
+ String filename = filenames.next();
+ boolean found = false;
+ for (ScannedFile scannedFile : files) {
+ if (scannedFile.getFilename().equals(filename)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ entriesToRemove.add(filename);
+ }
+ }
+ for (String filename : entriesToRemove) {
+ project.setFileOption(filename, null);
+ }
+ } else {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.scan-error"), null, JOptionPane.ERROR_MESSAGE);
+ }
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ wizard.setPreviousEnabled(true);
+ wizard.setNextEnabled(!error);
+ wizard.setQuitEnabled(true);
+ }
+ });
+ }
+
+ /**
+ * Returns the {@link FileOption file options} for the currently selected
+ * file.
+ *
+ * @return The {@link FileOption}s for the selected file, or {@code null} if
+ * no file is selected
+ */
+ private FileOption getSelectedFile() {
+ ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
+ if (scannedFile == null) {
+ return null;
+ }
+ return project.getFileOption(scannedFile.getFilename());
+ }
+
+ //
+ // INTERFACE ActionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void actionPerformed(ActionEvent actionEvent) {
+ Object source = actionEvent.getSource();
+ if ((source instanceof JCheckBox) && ("ignore-hidden-files".equals(((JCheckBox) source).getName()))) {
+ project.setIgnoreHiddenFiles(((JCheckBox) source).isSelected());
+ actionScan();
+ return;
+ }
+ ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
+ if (scannedFile == null) {
+ return;
+ }
+ String filename = scannedFile.getFilename();
+ FileOption fileOption = project.getFileOption(filename);
+ if (source instanceof JCheckBox) {
+ JCheckBox checkBox = (JCheckBox) source;
+ if ("default-file".equals(checkBox.getName())) {
+ if (checkBox.isSelected()) {
+ if (filename.indexOf('/') > -1) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.invalid-default-file"), null, JOptionPane.ERROR_MESSAGE);
+ checkBox.setSelected(false);
+ } else {
+ project.setIndexFile(filename);
+ }
+ } else {
+ if (filename.equals(project.getIndexFile())) {
+ project.setIndexFile(null);
+ }
+ }
+ } else if ("insert".equals(checkBox.getName())) {
+ boolean isInsert = checkBox.isSelected();
+ fileOption.setInsert(isInsert);
+ fileOptionsInsertRedirectCheckBox.setEnabled(!isInsert);
+ } else if ("force-insert".equals(checkBox.getName())) {
+ boolean isForceInsert = checkBox.isSelected();
+ fileOption.setForceInsert(isForceInsert);
+ } else if ("insert-redirect".equals(checkBox.getName())) {
+ boolean isInsertRedirect = checkBox.isSelected();
+ fileOption.setInsertRedirect(isInsertRedirect);
+ fileOptionsCustomKeyTextField.setEnabled(isInsertRedirect);
+ } else if ("rename".equals(checkBox.getName())) {
+ boolean isRenamed = checkBox.isSelected();
+ fileOptionsRenameTextField.setEnabled(isRenamed);
+ fileOption.setChangedName(isRenamed ? fileOptionsRenameTextField.getText() : "");
+ }
+ } else if (source instanceof JComboBox) {
+ JComboBox comboBox = (JComboBox) source;
+ if ("project-files.mime-type".equals(comboBox.getName())) {
+ fileOption.setMimeType((String) comboBox.getSelectedItem());
+ }
+ }
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("null")
+ public void valueChanged(ListSelectionEvent e) {
+ ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
+ boolean enabled = scannedFile != null;
+ String filename = (scannedFile == null) ? null : scannedFile.getFilename();
+ defaultFileCheckBox.setEnabled(enabled);
+ fileOptionsInsertCheckBox.setEnabled(enabled);
+ fileOptionsRenameCheckBox.setEnabled(enabled);
+ fileOptionsMIMETypeComboBox.setEnabled(enabled);
+ if (filename != null) {
+ FileOption fileOption = project.getFileOption(filename);
+ defaultFileCheckBox.setSelected(filename.equals(project.getIndexFile()));
+ fileOptionsInsertCheckBox.setSelected(fileOption.isInsert());
+ fileOptionsForceInsertCheckBox.setEnabled(scannedFile.getHash().equals(fileOption.getLastInsertHash()));
+ fileOptionsForceInsertCheckBox.setSelected(fileOption.isForceInsert());
+ fileOptionsInsertRedirectCheckBox.setEnabled(!fileOption.isInsert());
+ fileOptionsInsertRedirectCheckBox.setSelected(fileOption.isInsertRedirect());
+ fileOptionsCustomKeyTextField.setEnabled(fileOption.isInsertRedirect());
+ fileOptionsCustomKeyTextField.setText(fileOption.getCustomKey());
+ fileOptionsRenameCheckBox.setSelected(fileOption.hasChangedName());
+ fileOptionsRenameTextField.setEnabled(fileOption.hasChangedName());
+ fileOptionsRenameTextField.setText(fileOption.getChangedName());
+ fileOptionsMIMETypeComboBox.getModel().setSelectedItem(fileOption.getMimeType());
+ } else {
+ defaultFileCheckBox.setSelected(false);
+ fileOptionsInsertCheckBox.setSelected(true);
+ fileOptionsForceInsertCheckBox.setEnabled(false);
+ fileOptionsForceInsertCheckBox.setSelected(false);
+ fileOptionsInsertRedirectCheckBox.setEnabled(false);
+ fileOptionsInsertRedirectCheckBox.setSelected(false);
+ fileOptionsCustomKeyTextField.setEnabled(false);
+ fileOptionsCustomKeyTextField.setText("CHK@");
+ fileOptionsRenameCheckBox.setEnabled(false);
+ fileOptionsRenameCheckBox.setSelected(false);
+ fileOptionsRenameTextField.setEnabled(false);
+ fileOptionsRenameTextField.setText("");
+ fileOptionsMIMETypeComboBox.getModel().setSelectedItem(DefaultMIMETypes.DEFAULT_MIME_TYPE);
+ }
+ }
+
+ //
+ // INTERFACE DocumentListener
+ //
+
+ /**
+ * Updates the options of the currently selected file with the changes made
+ * in the “custom key” textfield.
+ *
+ * @param documentEvent
+ * The document event to process
+ */
+ private void processDocumentUpdate(DocumentEvent documentEvent) {
+ ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
+ if (scannedFile == null) {
+ return;
+ }
+ FileOption fileOption = project.getFileOption(scannedFile.getFilename());
+ Document document = documentEvent.getDocument();
+ try {
+ String text = document.getText(0, document.getLength());
+ fileOption.setCustomKey(text);
+ } catch (BadLocationException ble1) {
+ /* ignore. */
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changedUpdate(DocumentEvent documentEvent) {
+ processDocumentUpdate(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void insertUpdate(DocumentEvent documentEvent) {
+ processDocumentUpdate(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeUpdate(DocumentEvent documentEvent) {
+ processDocumentUpdate(documentEvent);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ProjectInsertPage.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import de.todesbaum.jsite.application.AbortedException;
+import de.todesbaum.jsite.application.Freenet7Interface;
+import de.todesbaum.jsite.application.InsertListener;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.application.ProjectInserter;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.jsite.i18n.I18nContainer;
+import de.todesbaum.util.freenet.fcp2.ClientPutDir.ManifestPutter;
+import de.todesbaum.util.freenet.fcp2.PriorityClass;
+import de.todesbaum.util.io.StreamCopier.ProgressListener;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * Wizard page that shows the progress of an insert.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class ProjectInsertPage extends TWizardPage implements InsertListener, ClipboardOwner {
+
+ /** The logger. */
+ private static final Logger logger = Logger.getLogger(ProjectInsertPage.class.getName());
+
+ /** The project inserter. */
+ private ProjectInserter projectInserter;
+
+ /** The “copy URI” action. */
+ private Action copyURIAction;
+
+ /** The “request URI” textfield. */
+ private JTextField requestURITextField;
+
+ /** The “start time” label. */
+ private JLabel startTimeLabel;
+
+ /** The progress bar. */
+ private JProgressBar progressBar;
+
+ /** The start time of the insert. */
+ private long startTime = 0;
+
+ /** The number of inserted blocks. */
+ private volatile int insertedBlocks;
+
+ /** Whether the “copy URI to clipboard” button was used. */
+ private boolean uriCopied;
+
+ /** Whether the insert is currently running. */
+ private volatile boolean running = false;
+
+ /**
+ * Creates a new progress insert wizard page.
+ *
+ * @param wizard
+ * The wizard this page belongs to
+ */
+ public ProjectInsertPage(final TWizard wizard) {
+ super(wizard);
+ createActions();
+ pageInit();
+ setHeading(I18n.getMessage("jsite.insert.heading"));
+ setDescription(I18n.getMessage("jsite.insert.description"));
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ setHeading(I18n.getMessage("jsite.insert.heading"));
+ setDescription(I18n.getMessage("jsite.insert.description"));
+ }
+ });
+ projectInserter = new ProjectInserter();
+ projectInserter.addInsertListener(this);
+ }
+
+ /**
+ * Creates all used actions.
+ */
+ private void createActions() {
+ copyURIAction = new AbstractAction(I18n.getMessage("jsite.project.action.copy-uri")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionCopyURI();
+ }
+ };
+ copyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
+ copyURIAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_U);
+ copyURIAction.setEnabled(false);
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ copyURIAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.copy-uri"));
+ copyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
+ }
+ });
+ }
+
+ /**
+ * Initializes the page.
+ */
+ private void pageInit() {
+ setLayout(new BorderLayout(12, 12));
+ add(createProjectInsertPanel(), BorderLayout.CENTER);
+ }
+
+ /**
+ * Creates the main panel.
+ *
+ * @return The main panel
+ */
+ private JComponent createProjectInsertPanel() {
+ JComponent projectInsertPanel = new JPanel(new GridBagLayout());
+
+ requestURITextField = new JTextField();
+ requestURITextField.setEditable(false);
+
+ startTimeLabel = new JLabel();
+
+ progressBar = new JProgressBar(0, 1);
+ progressBar.setStringPainted(true);
+ progressBar.setValue(0);
+
+ final JLabel projectInformationLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.insert.project-information") + "</b></html>");
+ projectInsertPanel.add(projectInformationLabel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ final JLabel requestURILabel = new JLabel(I18n.getMessage("jsite.insert.request-uri") + ":");
+ projectInsertPanel.add(requestURILabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+ projectInsertPanel.add(requestURITextField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ final JLabel startTimeLeftLabel = new JLabel(I18n.getMessage("jsite.insert.start-time") + ":");
+ projectInsertPanel.add(startTimeLeftLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+ projectInsertPanel.add(startTimeLabel, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ final JLabel progressLabel = new JLabel(I18n.getMessage("jsite.insert.progress") + ":");
+ projectInsertPanel.add(progressLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+ projectInsertPanel.add(progressBar, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ projectInsertPanel.add(new JButton(copyURIAction), new GridBagConstraints(0, 4, 2, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0));
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ projectInformationLabel.setText("<html><b>" + I18n.getMessage("jsite.insert.project-information") + "</b></html>");
+ requestURILabel.setText(I18n.getMessage("jsite.insert.request-uri") + ":");
+ startTimeLeftLabel.setText(I18n.getMessage("jsite.insert.start-time") + ":");
+ if (startTime != 0) {
+ startTimeLabel.setText(DateFormat.getDateTimeInstance().format(new Date(startTime)));
+ } else {
+ startTimeLabel.setText("");
+ }
+ progressLabel.setText(I18n.getMessage("jsite.insert.progress") + ":");
+ }
+ });
+
+ return projectInsertPanel;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ this.wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
+ this.wizard.setPreviousEnabled(false);
+ this.wizard.setNextName(I18n.getMessage("jsite.general.cancel"));
+ this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
+ }
+
+ /**
+ * Starts the insert.
+ */
+ public void startInsert() {
+ running = true;
+ copyURIAction.setEnabled(false);
+ progressBar.setValue(0);
+ progressBar.setString(I18n.getMessage("jsite.insert.starting"));
+ progressBar.setFont(progressBar.getFont().deriveFont(Font.PLAIN));
+ projectInserter.start(new ProgressListener() {
+
+ public void onProgress(final long copied, final long length) {
+ SwingUtilities.invokeLater(new Runnable() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ int divisor = 1;
+ while (((copied / divisor) > Integer.MAX_VALUE) || ((length / divisor) > Integer.MAX_VALUE)) {
+ divisor *= 10;
+ }
+ progressBar.setMaximum((int) (length / divisor));
+ progressBar.setValue((int) (copied / divisor));
+ progressBar.setString("Uploaded: " + copied + " / " + length);
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Stops the currently running insert.
+ */
+ public void stopInsert() {
+ if (running) {
+ wizard.setNextEnabled(false);
+ projectInserter.stop();
+ }
+ }
+
+ /**
+ * Returns whether the insert is currently running.
+ *
+ * @return {@code true} if the insert is currently running, {@code false}
+ * otherwise
+ */
+ public boolean isRunning() {
+ return running;
+ }
+
+ /**
+ * Sets the project to insert.
+ *
+ * @param project
+ * The project to insert
+ */
+ public void setProject(final Project project) {
+ projectInserter.setProject(project);
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ requestURITextField.setText(project.getFinalRequestURI(1));
+ }
+ });
+ }
+
+ /**
+ * Sets the freenet interface to use.
+ *
+ * @param freenetInterface
+ * The freenet interface to use
+ */
+ public void setFreenetInterface(Freenet7Interface freenetInterface) {
+ projectInserter.setFreenetInterface(freenetInterface);
+ }
+
+ /**
+ * Sets the project inserter’s temp directory.
+ *
+ * @see ProjectInserter#setTempDirectory(String)
+ * @param tempDirectory
+ * The temp directory to use, or {@code null} to use the system
+ * default
+ */
+ public void setTempDirectory(String tempDirectory) {
+ projectInserter.setTempDirectory(tempDirectory);
+ }
+
+ /**
+ * Returns whether the “copy URI to clipboard” button was used.
+ *
+ * @return {@code true} if an URI was copied to clipboard, {@code false}
+ * otherwise
+ */
+ public boolean wasUriCopied() {
+ return uriCopied;
+ }
+
+ /**
+ * Sets whether to use the “early encode“ flag for the insert.
+ *
+ * @param useEarlyEncode
+ * {@code true} to set the “early encode” flag for the insert,
+ * {@code false} otherwise
+ */
+ public void setUseEarlyEncode(boolean useEarlyEncode) {
+ projectInserter.setUseEarlyEncode(useEarlyEncode);
+ }
+
+ /**
+ * Sets the insert priority.
+ *
+ * @param priority
+ * The insert priority
+ */
+ public void setPriority(PriorityClass priority) {
+ projectInserter.setPriority(priority);
+ }
+
+ /**
+ * Sets the manifest putter to use for the insert.
+ *
+ * @see ProjectInserter#setManifestPutter(ManifestPutter)
+ * @param manifestPutter
+ * The manifest putter
+ */
+ public void setManifestPutter(ManifestPutter manifestPutter) {
+ projectInserter.setManifestPutter(manifestPutter);
+ }
+
+ //
+ // INTERFACE InsertListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertStarted(final Project project) {
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ startTimeLabel.setText(DateFormat.getDateTimeInstance().format(new Date()));
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectUploadFinished(Project project) {
+ startTime = System.currentTimeMillis();
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ progressBar.setString(I18n.getMessage("jsite.insert.starting"));
+ progressBar.setValue(0);
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectURIGenerated(Project project, final String uri) {
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ copyURIAction.setEnabled(true);
+ requestURITextField.setText(uri);
+ }
+ });
+ logger.log(Level.FINEST, "Insert generated URI: " + uri);
+ int slash = uri.indexOf('/');
+ slash = uri.indexOf('/', slash + 1);
+ int secondSlash = uri.indexOf('/', slash + 1);
+ if (secondSlash == -1) {
+ secondSlash = uri.length();
+ }
+ String editionNumber = uri.substring(slash + 1, secondSlash);
+ logger.log(Level.FINEST, "Extracted edition number: " + editionNumber);
+ int edition = -1;
+ try {
+ edition = Integer.valueOf(editionNumber);
+ } catch (NumberFormatException nfe1) {
+ /* ignore. */
+ }
+ logger.log(Level.FINEST, "Insert edition: " + edition + ", Project edition: " + project.getEdition());
+ if ((edition != -1) && (edition == project.getEdition())) {
+ JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.reinserted-edition"), I18n.getMessage("jsite.insert.reinserted-edition.title"), JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertProgress(Project project, final int succeeded, final int failed, final int fatal, final int total, final boolean finalized) {
+ insertedBlocks = succeeded;
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ if (total == 0) {
+ return;
+ }
+ progressBar.setMaximum(total);
+ progressBar.setValue(succeeded + failed + fatal);
+ int progress = (succeeded + failed + fatal) * 100 / total;
+ StringBuilder progressString = new StringBuilder();
+ progressString.append(progress).append("% (");
+ progressString.append(succeeded + failed + fatal).append('/').append(total);
+ progressString.append(") (");
+ progressString.append(getTransferRate());
+ progressString.append(' ').append(I18n.getMessage("jsite.insert.k-per-s")).append(')');
+ progressBar.setString(progressString.toString());
+ if (finalized) {
+ progressBar.setFont(progressBar.getFont().deriveFont(Font.BOLD));
+ }
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertFinished(Project project, boolean success, Throwable cause) {
+ running = false;
+ if (success) {
+ String copyURILabel = I18n.getMessage("jsite.insert.okay-copy-uri");
+ int selectedValue = JOptionPane.showOptionDialog(this, I18n.getMessage("jsite.insert.inserted"), I18n.getMessage("jsite.insert.done.title"), 0, JOptionPane.INFORMATION_MESSAGE, null, new Object[] { I18n.getMessage("jsite.general.ok"), copyURILabel }, copyURILabel);
+ if (selectedValue == 1) {
+ actionCopyURI();
+ }
+ } else {
+ if (cause == null) {
+ JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.insert-failed"), I18n.getMessage("jsite.insert.insert-failed.title"), JOptionPane.ERROR_MESSAGE);
+ } else {
+ if (cause instanceof AbortedException) {
+ JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.insert-aborted"), I18n.getMessage("jsite.insert.insert-aborted.title"), JOptionPane.INFORMATION_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.insert.insert-failed-with-cause"), cause.getMessage()), I18n.getMessage("jsite.insert.insert-failed.title"), JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ progressBar.setValue(progressBar.getMaximum());
+ progressBar.setString(I18n.getMessage("jsite.insert.done") + " (" + getTransferRate() + " " + I18n.getMessage("jsite.insert.k-per-s") + ")");
+ wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
+ wizard.setNextEnabled(true);
+ wizard.setQuitEnabled(true);
+ }
+ });
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Copies the request URI of the project to the clipboard.
+ */
+ private void actionCopyURI() {
+ uriCopied = true;
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ clipboard.setContents(new StringSelection(requestURITextField.getText()), this);
+ }
+
+ /**
+ * Formats the given number so that it always has the the given number of
+ * fractional digits.
+ *
+ * @param number
+ * The number to format
+ * @param digits
+ * The number of fractional digits
+ * @return The formatted number
+ */
+ private String formatNumber(double number, int digits) {
+ int multiplier = (int) Math.pow(10, digits);
+ String formattedNumber = String.valueOf((int) (number * multiplier) / (double) multiplier);
+ if (formattedNumber.indexOf('.') == -1) {
+ formattedNumber += '.';
+ for (int digit = 0; digit < digits; digit++) {
+ formattedNumber += "0";
+ }
+ }
+ return formattedNumber;
+ }
+
+ /**
+ * Returns the formatted transfer rate at this point.
+ *
+ * @return The formatted transfer rate
+ */
+ private String getTransferRate() {
+ return formatNumber(insertedBlocks * 32.0 / ((System.currentTimeMillis() - startTime) / 1000), 1);
+ }
+
+ //
+ // INTERFACE ClipboardOwner
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ /* ignore. */
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ProjectPage.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.DocumentFilter;
+
+import de.todesbaum.jsite.application.Freenet7Interface;
+import de.todesbaum.jsite.application.KeyDialog;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.i18n.I18n;
+import de.todesbaum.jsite.i18n.I18nContainer;
+import de.todesbaum.util.swing.SortedListModel;
+import de.todesbaum.util.swing.TLabel;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+
+/**
+ * Wizard page that lets the user manage his projects and start inserts.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class ProjectPage extends TWizardPage implements ListSelectionListener, DocumentListener, ClipboardOwner {
+
+ /** The freenet interface. */
+ private Freenet7Interface freenetInterface;
+
+ /** The “browse” action. */
+ private Action projectLocalPathBrowseAction;
+
+ /** The “add project” action. */
+ private Action projectAddAction;
+
+ /** The “delete project” action. */
+ private Action projectDeleteAction;
+
+ /** The “clone project” action. */
+ private Action projectCloneAction;
+
+ /** The “manage keys” action. */
+ private Action projectManageKeysAction;
+
+ /** The “copy URI” action. */
+ private Action projectCopyURIAction;
+
+ /** The “reset edition” action. */
+ private Action projectResetEditionAction;
+
+ /** The file chooser. */
+ private JFileChooser pathChooser;
+
+ /** The project list model. */
+ private SortedListModel<Project> projectListModel;
+
+ /** The project list scroll pane. */
+ private JScrollPane projectScrollPane;
+
+ /** The project list. */
+ private JList projectList;
+
+ /** The project name textfield. */
+ private JTextField projectNameTextField;
+
+ /** The project description textfield. */
+ private JTextField projectDescriptionTextField;
+
+ /** The local path textfield. */
+ private JTextField projectLocalPathTextField;
+
+ /** The textfield for the complete URI. */
+ private JTextField projectCompleteUriTextField;
+
+ /** The project path textfield. */
+ private JTextField projectPathTextField;
+
+ /** Whether the “copy URI to clipboard” action was used. */
+ private boolean uriCopied;
+
+ /**
+ * Creates a new project page.
+ *
+ * @param wizard
+ * The wizard this page belongs to
+ */
+ public ProjectPage(final TWizard wizard) {
+ super(wizard);
+ setLayout(new BorderLayout(12, 12));
+ dialogInit();
+ setHeading(I18n.getMessage("jsite.project.heading"));
+ setDescription(I18n.getMessage("jsite.project.description"));
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ setHeading(I18n.getMessage("jsite.project.heading"));
+ setDescription(I18n.getMessage("jsite.project.description"));
+ }
+ });
+ }
+
+ /**
+ * Initializes the page.
+ */
+ private void dialogInit() {
+ createActions();
+
+ pathChooser = new JFileChooser();
+ projectListModel = new SortedListModel<Project>();
+ projectList = new JList(projectListModel);
+ projectList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ projectList.addListSelectionListener(this);
+
+ add(projectScrollPane = new JScrollPane(projectList), BorderLayout.LINE_START);
+ projectScrollPane.setPreferredSize(new Dimension(150, projectList.getPreferredSize().height));
+ add(createInformationPanel(), BorderLayout.CENTER);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAdded(TWizard wizard) {
+ super.pageAdded(wizard);
+ projectList.clearSelection();
+ this.wizard.setPreviousName(I18n.getMessage("jsite.menu.nodes.manage-nodes"));
+ this.wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
+ this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
+ this.wizard.setNextEnabled(false);
+ }
+
+ /**
+ * Adds the given listener to the list of listeners.
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addListSelectionListener(ListSelectionListener listener) {
+ projectList.addListSelectionListener(listener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners.
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeListSelectionListener(ListSelectionListener listener) {
+ projectList.removeListSelectionListener(listener);
+ }
+
+ /**
+ * Creates all actions.
+ */
+ private void createActions() {
+ projectLocalPathBrowseAction = new AbstractAction(I18n.getMessage("jsite.project.action.browse")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionLocalPathBrowse();
+ }
+ };
+ projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip"));
+ projectLocalPathBrowseAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_B);
+ projectLocalPathBrowseAction.setEnabled(false);
+
+ projectAddAction = new AbstractAction(I18n.getMessage("jsite.project.action.add-project")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionAdd();
+ }
+ };
+ projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip"));
+ projectAddAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
+
+ projectDeleteAction = new AbstractAction(I18n.getMessage("jsite.project.action.delete-project")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionDelete();
+ }
+ };
+ projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip"));
+ projectDeleteAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
+ projectDeleteAction.setEnabled(false);
+
+ projectCloneAction = new AbstractAction(I18n.getMessage("jsite.project.action.clone-project")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionClone();
+ }
+ };
+ projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip"));
+ projectCloneAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_L);
+ projectCloneAction.setEnabled(false);
+
+ projectCopyURIAction = new AbstractAction(I18n.getMessage("jsite.project.action.copy-uri")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionCopyURI();
+ }
+ };
+ projectCopyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
+ projectCopyURIAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_U);
+ projectCopyURIAction.setEnabled(false);
+
+ projectManageKeysAction = new AbstractAction(I18n.getMessage("jsite.project.action.manage-keys")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionManageKeys();
+ }
+ };
+ projectManageKeysAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.manage-keys.tooltip"));
+ projectManageKeysAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_M);
+ projectManageKeysAction.setEnabled(false);
+
+ projectResetEditionAction = new AbstractAction(I18n.getMessage("jsite.project.action.reset-edition")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionResetEdition();
+ }
+ };
+ projectResetEditionAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.reset-edition.tooltip"));
+ projectResetEditionAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_R);
+ projectResetEditionAction.setEnabled(false);
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ projectLocalPathBrowseAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.browse"));
+ projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip"));
+ projectAddAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.add-project"));
+ projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip"));
+ projectDeleteAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.delete-project"));
+ projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip"));
+ projectCloneAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.clone-project"));
+ projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip"));
+ projectCopyURIAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.copy-uri"));
+ projectCopyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
+ projectManageKeysAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.manage-keys"));
+ projectManageKeysAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.manage-keys.tooltip"));
+ projectResetEditionAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.reset-edition"));
+ projectResetEditionAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.reset-edition.tooltip"));
+ pathChooser.setApproveButtonText(I18n.getMessage("jsite.project.action.browse.choose"));
+ }
+ });
+ }
+
+ /**
+ * Creates the information panel.
+ *
+ * @return The information panel
+ */
+ private JComponent createInformationPanel() {
+ JPanel informationPanel = new JPanel(new BorderLayout(12, 12));
+
+ JPanel informationTable = new JPanel(new GridBagLayout());
+
+ JPanel functionButtons = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
+ functionButtons.setBorder(new EmptyBorder(-12, -12, -12, -12));
+ functionButtons.add(new JButton(projectAddAction));
+ functionButtons.add(new JButton(projectDeleteAction));
+ functionButtons.add(new JButton(projectCloneAction));
+ functionButtons.add(new JButton(projectManageKeysAction));
+
+ informationPanel.add(functionButtons, BorderLayout.PAGE_START);
+ informationPanel.add(informationTable, BorderLayout.CENTER);
+
+ final JLabel projectInformationLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.information") + "</b></html>");
+ informationTable.add(projectInformationLabel, new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+
+ projectNameTextField = new JTextField();
+ projectNameTextField.getDocument().putProperty("name", "project.name");
+ projectNameTextField.getDocument().addDocumentListener(this);
+ projectNameTextField.setEnabled(false);
+
+ final TLabel projectNameLabel = new TLabel(I18n.getMessage("jsite.project.project.name") + ":", KeyEvent.VK_N, projectNameTextField);
+ informationTable.add(projectNameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectNameTextField, new GridBagConstraints(1, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectDescriptionTextField = new JTextField();
+ projectDescriptionTextField.getDocument().putProperty("name", "project.description");
+ projectDescriptionTextField.getDocument().addDocumentListener(this);
+ projectDescriptionTextField.setEnabled(false);
+
+ final TLabel projectDescriptionLabel = new TLabel(I18n.getMessage("jsite.project.project.description") + ":", KeyEvent.VK_D, projectDescriptionTextField);
+ informationTable.add(projectDescriptionLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectDescriptionTextField, new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectLocalPathTextField = new JTextField();
+ projectLocalPathTextField.getDocument().putProperty("name", "project.localpath");
+ projectLocalPathTextField.getDocument().addDocumentListener(this);
+ projectLocalPathTextField.setEnabled(false);
+
+ final TLabel projectLocalPathLabel = new TLabel(I18n.getMessage("jsite.project.project.local-path") + ":", KeyEvent.VK_L, projectLocalPathTextField);
+ informationTable.add(projectLocalPathLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectLocalPathTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ informationTable.add(new JButton(projectLocalPathBrowseAction), new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ final JLabel projectAddressLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.address") + "</b></html>");
+ informationTable.add(projectAddressLabel, new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
+
+ projectPathTextField = new JTextField();
+ projectPathTextField.getDocument().putProperty("name", "project.path");
+ projectPathTextField.getDocument().addDocumentListener(this);
+ ((AbstractDocument) projectPathTextField.getDocument()).setDocumentFilter(new DocumentFilter() {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
+ super.insertString(fb, offset, string.replaceAll("/", ""), attr);
+ updateCompleteURI();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
+ super.replace(fb, offset, length, text.replaceAll("/", ""), attrs);
+ updateCompleteURI();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
+ super.remove(fb, offset, length);
+ updateCompleteURI();
+ }
+ });
+ projectPathTextField.setEnabled(false);
+
+ final TLabel projectPathLabel = new TLabel(I18n.getMessage("jsite.project.project.path") + ":", KeyEvent.VK_P, projectPathTextField);
+ informationTable.add(projectPathLabel, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectPathTextField, new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ projectCompleteUriTextField = new JTextField();
+ projectCompleteUriTextField.setEditable(false);
+ final TLabel projectUriLabel = new TLabel(I18n.getMessage("jsite.project.project.uri") + ":", KeyEvent.VK_U, projectCompleteUriTextField);
+ informationTable.add(projectUriLabel, new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
+ informationTable.add(projectCompleteUriTextField, new GridBagConstraints(1, 6, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ informationTable.add(new JButton(projectCopyURIAction), new GridBagConstraints(2, 6, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ public void run() {
+ projectInformationLabel.setText("<html><b>" + I18n.getMessage("jsite.project.project.information") + "</b></html>");
+ projectNameLabel.setText(I18n.getMessage("jsite.project.project.name") + ":");
+ projectDescriptionLabel.setText(I18n.getMessage("jsite.project.project.description") + ":");
+ projectLocalPathLabel.setText(I18n.getMessage("jsite.project.project.local-path") + ":");
+ projectAddressLabel.setText("<html><b>" + I18n.getMessage("jsite.project.project.address") + "</b></html>");
+ projectPathLabel.setText(I18n.getMessage("jsite.project.project.path") + ":");
+ projectUriLabel.setText(I18n.getMessage("jsite.project.project.uri") + ":");
+ }
+ });
+
+ return informationPanel;
+ }
+
+ /**
+ * Sets the project list.
+ *
+ * @param projects
+ * The list of projects
+ */
+ public void setProjects(Project[] projects) {
+ projectListModel.clear();
+ for (Project project : projects) {
+ projectListModel.add(project);
+ }
+ }
+
+ /**
+ * Returns the list of projects.
+ *
+ * @return The list of projects
+ */
+ public Project[] getProjects() {
+ return projectListModel.toArray(new Project[projectListModel.size()]);
+ }
+
+ /**
+ * Sets the freenet interface to use.
+ *
+ * @param freenetInterface
+ * The freenetInterface to use
+ */
+ public void setFreenetInterface(Freenet7Interface freenetInterface) {
+ this.freenetInterface = freenetInterface;
+ }
+
+ /**
+ * Returns the currently selected project.
+ *
+ * @return The currently selected project
+ */
+ public Project getSelectedProject() {
+ return (Project) projectList.getSelectedValue();
+ }
+
+ /**
+ * Returns whether the “copy URI to clipboard” button was used.
+ *
+ * @return {@code true} if the “copy URI to clipboard” button was used,
+ * {@code false} otherwise
+ */
+ public boolean wasUriCopied() {
+ return uriCopied;
+ }
+
+ /**
+ * Updates the currently selected project with changed information from a
+ * textfield.
+ *
+ * @param documentEvent
+ * The document event to process
+ */
+ private void setTextField(DocumentEvent documentEvent) {
+ Document document = documentEvent.getDocument();
+ String propertyName = (String) document.getProperty("name");
+ Project project = (Project) projectList.getSelectedValue();
+ if (project == null) {
+ return;
+ }
+ try {
+ String text = document.getText(0, document.getLength()).trim();
+ if ("project.name".equals(propertyName)) {
+ project.setName(text);
+ projectList.repaint();
+ } else if ("project.description".equals(propertyName)) {
+ project.setDescription(text);
+ } else if ("project.localpath".equals(propertyName)) {
+ project.setLocalPath(text);
+ } else if ("project.privatekey".equals(propertyName)) {
+ project.setInsertURI(text);
+ } else if ("project.publickey".equals(propertyName)) {
+ project.setRequestURI(text);
+ } else if ("project.path".equals(propertyName)) {
+ project.setPath(text);
+ }
+ } catch (BadLocationException e) {
+ /* ignore. */
+ }
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Lets the user choose a local path for a project.
+ */
+ private void actionLocalPathBrowse() {
+ Project project = (Project) projectList.getSelectedValue();
+ if (project == null) {
+ return;
+ }
+ pathChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ if (pathChooser.showDialog(this, I18n.getMessage("jsite.project.action.browse.choose")) == JFileChooser.APPROVE_OPTION) {
+ projectLocalPathTextField.setText(pathChooser.getSelectedFile().getPath());
+ }
+ }
+
+ /**
+ * Adds a new project.
+ */
+ private void actionAdd() {
+ String[] keyPair = null;
+ if (!freenetInterface.hasNode()) {
+ JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ try {
+ keyPair = freenetInterface.generateKeyPair();
+ } catch (IOException ioe1) {
+ JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ Project newProject = new Project();
+ newProject.setName(I18n.getMessage("jsite.project.new-project.name"));
+ newProject.setInsertURI(keyPair[0]);
+ newProject.setRequestURI(keyPair[1]);
+ newProject.setEdition(-1);
+ newProject.setPath("");
+ projectListModel.add(newProject);
+ projectScrollPane.revalidate();
+ projectScrollPane.repaint();
+ projectList.setSelectedIndex(projectListModel.indexOf(newProject));
+ }
+
+ /**
+ * Deletes the currently selected project.
+ */
+ private void actionDelete() {
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ if (JOptionPane.showConfirmDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.action.delete-project.confirm"), ((Project) projectList.getSelectedValue()).getName()), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
+ projectListModel.remove(selectedIndex);
+ projectList.clearSelection();
+ if (projectListModel.getSize() != 0) {
+ projectList.setSelectedIndex(Math.min(selectedIndex, projectListModel.getSize() - 1));
+ }
+ }
+ }
+ }
+
+ /**
+ * Clones the currently selected project.
+ */
+ private void actionClone() {
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ Project newProject = new Project((Project) projectList.getSelectedValue());
+ newProject.setName(MessageFormat.format(I18n.getMessage("jsite.project.action.clone-project.copy"), newProject.getName()));
+ projectListModel.add(newProject);
+ projectList.setSelectedIndex(projectListModel.indexOf(newProject));
+ }
+ }
+
+ /**
+ * Copies the request URI of the currently selected project to the
+ * clipboard.
+ */
+ private void actionCopyURI() {
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ Project selectedProject = (Project) projectList.getSelectedValue();
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ clipboard.setContents(new StringSelection(selectedProject.getFinalRequestURI(0)), this);
+ uriCopied = true;
+ }
+ }
+
+ /**
+ * Opens a {@link KeyDialog} and lets the user manipulate the keys of the
+ * project.
+ */
+ private void actionManageKeys() {
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ Project selectedProject = (Project) projectList.getSelectedValue();
+ KeyDialog keyDialog = new KeyDialog(freenetInterface, wizard);
+ keyDialog.setPrivateKey(selectedProject.getInsertURI());
+ keyDialog.setPublicKey(selectedProject.getRequestURI());
+ keyDialog.setVisible(true);
+ if (!keyDialog.wasCancelled()) {
+ String originalPublicKey = selectedProject.getRequestURI();
+ String originalPrivateKey = selectedProject.getInsertURI();
+ selectedProject.setInsertURI(keyDialog.getPrivateKey());
+ selectedProject.setRequestURI(keyDialog.getPublicKey());
+ if (!originalPublicKey.equals(selectedProject.getRequestURI()) || !originalPrivateKey.equals(selectedProject.getInsertURI())) {
+ selectedProject.setEdition(-1);
+ }
+ updateCompleteURI();
+ }
+ }
+ }
+
+ /**
+ * Resets the edition of the currently selected project.
+ */
+ private void actionResetEdition() {
+ if (JOptionPane.showConfirmDialog(this, I18n.getMessage("jsite.project.warning.reset-edition"), null, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
+ return;
+ }
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ Project selectedProject = (Project) projectList.getSelectedValue();
+ selectedProject.setEdition(-1);
+ updateCompleteURI();
+ }
+ }
+
+ /**
+ * Updates the complete URI text field.
+ */
+ private void updateCompleteURI() {
+ int selectedIndex = projectList.getSelectedIndex();
+ if (selectedIndex > -1) {
+ Project selectedProject = (Project) projectList.getSelectedValue();
+ projectCompleteUriTextField.setText(selectedProject.getFinalRequestURI(0));
+ }
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void valueChanged(ListSelectionEvent listSelectionEvent) {
+ int selectedRow = projectList.getSelectedIndex();
+ Project selectedProject = (Project) projectList.getSelectedValue();
+ projectNameTextField.setEnabled(selectedRow > -1);
+ projectDescriptionTextField.setEnabled(selectedRow > -1);
+ projectLocalPathTextField.setEnabled(selectedRow > -1);
+ projectPathTextField.setEnabled(selectedRow > -1);
+ projectLocalPathBrowseAction.setEnabled(selectedRow > -1);
+ projectDeleteAction.setEnabled(selectedRow > -1);
+ projectCloneAction.setEnabled(selectedRow > -1);
+ projectCopyURIAction.setEnabled(selectedRow > -1);
+ projectManageKeysAction.setEnabled(selectedRow > -1);
+ projectResetEditionAction.setEnabled(selectedRow > -1);
+ if (selectedRow > -1) {
+ projectNameTextField.setText(selectedProject.getName());
+ projectDescriptionTextField.setText(selectedProject.getDescription());
+ projectLocalPathTextField.setText(selectedProject.getLocalPath());
+ projectPathTextField.setText(selectedProject.getPath());
+ projectCompleteUriTextField.setText("freenet:" + selectedProject.getFinalRequestURI(0));
+ } else {
+ projectNameTextField.setText("");
+ projectDescriptionTextField.setText("");
+ projectLocalPathTextField.setText("");
+ projectPathTextField.setText("");
+ projectCompleteUriTextField.setText("");
+ }
+ }
+
+ //
+ // INTERFACE ChangeListener
+ //
+
+ //
+ // INTERFACE DocumentListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void insertUpdate(DocumentEvent documentEvent) {
+ setTextField(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeUpdate(DocumentEvent documentEvent) {
+ setTextField(documentEvent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changedUpdate(DocumentEvent documentEvent) {
+ setTextField(documentEvent);
+ }
+
+ //
+ // INTERFACE ClipboardOwner
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ /* ignore. */
+ }
+
+}
--- /dev/null
+/*
+ * jSite - I18n.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.i18n;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Maps i18n keys to translated texts, depending on a current locale.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class I18n {
+
+ /** The default locale, English. */
+ private static Locale defaultLocale = new Locale("en");
+
+ /** The current locale. */
+ private static Locale currentLocale;
+
+ /**
+ * Returns the currently set locale.
+ *
+ * @return The current locale
+ */
+ public static Locale getLocale() {
+ if (currentLocale == null) {
+ currentLocale = Locale.getDefault();
+ }
+ return currentLocale;
+ }
+
+ /**
+ * Sets the current locale.
+ *
+ * @param locale
+ * The new current locale
+ */
+ public static void setLocale(Locale locale) {
+ currentLocale = locale;
+ Locale.setDefault(locale);
+ }
+
+ /**
+ * Returns the resource bundle for the current locale.
+ *
+ * @return The resource bundle for the current locale
+ */
+ public static ResourceBundle getResourceBundle() {
+ return getResourceBundle(getLocale());
+ }
+
+ /**
+ * Returns the resource bundle for the given locale.
+ *
+ * @param locale
+ * The locale to get the resource bundle for
+ * @return The resource bundle for the given locale
+ */
+ public static ResourceBundle getResourceBundle(Locale locale) {
+ return ResourceBundle.getBundle("de.todesbaum.jsite.i18n.jSite", locale);
+ }
+
+ /**
+ * Retrieves a translated text for the given i18n key. If the resource
+ * bundle for the current locale does not have a translation for the given
+ * key, the default locale is tried. If that fails, the key is returned.
+ *
+ * @param key
+ * The key to get the translation for
+ * @return The translated value, or the key itself if not translation can be
+ * found
+ */
+ public static String getMessage(String key) {
+ try {
+ return getResourceBundle().getString(key);
+ } catch (MissingResourceException mre1) {
+ try {
+ return getResourceBundle(defaultLocale).getString(key);
+ } catch (MissingResourceException mre2) {
+ return key;
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - I18nContainer.java - Copyright © 2007–2012 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 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.i18n;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Container that collects {@link Runnable}s that change the texts of GUI
+ * components when the current locale has changed.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class I18nContainer implements Iterable<Runnable> {
+
+ /** The container singleton. */
+ private static final I18nContainer singleton = new I18nContainer();
+
+ /** The list of runnables that change texts. */
+ private final List<Runnable> i18nRunnables = Collections.synchronizedList(new ArrayList<Runnable>());
+
+ /**
+ * The list of runnables that change texts and run after
+ * {@link #i18nRunnables}.
+ */
+ private final List<Runnable> i18nPostRunnables = Collections.synchronizedList(new ArrayList<Runnable>());
+
+ /**
+ * Returns the singleton instance.
+ *
+ * @return The singleton instance
+ */
+ public static I18nContainer getInstance() {
+ return singleton;
+ }
+
+ /**
+ * Registers an i18n runnable that is run when the current locale has
+ * changed.
+ *
+ * @param i18nRunnable
+ * The runnable to register
+ */
+ public void registerRunnable(Runnable i18nRunnable) {
+ i18nRunnables.add(i18nRunnable);
+ }
+
+ /**
+ * Registers a {@link Runnable} that changes texts when the current locale
+ * has changed and runs after {@link #i18nRunnables} have run.
+ *
+ * @param i18nPostRunnable
+ * The runnable to register
+ */
+ public void registerPostRunnable(Runnable i18nPostRunnable) {
+ i18nPostRunnables.add(i18nPostRunnable);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns a combined list of {@link #i18nRunnables} and
+ * {@link #i18nPostRunnables}, in that order.
+ */
+ public Iterator<Runnable> iterator() {
+ List<Runnable> allRunnables = new ArrayList<Runnable>();
+ allRunnables.addAll(i18nRunnables);
+ allRunnables.addAll(i18nPostRunnables);
+ return allRunnables.iterator();
+ }
+
+}
--- /dev/null
+/*
+ * jSite - CLI.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+import java.io.PrintWriter;
+
+import de.todesbaum.jsite.application.Freenet7Interface;
+import de.todesbaum.jsite.application.InsertListener;
+import de.todesbaum.jsite.application.Node;
+import de.todesbaum.jsite.application.Project;
+import de.todesbaum.jsite.application.ProjectInserter;
+import de.todesbaum.util.io.StreamCopier.ProgressListener;
+
+/**
+ * Command-line interface for jSite.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class CLI implements InsertListener {
+
+ /** Object used for synchronization. */
+ private Object lockObject = new Object();
+
+ /** Writer for the console. */
+ private PrintWriter outputWriter = new PrintWriter(System.out, true);
+
+ /** The freenet interface. */
+ private Freenet7Interface freenetInterface;
+
+ /** The project inserter. */
+ private ProjectInserter projectInserter = new ProjectInserter();
+
+ /** The list of nodes. */
+ private Node[] nodes;
+
+ /** The projects. */
+ private Project[] projects;
+
+ /** Whether the insert has finished. */
+ private boolean finished = false;
+
+ /** Whether the insert finished successfully. */
+ private boolean success;
+
+ /**
+ * Creates a new command-line interface.
+ *
+ * @param args
+ * The command-line arguments
+ */
+ private CLI(String[] args) {
+
+ if ((args.length == 0) || args[0].equals("-h") || args[0].equals("--help")) {
+ outputWriter.println("\nParameters:\n");
+ outputWriter.println(" --config-file=<configuration file>");
+ outputWriter.println(" --node=<node name>");
+ outputWriter.println(" --project=<project name>");
+ outputWriter.println(" --local-directory=<local directory>");
+ outputWriter.println(" --path=<path>");
+ outputWriter.println(" --edition=<edition>");
+ outputWriter.println("\nA project gets inserted when a new project is loaded on the command line,");
+ outputWriter.println("or when the command line is finished. --local-directory, --path, and --edition");
+ outputWriter.println("override the parameters in the project.");
+ return;
+ }
+
+ String configFile = System.getProperty("user.home") + "/.jSite/config7";
+ for (String argument : args) {
+ String value = argument.substring(argument.indexOf('=') + 1).trim();
+ if (argument.startsWith("--config-file=")) {
+ configFile = value;
+ }
+ }
+
+ ConfigurationLocator configurationLocator = new ConfigurationLocator();
+ if (configFile != null) {
+ configurationLocator.setCustomLocation(configFile);
+ }
+ Configuration configuration = new Configuration(configurationLocator, configurationLocator.findPreferredLocation());
+
+ projectInserter.addInsertListener(this);
+ projects = configuration.getProjects();
+ Node node = configuration.getSelectedNode();
+ nodes = configuration.getNodes();
+
+ freenetInterface = new Freenet7Interface();
+ freenetInterface.setNode(node);
+
+ projectInserter.setFreenetInterface(freenetInterface);
+
+ Project currentProject = null;
+ for (String argument : args) {
+ if (argument.startsWith("--config-file=")) {
+ /* we already parsed this one. */
+ continue;
+ }
+ String value = argument.substring(argument.indexOf('=') + 1).trim();
+ if (argument.startsWith("--node=")) {
+ Node newNode = getNode(value);
+ if (newNode == null) {
+ outputWriter.println("Node \"" + value + "\" not found.");
+ return;
+ }
+ node = newNode;
+ freenetInterface.setNode(node);
+ } else if (argument.startsWith("--project=")) {
+ if (currentProject != null) {
+ if (insertProject(currentProject)) {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted.");
+ } else {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted.");
+ }
+ currentProject = null;
+ }
+ currentProject = getProject(value);
+ if (currentProject == null) {
+ outputWriter.println("Project \"" + value + "\" not found.");
+ }
+ } else if (argument.startsWith("--local-directory")) {
+ if (currentProject == null) {
+ outputWriter.println("You can't specifiy --local-directory before --project.");
+ return;
+ }
+ currentProject.setLocalPath(value);
+ } else if (argument.startsWith("--path=")) {
+ if (currentProject == null) {
+ outputWriter.println("You can't specify --path before --project.");
+ return;
+ }
+ currentProject.setPath(value);
+ } else if (argument.startsWith("--edition=")) {
+ if (currentProject == null) {
+ outputWriter.println("You can't specify --edition before --project.");
+ return;
+ }
+ currentProject.setEdition(Integer.parseInt(value));
+ } else {
+ outputWriter.println("Unknown parameter: " + argument);
+ return;
+ }
+ }
+
+ int errorCode = 1;
+ if (currentProject != null) {
+ if (insertProject(currentProject)) {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted.");
+ errorCode = 0;
+ } else {
+ outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted.");
+ }
+ }
+
+ configuration.setProjects(projects);
+ configuration.save();
+
+ System.exit(errorCode);
+ }
+
+ /**
+ * Returns the project with the given name.
+ *
+ * @param name
+ * The name of the project
+ * @return The project, or <code>null</code> if no project could be found
+ */
+ private Project getProject(String name) {
+ for (Project project : projects) {
+ if (project.getName().equals(name)) {
+ return project;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the node with the given name.
+ *
+ * @param name
+ * The name of the node
+ * @return The node, or <code>null</code> if no node could be found
+ */
+ private Node getNode(String name) {
+ for (Node node : nodes) {
+ if (node.getName().equals(name)) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Inserts the given project.
+ *
+ * @param currentProject
+ * The project to insert
+ * @return <code>true</code> if the insert finished successfully,
+ * <code>false</code> otherwise
+ */
+ private boolean insertProject(Project currentProject) {
+ if (!freenetInterface.hasNode()) {
+ outputWriter.println("Node is not running!");
+ return false;
+ }
+ projectInserter.setProject(currentProject);
+ projectInserter.start(new ProgressListener() {
+
+ public void onProgress(long copied, long length) {
+ System.out.print("Uploaded: " + copied + " / " + length + " bytes...\r");
+ }
+ });
+ synchronized (lockObject) {
+ while (!finished) {
+ try {
+ lockObject.wait();
+ } catch (InterruptedException e) {
+ /* ignore, we're in a loop. */
+ }
+ }
+ }
+ return success;
+ }
+
+ //
+ // INTERFACE InsertListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertStarted(Project project) {
+ outputWriter.println("Starting Insert of project \"" + project.getName() + "\".");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectUploadFinished(Project project) {
+ outputWriter.println("Project \"" + project.getName() + "\" has been uploaded, starting insert...");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectURIGenerated(Project project, String uri) {
+ outputWriter.println("URI: " + uri);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized) {
+ outputWriter.println("Progress: " + succeeded + " done, " + failed + " failed, " + fatal + " fatal, " + total + " total" + (finalized ? " (finalized)" : "") + ", " + ((succeeded + failed + fatal) * 100 / total) + "%");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void projectInsertFinished(Project project, boolean success, Throwable cause) {
+ outputWriter.println("Request URI: " + project.getFinalRequestURI(0));
+ finished = true;
+ this.success = success;
+ synchronized (lockObject) {
+ lockObject.notify();
+ }
+ }
+
+ //
+ // MAIN
+ //
+
+ /**
+ * Creates a new command-line interface with the given arguments.
+ *
+ * @param args
+ * The command-line arguments
+ */
+ public static void main(String[] args) {
+ new CLI(args);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Configuration.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+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.freenet.fcp2.ClientPutDir.ManifestPutter;
+import de.todesbaum.util.freenet.fcp2.PriorityClass;
+import de.todesbaum.util.io.Closer;
+import de.todesbaum.util.io.StreamCopier;
+import de.todesbaum.util.xml.SimpleXML;
+import de.todesbaum.util.xml.XML;
+
+/**
+ * The configuration.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class Configuration {
+
+ /** The root node of the configuration. */
+ private SimpleXML rootNode;
+
+ /** The configuration locator. */
+ private final ConfigurationLocator configurationLocator;
+
+ /** Where the configuration resides. */
+ private ConfigurationLocation configurationLocation;
+
+ /**
+ * Creates a new configuration that is read from the given file.
+ *
+ * @param configurationLocator
+ * The configuration locator
+ * @param configurationLocation
+ * The configuration directory
+ */
+ public Configuration(ConfigurationLocator configurationLocator, ConfigurationLocation configurationLocation) {
+ this.configurationLocator = configurationLocator;
+ this.configurationLocation = configurationLocation;
+ readConfiguration(configurationLocator.getFile(configurationLocation));
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Returns the configuration locator.
+ *
+ * @return The configuration locator
+ */
+ public ConfigurationLocator getConfigurationLocator() {
+ return configurationLocator;
+ }
+
+ /**
+ * Returns the location the configuration will be written to when calling
+ * {@link #save()}.
+ *
+ * @return The location the configuration will be written to
+ */
+ public ConfigurationLocation getConfigurationDirectory() {
+ return configurationLocation;
+ }
+
+ /**
+ * Sets the location the configuration will be written to when calling
+ * {@link #save()}.
+ *
+ * @param configurationLocation
+ * The location to write the configuration to
+ */
+ 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(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");
+ }
+
+ /**
+ * Saves the configuration.
+ *
+ * @return <code>true</code> if the configuration could be saved,
+ * <code>false</code> otherwise
+ */
+ public boolean save() {
+ 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()) {
+ return false;
+ }
+ }
+ FileOutputStream fileOutputStream = null;
+ ByteArrayInputStream configurationInputStream = null;
+ try {
+ byte[] configurationBytes = XML.transformToByteArray(rootNode.getDocument());
+ configurationInputStream = new ByteArrayInputStream(configurationBytes);
+ fileOutputStream = new FileOutputStream(configurationFile);
+ StreamCopier.copy(configurationInputStream, fileOutputStream, configurationBytes.length);
+ return true;
+ } catch (IOException ioe1) {
+ /* ignore. */
+ } finally {
+ Closer.close(configurationInputStream);
+ Closer.close(fileOutputStream);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the value of a node.
+ *
+ * @param nodeNames
+ * The name of all nodes in the chain
+ * @param defaultValue
+ * The default value to return if the node could not be found
+ * @return The value of the node, or the default value if the node could not
+ * be found
+ */
+ private String getNodeValue(String[] nodeNames, String defaultValue) {
+ SimpleXML node = rootNode;
+ int nodeIndex = 0;
+ while ((node != null) && (nodeIndex < nodeNames.length)) {
+ node = node.getNode(nodeNames[nodeIndex++]);
+ }
+ if (node == null) {
+ return defaultValue;
+ }
+ return node.getValue();
+ }
+
+ /**
+ * Returns the integer value of a node.
+ *
+ * @param nodeNames
+ * The names of all nodes in the chain
+ * @param defaultValue
+ * The default value to return if the node can not be found
+ * @return The parsed integer value, or the default value if the node can
+ * not be found or the value can not be parsed into an integer
+ */
+ private int getNodeIntValue(String[] nodeNames, int defaultValue) {
+ try {
+ return Integer.parseInt(getNodeValue(nodeNames, String.valueOf(defaultValue)));
+ } catch (NumberFormatException nfe1) {
+ /* ignore. */
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Returns the boolean value of a node.
+ *
+ * @param nodeNames
+ * The names of all nodes in the chain
+ * @param defaultValue
+ * The default value to return if the node can not be found
+ * @return The parsed boolean value, or the default value if the node can
+ * not be found
+ */
+ private boolean getNodeBooleanValue(String[] nodeNames, boolean defaultValue) {
+ String nodeValue = getNodeValue(nodeNames, null);
+ if (nodeValue == null) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(nodeValue);
+ }
+
+ /**
+ * Returns the hostname of the node.
+ *
+ * @return The hostname of the node
+ * @deprecated Use {@link #getSelectedNode()} instead
+ */
+ @Deprecated
+ public String getNodeAddress() {
+ return getNodeValue(new String[] { "node-address" }, "localhost");
+ }
+
+ /**
+ * Sets the hostname of the node.
+ *
+ * @param nodeAddress
+ * The hostname of the node
+ * @deprecated Use {@link #setSelectedNode(Node)} instead
+ */
+ @Deprecated
+ public void setNodeAddress(String nodeAddress) {
+ rootNode.replace("node-address", nodeAddress);
+ }
+
+ /**
+ * The port number of the node
+ *
+ * @return The port number of the node
+ * @deprecated Use {@link #getSelectedNode()} instead.
+ */
+ @Deprecated
+ public int getNodePort() {
+ return getNodeIntValue(new String[] { "node-port" }, 9481);
+ }
+
+ /**
+ * Sets the port number of the node.
+ *
+ * @param nodePort
+ * The port number of the node
+ * @deprecated Use {@link #setSelectedNode(Node)} instead
+ */
+ @Deprecated
+ public void setNodePort(int nodePort) {
+ rootNode.replace("node-port", String.valueOf(nodePort));
+ }
+
+ /**
+ * Returns whether the node configuration page should be skipped on startup.
+ *
+ * @return <code>true</code> to skip the node configuration page on startup,
+ * <code>false</code> to show it
+ */
+ public boolean isSkipNodePage() {
+ return getNodeBooleanValue(new String[] { "skip-node-page" }, false);
+ }
+
+ /**
+ * Sets whether the node configuration page should be skipped on startup.
+ *
+ * @param skipNodePage
+ * <code>true</code> to skip the node configuration page on
+ * startup, <code>false</code> to show it
+ */
+ public void setSkipNodePage(boolean skipNodePage) {
+ rootNode.replace("skip-node-page", String.valueOf(skipNodePage));
+ }
+
+ /**
+ * Returns all configured projects.
+ *
+ * @return A list of all projects
+ */
+ public Project[] getProjects() {
+ List<Project> projects = new ArrayList<Project>();
+ SimpleXML projectsNode = rootNode.getNode("project-list");
+ if (projectsNode != null) {
+ SimpleXML[] projectNodes = projectsNode.getNodes("project");
+ for (SimpleXML projectNode : projectNodes) {
+ try {
+ Project project = new Project();
+ projects.add(project);
+ project.setDescription(projectNode.getNode("description").getValue(""));
+ String indexFile = projectNode.getNode("index-file").getValue("");
+ if (indexFile.indexOf('/') > -1) {
+ indexFile = "";
+ }
+ project.setIndexFile(indexFile);
+ project.setLastInsertionTime(Long.parseLong(projectNode.getNode("last-insertion-time").getValue("0")));
+ project.setLocalPath(projectNode.getNode("local-path").getValue(""));
+ project.setName(projectNode.getNode("name").getValue(""));
+ project.setPath(projectNode.getNode("path").getValue(""));
+ if ((project.getPath() != null) && (project.getPath().indexOf("/") != -1)) {
+ project.setPath(project.getPath().replaceAll("/", ""));
+ }
+ project.setEdition(Integer.parseInt(projectNode.getNode("edition").getValue("0")));
+ project.setInsertURI(projectNode.getNode("insert-uri").getValue(""));
+ project.setRequestURI(projectNode.getNode("request-uri").getValue(""));
+ if (projectNode.getNode("ignore-hidden-files") != null) {
+ project.setIgnoreHiddenFiles(Boolean.parseBoolean(projectNode.getNode("ignore-hidden-files").getValue("true")));
+ } else {
+ project.setIgnoreHiddenFiles(true);
+ }
+
+ /* load last insert hashes. */
+ Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
+ SimpleXML lastInsertHashesNode = projectNode.getNode("last-insert-hashes");
+ if (lastInsertHashesNode != null) {
+ for (SimpleXML fileNode : lastInsertHashesNode.getNodes("file")) {
+ String filename = fileNode.getNode("filename").getValue();
+ String lastInsertHash = fileNode.getNode("last-insert-hash").getValue();
+ int lastInsertEdition = Integer.valueOf(fileNode.getNode("last-insert-edition").getValue());
+ String lastInsertFilename = filename;
+ if (fileNode.getNode("last-insert-filename") != null) {
+ lastInsertFilename = fileNode.getNode("last-insert-filename").getValue();
+ }
+ FileOption fileOption = project.getFileOption(filename);
+ fileOption.setLastInsertHash(lastInsertHash).setLastInsertEdition(lastInsertEdition).setLastInsertFilename(lastInsertFilename);
+ fileOptions.put(filename, fileOption);
+ }
+ }
+
+ SimpleXML fileOptionsNode = projectNode.getNode("file-options");
+ if (fileOptionsNode != null) {
+ SimpleXML[] fileOptionNodes = fileOptionsNode.getNodes("file-option");
+ for (SimpleXML fileOptionNode : fileOptionNodes) {
+ String filename = fileOptionNode.getNode("filename").getValue();
+ FileOption fileOption = project.getFileOption(filename);
+ fileOption.setInsert(Boolean.parseBoolean(fileOptionNode.getNode("insert").getValue()));
+ if (fileOptionNode.getNode("insert-redirect") != null) {
+ fileOption.setInsertRedirect(Boolean.parseBoolean(fileOptionNode.getNode("insert-redirect").getValue()));
+ }
+ fileOption.setCustomKey(fileOptionNode.getNode("custom-key").getValue(""));
+ if (fileOptionNode.getNode("changed-name") != null) {
+ fileOption.setChangedName(fileOptionNode.getNode("changed-name").getValue());
+ }
+ fileOption.setMimeType(fileOptionNode.getNode("mime-type").getValue(""));
+ fileOptions.put(filename, fileOption);
+ }
+ }
+ project.setFileOptions(fileOptions);
+ } catch (NumberFormatException nfe1) {
+ nfe1.printStackTrace();
+ }
+ }
+ }
+ return projects.toArray(new Project[projects.size()]);
+ }
+
+ /**
+ * Sets the list of all projects.
+ *
+ * @param projects
+ * The list of all projects
+ */
+ public void setProjects(Project[] projects) {
+ SimpleXML projectsNode = new SimpleXML("project-list");
+ for (Project project : projects) {
+ SimpleXML projectNode = projectsNode.append("project");
+ projectNode.append("edition", String.valueOf(project.getEdition()));
+ projectNode.append("description", project.getDescription());
+ projectNode.append("index-file", project.getIndexFile());
+ projectNode.append("last-insertion-time", String.valueOf(project.getLastInsertionTime()));
+ projectNode.append("local-path", project.getLocalPath());
+ projectNode.append("name", project.getName());
+ projectNode.append("path", project.getPath());
+ projectNode.append("insert-uri", project.getInsertURI());
+ projectNode.append("request-uri", project.getRequestURI());
+ projectNode.append("ignore-hidden-files", String.valueOf(project.isIgnoreHiddenFiles()));
+
+ /* store last insert hashes. */
+ SimpleXML lastInsertHashesNode = projectNode.append("last-insert-hashes");
+ for (Entry<String, FileOption> fileOption : project.getFileOptions().entrySet()) {
+ if ((fileOption.getValue().getLastInsertHash() == null) || (fileOption.getValue().getLastInsertHash().length() == 0)) {
+ continue;
+ }
+ SimpleXML fileNode = lastInsertHashesNode.append("file");
+ fileNode.append("filename", fileOption.getKey());
+ fileNode.append("last-insert-hash", fileOption.getValue().getLastInsertHash());
+ fileNode.append("last-insert-edition", String.valueOf(fileOption.getValue().getLastInsertEdition()));
+ fileNode.append("last-insert-filename", fileOption.getValue().getLastInsertFilename());
+ }
+
+ SimpleXML fileOptionsNode = projectNode.append("file-options");
+ Iterator<Entry<String, FileOption>> entries = project.getFileOptions().entrySet().iterator();
+ while (entries.hasNext()) {
+ Entry<String, FileOption> entry = entries.next();
+ FileOption fileOption = entry.getValue();
+ if (fileOption.isCustom()) {
+ SimpleXML fileOptionNode = fileOptionsNode.append("file-option");
+ fileOptionNode.append("filename", entry.getKey());
+ fileOptionNode.append("insert", String.valueOf(fileOption.isInsert()));
+ fileOptionNode.append("insert-redirect", String.valueOf(fileOption.isInsertRedirect()));
+ fileOptionNode.append("custom-key", fileOption.getCustomKey());
+ fileOptionNode.append("changed-name", fileOption.getChangedName());
+ fileOptionNode.append("mime-type", fileOption.getMimeType());
+ }
+ }
+ }
+ rootNode.replace(projectsNode);
+ }
+
+ /**
+ * Returns the stored locale.
+ *
+ * @return The stored locale
+ */
+ public Locale getLocale() {
+ String language = getNodeValue(new String[] { "i18n", "language" }, "en");
+ String country = getNodeValue(new String[] { "i18n", "country" }, null);
+ if (country != null) {
+ return new Locale(language, country);
+ }
+ return new Locale(language);
+ }
+
+ /**
+ * Sets the locale to store.
+ *
+ * @param locale
+ * The locale to store
+ */
+ public void setLocale(Locale locale) {
+ SimpleXML i18nNode = new SimpleXML("i18n");
+ if (locale.getCountry().length() != 0) {
+ i18nNode.append("country", locale.getCountry());
+ }
+ i18nNode.append("language", locale.getLanguage());
+ rootNode.replace(i18nNode);
+ return;
+ }
+
+ /**
+ * Returns a list of configured nodes.
+ *
+ * @return The list of the configured nodes
+ */
+ public Node[] getNodes() {
+ SimpleXML nodesNode = rootNode.getNode("nodes");
+ if (nodesNode == null) {
+ String hostname = getNodeAddress();
+ int port = getNodePort();
+ if (hostname == null) {
+ hostname = "127.0.0.1";
+ port = 9481;
+ }
+ return new Node[] { new Node(hostname, port, "Node") };
+ }
+ SimpleXML[] nodeNodes = nodesNode.getNodes("node");
+ Node[] returnNodes = new Node[nodeNodes.length];
+ int nodeIndex = 0;
+ for (SimpleXML nodeNode : nodeNodes) {
+ String name = nodeNode.getNode("name").getValue();
+ String hostname = nodeNode.getNode("hostname").getValue();
+ int port = Integer.parseInt(nodeNode.getNode("port").getValue());
+ Node node = new Node(hostname, port, name);
+ returnNodes[nodeIndex++] = node;
+ }
+ return returnNodes;
+ }
+
+ /**
+ * Sets the list of configured nodes.
+ *
+ * @param nodes
+ * The list of configured nodes
+ */
+ public void setNodes(Node[] nodes) {
+ SimpleXML nodesNode = new SimpleXML("nodes");
+ for (Node node : nodes) {
+ SimpleXML nodeNode = nodesNode.append("node");
+ nodeNode.append("name", node.getName());
+ nodeNode.append("hostname", node.getHostname());
+ nodeNode.append("port", String.valueOf(node.getPort()));
+ }
+ rootNode.replace(nodesNode);
+ rootNode.remove("node-address");
+ rootNode.remove("node-port");
+ }
+
+ /**
+ * Sets the selected node.
+ *
+ * @param selectedNode
+ * The selected node
+ */
+ public void setSelectedNode(Node selectedNode) {
+ SimpleXML selectedNodeNode = new SimpleXML("selected-node");
+ selectedNodeNode.append("name", selectedNode.getName());
+ selectedNodeNode.append("hostname", selectedNode.getHostname());
+ selectedNodeNode.append("port", String.valueOf(selectedNode.getPort()));
+ rootNode.replace(selectedNodeNode);
+ }
+
+ /**
+ * Returns the selected node.
+ *
+ * @return The selected node
+ */
+ public Node getSelectedNode() {
+ SimpleXML selectedNodeNode = rootNode.getNode("selected-node");
+ if (selectedNodeNode == null) {
+ String hostname = getNodeAddress();
+ int port = getNodePort();
+ if (hostname == null) {
+ hostname = "127.0.0.1";
+ port = 9481;
+ }
+ return new Node(hostname, port, "Node");
+ }
+ String name = selectedNodeNode.getNode("name").getValue();
+ String hostname = selectedNodeNode.getNode("hostname").getValue();
+ int port = Integer.valueOf(selectedNodeNode.getNode("port").getValue());
+ return new Node(hostname, port, name);
+ }
+
+ /**
+ * Returns the temp directory to use.
+ *
+ * @return The temp directoy, or {@code null} to use the default temp
+ * directory
+ */
+ public String getTempDirectory() {
+ return getNodeValue(new String[] { "temp-directory" }, null);
+ }
+
+ /**
+ * Sets the temp directory to use.
+ *
+ * @param tempDirectory
+ * The temp directory to use, or {@code null} to use the default
+ * temp directory
+ */
+ public void setTempDirectory(String tempDirectory) {
+ if (tempDirectory != null) {
+ SimpleXML tempDirectoryNode = new SimpleXML("temp-directory");
+ tempDirectoryNode.setValue(tempDirectory);
+ rootNode.replace(tempDirectoryNode);
+ } else {
+ rootNode.remove("temp-directory");
+ }
+ }
+
+ /**
+ * Returns whether to use the “early encode“ flag for the insert.
+ *
+ * @return {@code true} to set the “early encode” flag for the insert,
+ * {@code false} otherwise
+ */
+ public boolean useEarlyEncode() {
+ return getNodeBooleanValue(new String[] { "use-early-encode" }, false);
+ }
+
+ /**
+ * Sets whether to use the “early encode“ flag for the insert.
+ *
+ * @param useEarlyEncode
+ * {@code true} to set the “early encode” flag for the insert,
+ * {@code false} otherwise
+ * @return This configuration
+ */
+ public Configuration setUseEarlyEncode(boolean useEarlyEncode) {
+ rootNode.replace("use-early-encode", String.valueOf(useEarlyEncode));
+ return this;
+ }
+
+ /**
+ * Returns the insert priority.
+ *
+ * @return The insert priority
+ */
+ public PriorityClass getPriority() {
+ return PriorityClass.valueOf(getNodeValue(new String[] { "insert-priority" }, "interactive"));
+ }
+
+ /**
+ * Sets the insert priority.
+ *
+ * @param priority
+ * The insert priority
+ * @return This configuration
+ */
+ public Configuration setPriority(PriorityClass priority) {
+ rootNode.replace("insert-priority", priority.toString());
+ return this;
+ }
+
+ /**
+ * Returns the manifest putter.
+ *
+ * @return The manifest putter
+ */
+ public ManifestPutter getManifestPutter() {
+ return ManifestPutter.valueOf(getNodeValue(new String[] { "manifest-putter" }, "simple").toUpperCase());
+ }
+
+ /**
+ * Sets the manifest putter.
+ *
+ * @param manifestPutter
+ * The manifest putter
+ * @return This configuration
+ */
+ public Configuration setManifestPutter(ManifestPutter manifestPutter) {
+ rootNode.replace("manifest-putter", manifestPutter.name().toLowerCase());
+ return this;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ConfigurationLocator.java - Copyright © 2011–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Locator for configuration files in different places.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class ConfigurationLocator {
+
+ /**
+ * The location of the configuration directory.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+ public enum ConfigurationLocation {
+
+ /** 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,
+
+ /** Custom location. */
+ CUSTOM,
+
+ }
+
+ /** The possible configuration locations. */
+ private final Map<ConfigurationLocation, String> configurationFiles = new HashMap<ConfigurationLocation, String>();
+
+ /**
+ * Creates a new configuration locator. If this class is loaded from a JAR
+ * file, {@link ConfigurationLocation#NEXT_TO_JAR_FILE} is added to the list
+ * of possible configuration file locations.
+ * {@link ConfigurationLocation#HOME_DIRECTORY} is always added to this
+ * list, {@link ConfigurationLocation#CUSTOM} has to be enabled by calling
+ * {@link #setCustomLocation(String)}.
+ */
+ public ConfigurationLocator() {
+ /* are we executed from a JAR file? */
+ String resource = getClass().getResource("/" + getClass().getName().replace(".", "/") + ".class").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");
+ configurationFiles.put(ConfigurationLocation.NEXT_TO_JAR_FILE, configurationFile.getPath());
+ }
+ File homeDirectoryFile = new File(System.getProperty("user.home"), ".jSite/config7");
+ configurationFiles.put(ConfigurationLocation.HOME_DIRECTORY, homeDirectoryFile.getPath());
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * Sets the location of the custom configuration file.
+ *
+ * @param customFile
+ * The custom location of the configuration file
+ */
+ public void setCustomLocation(String customFile) {
+ configurationFiles.put(ConfigurationLocation.CUSTOM, customFile);
+ }
+
+ /**
+ * Returns whether the given location is valid. Certain locations (such as
+ * {@link ConfigurationLocation#NEXT_TO_JAR_FILE}) may be invalid in certain
+ * circumstances (such as the application not being run from a JAR file). A
+ * location being valid does not imply that a configuration file does exist
+ * at the given location, use {@link #hasFile(ConfigurationLocation)} to
+ * check for a configuration file at the desired location.
+ *
+ * @param configurationLocation
+ * The configuration location
+ * @return {@code true} if the location is valid, {@code false} otherwise
+ */
+ public boolean isValidLocation(ConfigurationLocation configurationLocation) {
+ return configurationFiles.containsKey(configurationLocation);
+ }
+
+ /**
+ * Checks whether a configuration file exists at the given location.
+ *
+ * @param configurationLocation
+ * The configuration location
+ * @return {@code true} if a configuration file exists at the given
+ * location, {@code false} otherwise
+ */
+ public boolean hasFile(ConfigurationLocation configurationLocation) {
+ if (!isValidLocation(configurationLocation)) {
+ return false;
+ }
+ return new File(configurationFiles.get(configurationLocation)).exists();
+ }
+
+ /**
+ * Returns the configuration file for the given location.
+ *
+ * @param configurationLocation
+ * The location to get the file for
+ * @return The name of the configuration file at the given location, or
+ * {@code null} if the given location is invalid
+ */
+ public String getFile(ConfigurationLocation configurationLocation) {
+ return configurationFiles.get(configurationLocation);
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Finds the preferred location of the configuration file.
+ *
+ * @see #findPreferredLocation(ConfigurationLocation)
+ * @return The preferred location of the configuration file
+ */
+ public ConfigurationLocation findPreferredLocation() {
+ return findPreferredLocation(ConfigurationLocation.NEXT_TO_JAR_FILE);
+ }
+
+ /**
+ * Finds the preferred location of the configuration file. The following
+ * checks are performed: if a custom configuration location has been defined
+ * (by calling {@link #setCustomLocation(String)})
+ * {@link ConfigurationLocation#CUSTOM} is returned. If the application is
+ * run from a JAR file and a configuration file is found next to the JAR
+ * file (i.e. in the same directory),
+ * {@link ConfigurationLocation#NEXT_TO_JAR_FILE} is returned. If a
+ * configuration file exists in the user’s home directory,
+ * {@link ConfigurationLocation#HOME_DIRECTORY} is returned. Otherwise, the
+ * given {@code defaultLocation} is returned.
+ *
+ * @param defaultLocation
+ * The default location to return if no other configuration file
+ * is found
+ * @return The configuration location to load the configuration from
+ */
+ public ConfigurationLocation findPreferredLocation(ConfigurationLocation defaultLocation) {
+ if (hasFile(ConfigurationLocation.CUSTOM)) {
+ return ConfigurationLocation.CUSTOM;
+ }
+ if (hasFile(ConfigurationLocation.NEXT_TO_JAR_FILE)) {
+ return ConfigurationLocation.NEXT_TO_JAR_FILE;
+ }
+ if (hasFile(ConfigurationLocation.HOME_DIRECTORY)) {
+ return ConfigurationLocation.HOME_DIRECTORY;
+ }
+ if (isValidLocation(defaultLocation)) {
+ return defaultLocation;
+ }
+ return ConfigurationLocation.HOME_DIRECTORY;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Main.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonGroup;
+import javax.swing.Icon;
+import javax.swing.JList;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+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.ProjectInserter.CheckReport;
+import de.todesbaum.jsite.application.ProjectInserter.Issue;
+import de.todesbaum.jsite.application.UpdateChecker;
+import de.todesbaum.jsite.application.UpdateListener;
+import de.todesbaum.jsite.gui.NodeManagerListener;
+import de.todesbaum.jsite.gui.NodeManagerPage;
+import de.todesbaum.jsite.gui.PreferencesPage;
+import de.todesbaum.jsite.gui.ProjectFilesPage;
+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.ConfigurationLocator.ConfigurationLocation;
+import de.todesbaum.util.image.IconLoader;
+import de.todesbaum.util.swing.TWizard;
+import de.todesbaum.util.swing.TWizardPage;
+import de.todesbaum.util.swing.WizardListener;
+
+/**
+ * The main class that ties together everything.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class Main implements ActionListener, ListSelectionListener, WizardListener, NodeManagerListener, UpdateListener {
+
+ /** The logger. */
+ private static final Logger logger = Logger.getLogger(Main.class.getName());
+
+ /** The version. */
+ private static final Version VERSION = new Version(0, 10);
+
+ /** The configuration. */
+ private Configuration configuration;
+
+ /** The freenet interface. */
+ private Freenet7Interface freenetInterface = new Freenet7Interface();
+
+ /** The update checker. */
+ private final UpdateChecker updateChecker;
+
+ /** The jSite icon. */
+ private Icon jSiteIcon;
+
+ /**
+ * Enumeration for all possible pages.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+ private static enum PageType {
+
+ /** The node manager page. */
+ PAGE_NODE_MANAGER,
+
+ /** The project page. */
+ PAGE_PROJECTS,
+
+ /** The project files page. */
+ PAGE_PROJECT_FILES,
+
+ /** The project insert page. */
+ PAGE_INSERT_PROJECT,
+
+ /** The preferences page. */
+ PAGE_PREFERENCES
+
+ }
+
+ /** The supported locales. */
+ private static final Locale[] SUPPORTED_LOCALES = new Locale[] { Locale.ENGLISH, Locale.GERMAN, Locale.FRENCH };
+
+ /** The actions that switch the language. */
+ private Map<Locale, Action> languageActions = new HashMap<Locale, Action>();
+
+ /** The “manage nodes” action. */
+ private Action manageNodeAction;
+
+ /** The “preferences” action. */
+ private Action optionsPreferencesAction;
+
+ /** The “check for updates” action. */
+ private Action checkForUpdatesAction;
+
+ /** The “about jSite” action. */
+ private Action aboutAction;
+
+ /** The wizard. */
+ private TWizard wizard;
+
+ /** The node menu. */
+ private JMenu nodeMenu;
+
+ /** The currently selected node. */
+ private Node selectedNode;
+
+ /** Mapping from page type to page. */
+ private final Map<PageType, TWizardPage> pages = new HashMap<PageType, TWizardPage>();
+
+ /** The original location of the configuration file. */
+ private ConfigurationLocation originalLocation;
+
+ /**
+ * Creates a new core with the default configuration file.
+ */
+ private Main() {
+ this(null);
+ }
+
+ /**
+ * Creates a new core with the given configuration from the given file.
+ *
+ * @param configFilename
+ * The name of the configuration file
+ */
+ private Main(String configFilename) {
+ /* collect all possible configuration file locations. */
+ ConfigurationLocator configurationLocator = new ConfigurationLocator();
+ if (configFilename != null) {
+ configurationLocator.setCustomLocation(configFilename);
+ }
+
+ originalLocation = configurationLocator.findPreferredLocation();
+ logger.log(Level.CONFIG, "Using configuration from " + originalLocation + ".");
+ configuration = new Configuration(configurationLocator, originalLocation);
+
+ Locale.setDefault(configuration.getLocale());
+ I18n.setLocale(configuration.getLocale());
+ wizard = new TWizard();
+ createActions();
+ wizard.setJMenuBar(createMenuBar());
+ wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
+ wizard.setPreviousEnabled(false);
+ wizard.setNextEnabled(true);
+ wizard.addWizardListener(this);
+ jSiteIcon = IconLoader.loadIcon("/jsite-icon.png");
+ wizard.setIcon(jSiteIcon);
+
+ updateChecker = new UpdateChecker(freenetInterface);
+ updateChecker.addUpdateListener(this);
+ updateChecker.start();
+
+ initPages();
+ showPage(PageType.PAGE_PROJECTS);
+ }
+
+ /**
+ * Creates all actions.
+ */
+ private void createActions() {
+ for (final Locale locale : SUPPORTED_LOCALES) {
+ languageActions.put(locale, new AbstractAction(I18n.getMessage("jsite.menu.language." + locale.getLanguage()), IconLoader.loadIcon("/flag-" + locale.getLanguage() + ".png")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ switchLanguage(locale);
+ }
+ });
+ }
+ manageNodeAction = new AbstractAction(I18n.getMessage("jsite.menu.nodes.manage-nodes")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ showPage(PageType.PAGE_NODE_MANAGER);
+ optionsPreferencesAction.setEnabled(true);
+ wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
+ wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
+ }
+ };
+ optionsPreferencesAction = new AbstractAction(I18n.getMessage("jsite.menu.options.preferences")) {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ optionsPreferences();
+ }
+ };
+ checkForUpdatesAction = new AbstractAction(I18n.getMessage("jsite.menu.help.check-for-updates")) {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent actionEvent) {
+ showLatestUpdate();
+ }
+ };
+ aboutAction = new AbstractAction(I18n.getMessage("jsite.menu.help.about")) {
+
+ @SuppressWarnings("synthetic-access")
+ public void actionPerformed(ActionEvent e) {
+ JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.about.message"), getVersion().toString()), null, JOptionPane.INFORMATION_MESSAGE, jSiteIcon);
+ }
+ };
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ manageNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.nodes.manage-nodes"));
+ optionsPreferencesAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.options.preferences"));
+ checkForUpdatesAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.help.check-for-updates"));
+ aboutAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.help.about"));
+ }
+ });
+ }
+
+ /**
+ * Creates the menu bar.
+ *
+ * @return The menu bar
+ */
+ private JMenuBar createMenuBar() {
+ JMenuBar menuBar = new JMenuBar();
+ final JMenu languageMenu = new JMenu(I18n.getMessage("jsite.menu.languages"));
+ menuBar.add(languageMenu);
+ ButtonGroup languageButtonGroup = new ButtonGroup();
+ for (Locale locale : SUPPORTED_LOCALES) {
+ Action languageAction = languageActions.get(locale);
+ JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(languageActions.get(locale));
+ if (locale.equals(Locale.getDefault())) {
+ menuItem.setSelected(true);
+ }
+ languageAction.putValue("menuItem", menuItem);
+ languageButtonGroup.add(menuItem);
+ languageMenu.add(menuItem);
+ }
+ nodeMenu = new JMenu(I18n.getMessage("jsite.menu.nodes"));
+ menuBar.add(nodeMenu);
+ selectedNode = configuration.getSelectedNode();
+ nodesUpdated(configuration.getNodes());
+
+ final JMenu optionsMenu = new JMenu(I18n.getMessage("jsite.menu.options"));
+ menuBar.add(optionsMenu);
+ optionsMenu.add(optionsPreferencesAction);
+
+ /* evil hack to right-align the help menu */
+ JPanel panel = new JPanel();
+ panel.setOpaque(false);
+ menuBar.add(panel);
+
+ final JMenu helpMenu = new JMenu(I18n.getMessage("jsite.menu.help"));
+ menuBar.add(helpMenu);
+ helpMenu.add(checkForUpdatesAction);
+ helpMenu.add(aboutAction);
+
+ I18nContainer.getInstance().registerRunnable(new Runnable() {
+
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ languageMenu.setText(I18n.getMessage("jsite.menu.languages"));
+ nodeMenu.setText(I18n.getMessage("jsite.menu.nodes"));
+ optionsMenu.setText(I18n.getMessage("jsite.menu.options"));
+ helpMenu.setText(I18n.getMessage("jsite.menu.help"));
+ for (Map.Entry<Locale, Action> languageActionEntry : languageActions.entrySet()) {
+ languageActionEntry.getValue().putValue(Action.NAME, I18n.getMessage("jsite.menu.language." + languageActionEntry.getKey().getLanguage()));
+ }
+ }
+ });
+
+ return menuBar;
+ }
+
+ /**
+ * Initializes all pages.
+ */
+ private void initPages() {
+ NodeManagerPage nodeManagerPage = new NodeManagerPage(wizard);
+ nodeManagerPage.setName("page.node-manager");
+ nodeManagerPage.addNodeManagerListener(this);
+ nodeManagerPage.setNodes(configuration.getNodes());
+ pages.put(PageType.PAGE_NODE_MANAGER, nodeManagerPage);
+
+ ProjectPage projectPage = new ProjectPage(wizard);
+ projectPage.setName("page.project");
+ projectPage.setProjects(configuration.getProjects());
+ projectPage.setFreenetInterface(freenetInterface);
+ projectPage.addListSelectionListener(this);
+ pages.put(PageType.PAGE_PROJECTS, projectPage);
+
+ ProjectFilesPage projectFilesPage = new ProjectFilesPage(wizard);
+ projectFilesPage.setName("page.project.files");
+ pages.put(PageType.PAGE_PROJECT_FILES, projectFilesPage);
+
+ ProjectInsertPage projectInsertPage = new ProjectInsertPage(wizard);
+ projectInsertPage.setName("page.project.insert");
+ projectInsertPage.setFreenetInterface(freenetInterface);
+ pages.put(PageType.PAGE_INSERT_PROJECT, projectInsertPage);
+
+ PreferencesPage preferencesPage = new PreferencesPage(wizard);
+ preferencesPage.setName("page.preferences");
+ preferencesPage.setTempDirectory(configuration.getTempDirectory());
+ pages.put(PageType.PAGE_PREFERENCES, preferencesPage);
+ }
+
+ /**
+ * Shows the page with the given type.
+ *
+ * @param pageType
+ * The page type to show
+ */
+ private void showPage(PageType pageType) {
+ wizard.setPreviousEnabled(pageType.ordinal() > 0);
+ wizard.setNextEnabled(pageType.ordinal() < (pages.size() - 1));
+ wizard.setPage(pages.get(pageType));
+ wizard.setTitle(pages.get(pageType).getHeading() + " - jSite");
+ }
+
+ /**
+ * 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,
+ * <code>false</code> otherwise
+ */
+ private boolean saveConfiguration() {
+ NodeManagerPage nodeManagerPage = (NodeManagerPage) pages.get(PageType.PAGE_NODE_MANAGER);
+ configuration.setNodes(nodeManagerPage.getNodes());
+ if (selectedNode != null) {
+ configuration.setSelectedNode(selectedNode);
+ }
+
+ ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
+ configuration.setProjects(projectPage.getProjects());
+
+ PreferencesPage preferencesPage = (PreferencesPage) pages.get(PageType.PAGE_PREFERENCES);
+ configuration.setTempDirectory(preferencesPage.getTempDirectory());
+
+ return configuration.save();
+ }
+
+ /**
+ * Finds a supported locale for the given locale.
+ *
+ * @param forLocale
+ * The locale to find a supported locale for
+ * @return The supported locale that was found, or the default locale if no
+ * supported locale could be found
+ */
+ private Locale findSupportedLocale(Locale forLocale) {
+ for (Locale locale : SUPPORTED_LOCALES) {
+ if (locale.equals(forLocale)) {
+ return locale;
+ }
+ }
+ for (Locale locale : SUPPORTED_LOCALES) {
+ if (locale.getCountry().equals(forLocale.getCountry()) && locale.getLanguage().equals(forLocale.getLanguage())) {
+ return locale;
+ }
+ }
+ for (Locale locale : SUPPORTED_LOCALES) {
+ if (locale.getLanguage().equals(forLocale.getLanguage())) {
+ return locale;
+ }
+ }
+ return SUPPORTED_LOCALES[0];
+ }
+
+ /**
+ * Returns the version.
+ *
+ * @return The version
+ */
+ public static final Version getVersion() {
+ return VERSION;
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Switches the language of the interface to the given locale.
+ *
+ * @param locale
+ * The locale to switch to
+ */
+ private void switchLanguage(Locale locale) {
+ Locale supportedLocale = findSupportedLocale(locale);
+ Action languageAction = languageActions.get(supportedLocale);
+ JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) languageAction.getValue("menuItem");
+ menuItem.setSelected(true);
+ I18n.setLocale(supportedLocale);
+ for (Runnable i18nRunnable : I18nContainer.getInstance()) {
+ try {
+ i18nRunnable.run();
+ } catch (Throwable t) {
+ /* we probably shouldn't swallow this. */
+ }
+ }
+ wizard.setPage(wizard.getPage());
+ configuration.setLocale(supportedLocale);
+ }
+
+ /**
+ * Shows a dialog with general preferences.
+ */
+ private void optionsPreferences() {
+ ((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));
+ ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setUseEarlyEncode(configuration.useEarlyEncode());
+ ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setPriority(configuration.getPriority());
+ ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).setManifestPutter(configuration.getManifestPutter());
+ showPage(PageType.PAGE_PREFERENCES);
+ optionsPreferencesAction.setEnabled(false);
+ wizard.setNextEnabled(true);
+ wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
+ }
+
+ /**
+ * Shows a dialog box that shows the last version that was found by the
+ * {@link UpdateChecker}.
+ */
+ private void showLatestUpdate() {
+ Version latestVersion = updateChecker.getLatestVersion();
+ int versionDifference = latestVersion.compareTo(VERSION);
+ if (versionDifference > 0) {
+ JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.newer.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
+ } else if (versionDifference < 0) {
+ JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.older.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.okay.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+
+ //
+ // INTERFACE ListSelectionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void valueChanged(ListSelectionEvent e) {
+ JList list = (JList) e.getSource();
+ int selectedRow = list.getSelectedIndex();
+ wizard.setNextEnabled(selectedRow > -1);
+ }
+
+ //
+ // INTERFACE WizardListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void wizardNextPressed(TWizard wizard) {
+ String pageName = wizard.getPage().getName();
+ if ("page.node-manager".equals(pageName)) {
+ showPage(PageType.PAGE_PROJECTS);
+ } else if ("page.project".equals(pageName)) {
+ ProjectPage projectPage = (ProjectPage) wizard.getPage();
+ Project project = projectPage.getSelectedProject();
+ if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) {
+ 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.warning.no-path"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ ((ProjectFilesPage) pages.get(PageType.PAGE_PROJECT_FILES)).setProject(project);
+ ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).setProject(project);
+ showPage(PageType.PAGE_PROJECT_FILES);
+ } else if ("page.project.files".equals(pageName)) {
+ ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
+ Project project = projectPage.getSelectedProject();
+ if (selectedNode == null) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.error.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ 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;
+ }
+ 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;
+ }
+ }
+ boolean nodeRunning = false;
+ try {
+ nodeRunning = freenetInterface.isNodePresent();
+ } catch (IOException e) {
+ /* ignore. */
+ }
+ if (!nodeRunning) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.error.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ configuration.save();
+ showPage(PageType.PAGE_INSERT_PROJECT);
+ ProjectInsertPage projectInsertPage = (ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT);
+ String tempDirectory = ((PreferencesPage) pages.get(PageType.PAGE_PREFERENCES)).getTempDirectory();
+ projectInsertPage.setTempDirectory(tempDirectory);
+ projectInsertPage.setUseEarlyEncode(configuration.useEarlyEncode());
+ projectInsertPage.setPriority(configuration.getPriority());
+ projectInsertPage.setManifestPutter(configuration.getManifestPutter());
+ projectInsertPage.startInsert();
+ nodeMenu.setEnabled(false);
+ optionsPreferencesAction.setEnabled(false);
+ } else if ("page.project.insert".equals(pageName)) {
+ ProjectInsertPage projectInsertPage = (ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT);
+ if (projectInsertPage.isRunning()) {
+ projectInsertPage.stopInsert();
+ } else {
+ showPage(PageType.PAGE_PROJECTS);
+ nodeMenu.setEnabled(true);
+ 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.setUseEarlyEncode(preferencesPage.useEarlyEncode());
+ configuration.setPriority(preferencesPage.getPriority());
+ configuration.setManifestPutter(preferencesPage.getManifestPutter());
+ configuration.setConfigurationLocation(preferencesPage.getConfigurationLocation());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void wizardPreviousPressed(TWizard wizard) {
+ String pageName = wizard.getPage().getName();
+ if ("page.project".equals(pageName) || "page.preferences".equals(pageName)) {
+ showPage(PageType.PAGE_NODE_MANAGER);
+ optionsPreferencesAction.setEnabled(true);
+ } else if ("page.project.files".equals(pageName)) {
+ showPage(PageType.PAGE_PROJECTS);
+ } else if ("page.project.insert".equals(pageName)) {
+ showPage(PageType.PAGE_PROJECT_FILES);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void wizardQuitPressed(TWizard wizard) {
+ if (((ProjectPage) pages.get(PageType.PAGE_PROJECTS)).wasUriCopied() || ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).wasUriCopied()) {
+ JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.use-clipboard-now"));
+ }
+ if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), I18n.getMessage("jsite.quit.question.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
+ if (isOverwritingConfiguration() && !originalLocation.equals(configuration.getConfigurationDirectory())) {
+ int overwriteConfigurationAnswer = JOptionPane.showConfirmDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.quit.overwrite-configuration"), configuration.getConfigurationLocator().getFile(configuration.getConfigurationDirectory())), I18n.getMessage("jsite.quit.overwrite-configuration.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
+ if (overwriteConfigurationAnswer == JOptionPane.YES_OPTION) {
+ if (saveConfiguration()) {
+ System.exit(0);
+ }
+ } else if (overwriteConfigurationAnswer == JOptionPane.CANCEL_OPTION) {
+ return;
+ }
+ if (overwriteConfigurationAnswer == JOptionPane.NO_OPTION) {
+ 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);
+ }
+ }
+ }
+
+ //
+ // INTERFACE NodeManagerListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void nodesUpdated(Node[] nodes) {
+ nodeMenu.removeAll();
+ ButtonGroup nodeButtonGroup = new ButtonGroup();
+ Node newSelectedNode = null;
+ for (Node node : nodes) {
+ JRadioButtonMenuItem nodeMenuItem = new JRadioButtonMenuItem(node.getName());
+ nodeMenuItem.putClientProperty("Node", node);
+ nodeMenuItem.addActionListener(this);
+ nodeButtonGroup.add(nodeMenuItem);
+ if (node.equals(selectedNode)) {
+ newSelectedNode = node;
+ nodeMenuItem.setSelected(true);
+ }
+ nodeMenu.add(nodeMenuItem);
+ }
+ nodeMenu.addSeparator();
+ nodeMenu.add(manageNodeAction);
+ selectedNode = newSelectedNode;
+ freenetInterface.setNode(selectedNode);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void nodeSelected(Node node) {
+ for (Component menuItem : nodeMenu.getMenuComponents()) {
+ if (menuItem instanceof JMenuItem) {
+ if (node.equals(((JMenuItem) menuItem).getClientProperty("Node"))) {
+ ((JMenuItem) menuItem).setSelected(true);
+ }
+ }
+ }
+ freenetInterface.setNode(node);
+ selectedNode = node;
+ }
+
+ //
+ // INTERFACE ActionListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void actionPerformed(ActionEvent e) {
+ Object source = e.getSource();
+ if (source instanceof JRadioButtonMenuItem) {
+ JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) source;
+ Node node = (Node) menuItem.getClientProperty("Node");
+ selectedNode = node;
+ freenetInterface.setNode(selectedNode);
+ }
+ }
+
+ //
+ // INTERFACE UpdateListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void foundUpdateData(Version foundVersion, long versionTimestamp) {
+ logger.log(Level.FINEST, "Found version {0} from {1,date}.", new Object[] { foundVersion, versionTimestamp });
+ if (foundVersion.compareTo(VERSION) > 0) {
+ JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.found-version.message"), foundVersion.toString(), new Date(versionTimestamp)), I18n.getMessage("jsite.update-checker.found-version.title"), JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+
+ //
+ // MAIN METHOD
+ //
+
+ /**
+ * Main method that is called by the VM.
+ *
+ * @param args
+ * The command-line arguments
+ */
+ public static void main(String[] args) {
+ /* initialize logger. */
+ Logger logger = Logger.getLogger("de.todesbaum");
+ Handler handler = new ConsoleHandler();
+ logger.addHandler(handler);
+ String configFilename = null;
+ boolean nextIsConfigFilename = false;
+ for (String argument : args) {
+ if (nextIsConfigFilename) {
+ configFilename = argument;
+ nextIsConfigFilename = false;
+ }
+ if ("--help".equals(argument)) {
+ printHelp();
+ return;
+ } else if ("--debug".equals(argument)) {
+ logger.setLevel(Level.ALL);
+ handler.setLevel(Level.ALL);
+ } else if ("--config-file".equals(argument)) {
+ nextIsConfigFilename = true;
+ }
+ }
+ if (nextIsConfigFilename) {
+ System.out.println("--config-file needs parameter!");
+ return;
+ }
+ new Main(configFilename);
+ }
+
+ /**
+ * Prints a small syntax help.
+ */
+ private static void printHelp() {
+ System.out.println("--help\tshows this cruft");
+ System.out.println("--debug\tenables some debug output");
+ System.out.println("--config-file <file>\tuse specified configuration file");
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Version.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.jsite.main;
+
+/**
+ * Container for version information.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public class Version implements Comparable<Version> {
+
+ /** The components of the version information. */
+ private final int[] components;
+
+ /**
+ * Creates a new version container with the given components.
+ *
+ * @param components
+ * The version components
+ */
+ public Version(int... components) {
+ this.components = new int[components.length];
+ System.arraycopy(components, 0, this.components, 0, components.length);
+ }
+
+ /**
+ * Returns the number of version components.
+ *
+ * @return The number of version components
+ */
+ public int size() {
+ return components.length;
+ }
+
+ /**
+ * Returns the version component with the given index.
+ *
+ * @param index
+ * The index of the version component
+ * @return The version component
+ */
+ public int getComponent(int index) {
+ return components[index];
+ }
+
+ /**
+ * Parses a version from the given string.
+ *
+ * @param versionString
+ * The version string to parse
+ * @return The parsed version, or <code>null</code> if the string could not
+ * be parsed
+ */
+ public static Version parse(String versionString) {
+ String[] componentStrings = versionString.split("\\.");
+ int[] components = new int[componentStrings.length];
+ int index = -1;
+ for (String componentString : componentStrings) {
+ try {
+ components[++index] = Integer.parseInt(componentString);
+ } catch (NumberFormatException nfe1) {
+ return null;
+ }
+ }
+ return new Version(components);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder versionString = new StringBuilder();
+ for (int component : components) {
+ if (versionString.length() != 0) {
+ versionString.append('.');
+ }
+ versionString.append(component);
+ }
+ return versionString.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(Version version) {
+ int lessComponents = Math.min(components.length, version.components.length);
+ for (int index = 0; index < lessComponents; index++) {
+ if (version.components[index] == components[index]) {
+ continue;
+ }
+ return components[index] - version.components[index];
+ }
+ return components.length - version.components.length;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Client.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.todesbaum.util.io.StreamCopier.ProgressListener;
+
+/**
+ * A Client executes {@link Command}s over a {@link Connection} to a
+ * {@link Node} and delivers resulting {@link Message}s.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class Client implements ConnectionListener {
+
+ /** The connection this client operates on. */
+ private final Connection connection;
+
+ /** The identifiers the client filters messages for. */
+ private List<String> identifiers = new ArrayList<String>();
+
+ /** The queued messages. */
+ private final List<Message> messageQueue = new ArrayList<Message>();
+
+ /** Whether the client was disconnected. */
+ private boolean disconnected = false;
+
+ /** Whether to catch all messages from the connection. */
+ private boolean catchAll = false;
+
+ /**
+ * Creates a new client that operates on the specified connection.
+ *
+ * @param connection
+ * The connection to operate on
+ */
+ public Client(Connection connection) {
+ this.connection = connection;
+ connection.addConnectionListener(this);
+ }
+
+ /**
+ * Creates a new client that operates on the specified connection and
+ * immediately executes the specified command.
+ *
+ * @param connection
+ * The connection to operate on
+ * @param command
+ * The command to execute
+ * @throws IOException
+ * if an I/O error occurs
+ * @see #execute(Command)
+ */
+ public Client(Connection connection, Command command) throws IOException {
+ this(connection);
+ execute(command);
+ }
+
+ /**
+ * Returns whether this client catches all messages going over the
+ * connection.
+ *
+ * @return <code>true</code> if the client catches all messages,
+ * <code>false</code> otherwise
+ */
+ public boolean isCatchAll() {
+ return catchAll;
+ }
+
+ /**
+ * Sets whether this client catches all messages going over the connection.
+ *
+ * @param catchAll
+ * <code>true</code> if the client should catch all messages,
+ * <code>false</code> otherwise
+ */
+ public void setCatchAll(boolean catchAll) {
+ this.catchAll = catchAll;
+ }
+
+ /**
+ * Executes the specified command. This will also clear the queue of
+ * messages, discarding all messages that resulted from the previous command
+ * and have not yet been read.
+ *
+ * @param command
+ * The command to execute
+ * @throws IOException
+ * if an I/O error occurs
+ * @see #execute(Command, boolean)
+ */
+ public void execute(Command command) throws IOException {
+ execute(command, true);
+ }
+
+ /**
+ * Executes the specified command. This will also clear the queue of
+ * messages, discarding all messages that resulted from the previous
+ * command and have not yet been read.
+ *
+ * @param command
+ * The command to execute
+ * @param progressListener
+ * The progress listener for payload transfers
+ * @throws IOException
+ * if an I/O error occurs
+ * @see #execute(Command, boolean)
+ */
+ public void execute(Command command, ProgressListener progressListener) throws IOException {
+ execute(command, true, progressListener);
+ }
+
+ /**
+ * Executes the specified command and optionally clears the list of
+ * identifiers this clients listens to before starting the command.
+ *
+ * @param command
+ * The command to execute
+ * @param removeExistingIdentifiers
+ * If <code>true</code>, the list of identifiers that this
+ * clients listens to is cleared
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public void execute(Command command, boolean removeExistingIdentifiers) throws IOException {
+ execute(command, removeExistingIdentifiers, null);
+ }
+
+ /**
+ * Executes the specified command and optionally clears the list of
+ * identifiers this clients listens to before starting the command.
+ *
+ * @param command
+ * The command to execute
+ * @param removeExistingIdentifiers
+ * If <code>true</code>, the list of identifiers that this
+ * clients listens to is cleared
+ * @param progressListener
+ * The progress listener for payload transfers
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public void execute(Command command, boolean removeExistingIdentifiers, ProgressListener progressListener) throws IOException {
+ synchronized (messageQueue) {
+ messageQueue.clear();
+ if (removeExistingIdentifiers) {
+ identifiers.clear();
+ }
+ identifiers.add(command.getIdentifier());
+ }
+ connection.execute(command, progressListener);
+ }
+
+ /**
+ * Returns the next message, waiting endlessly for it, if need be. If you
+ * are not sure whether a message will arrive, better use
+ * {@link #readMessage(long)} to only wait for a specific time.
+ *
+ * @return The next message that resulted from the execution of the last
+ * command
+ * @see #readMessage(long)
+ * @see #execute(Command)
+ */
+ public Message readMessage() {
+ return readMessage(0);
+ }
+
+ /**
+ * Returns the next message. If the message queue is currently empty, at
+ * least <code>maxWaitTime</code> milliseconds will be waited for a
+ * message to arrive.
+ *
+ * @param maxWaitTime
+ * The minimum time to wait for a message, in milliseconds
+ * @return The message, or <code>null</code> if no message arrived in time
+ * or the client is currently disconnected
+ * @see #isDisconnected()
+ * @see Object#wait(long)
+ */
+ public Message readMessage(long maxWaitTime) {
+ synchronized (messageQueue) {
+ if (disconnected) {
+ return null;
+ }
+ if (messageQueue.size() == 0) {
+ try {
+ messageQueue.wait(maxWaitTime);
+ } catch (InterruptedException ie1) {
+ }
+ }
+ if (messageQueue.size() > 0) {
+ return messageQueue.remove(0);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether the client is currently disconnected.
+ *
+ * @return <code>true</code> if the client is disconnected,
+ * <code>false</code> otherwise
+ */
+ public boolean isDisconnected() {
+ synchronized (messageQueue) {
+ return disconnected;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void messageReceived(Connection connection, Message message) {
+ synchronized (messageQueue) {
+ if (catchAll || (message.getIdentifier().length() == 0) || identifiers.contains(message.getIdentifier())) {
+ messageQueue.add(message);
+ messageQueue.notify();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void connectionTerminated(Connection connection) {
+ synchronized (messageQueue) {
+ disconnected = true;
+ messageQueue.notify();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ClientGet.java - Copyright © 2008–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Implementation of the “ClientGet” command.
+ *
+ * @author David ‘BombeB Roden <bombe@freenetproject.org>
+ */
+public class ClientGet extends Command {
+
+ private boolean ignoreDataStore;
+ private boolean dataStoreOnly;
+ private String uri;
+ private Verbosity verbosity = Verbosity.NONE;
+ private long maxSize = -1;
+ private long maxTempSize = -1;
+ private int maxRetries = -1;
+ private PriorityClass priorityClass = PriorityClass.INTERACTIVE;
+ private Persistence persistence = Persistence.CONNECTION;
+ private String clientToken;
+ private boolean global = false;
+ private ReturnType returnType = ReturnType.direct;
+ private boolean binaryBlob = false;
+ private String allowedMimeTypes = null;
+ private String filename = null;
+ private String tempFilename = null;
+
+ /**
+ *Creates a new ClientGet command with the given request identifier.
+ *
+ * @param identifier
+ * The request identifier
+ */
+ public ClientGet(String identifier) {
+ super("ClientGet", identifier);
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public boolean isIgnoreDataStore() {
+ return ignoreDataStore;
+ }
+
+ /**
+ * TODO
+ *
+ * @param ignoreDataStore
+ */
+ public void setIgnoreDataStore(boolean ignoreDataStore) {
+ this.ignoreDataStore = ignoreDataStore;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public boolean isDataStoreOnly() {
+ return dataStoreOnly;
+ }
+
+ /**
+ * TODO
+ *
+ * @param dataStoreOnly
+ */
+ public void setDataStoreOnly(boolean dataStoreOnly) {
+ this.dataStoreOnly = dataStoreOnly;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * TODO
+ *
+ * @param uri
+ */
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public Verbosity getVerbosity() {
+ return verbosity;
+ }
+
+ /**
+ * TODO
+ *
+ * @param verbosity
+ */
+ public void setVerbosity(Verbosity verbosity) {
+ this.verbosity = verbosity;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public long getMaxSize() {
+ return maxSize;
+ }
+
+ /**
+ * TODO
+ *
+ * @param maxSize
+ */
+ public void setMaxSize(long maxSize) {
+ this.maxSize = maxSize;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public long getMaxTempSize() {
+ return maxTempSize;
+ }
+
+ /**
+ * TODO
+ *
+ * @param maxTempSize
+ */
+ public void setMaxTempSize(long maxTempSize) {
+ this.maxTempSize = maxTempSize;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ /**
+ * TODO
+ *
+ * @param maxRetries
+ */
+ public void setMaxRetries(int maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public PriorityClass getPriorityClass() {
+ return priorityClass;
+ }
+
+ /**
+ * TODO
+ *
+ * @param priorityClass
+ */
+ public void setPriorityClass(PriorityClass priorityClass) {
+ this.priorityClass = priorityClass;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public Persistence getPersistence() {
+ return persistence;
+ }
+
+ /**
+ * TODO
+ *
+ * @param persistence
+ */
+ public void setPersistence(Persistence persistence) {
+ this.persistence = persistence;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public String getClientToken() {
+ return clientToken;
+ }
+
+ /**
+ * TODO
+ *
+ * @param clientToken
+ */
+ public void setClientToken(String clientToken) {
+ this.clientToken = clientToken;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public boolean isGlobal() {
+ return global;
+ }
+
+ /**
+ * TODO
+ *
+ * @param global
+ */
+ public void setGlobal(boolean global) {
+ this.global = global;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public ReturnType getReturnType() {
+ return returnType;
+ }
+
+ /**
+ * TODO
+ *
+ * @param returnType
+ */
+ public void setReturnType(ReturnType returnType) {
+ this.returnType = returnType;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public boolean isBinaryBlob() {
+ return binaryBlob;
+ }
+
+ /**
+ * TODO
+ *
+ * @param binaryBlob
+ */
+ public void setBinaryBlob(boolean binaryBlob) {
+ this.binaryBlob = binaryBlob;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public String getAllowedMimeTypes() {
+ return allowedMimeTypes;
+ }
+
+ /**
+ * TODO
+ *
+ * @param allowedMimeTypes
+ */
+ public void setAllowedMimeTypes(String allowedMimeTypes) {
+ this.allowedMimeTypes = allowedMimeTypes;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public String getFilename() {
+ return filename;
+ }
+
+ /**
+ * TODO
+ *
+ * @param filename
+ */
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ /**
+ * TODO
+ *
+ * @return
+ */
+ public String getTempFilename() {
+ return tempFilename;
+ }
+
+ /**
+ * TODO
+ *
+ * @param tempFilename
+ */
+ public void setTempFilename(String tempFilename) {
+ this.tempFilename = tempFilename;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ super.write(writer);
+ writer.write("IgnoreDS=" + ignoreDataStore + LINEFEED);
+ writer.write("DSonly=" + dataStoreOnly + LINEFEED);
+ writer.write("URI=" + uri + LINEFEED);
+ writer.write("Verbosity=" + verbosity.getValue() + LINEFEED);
+ if (maxSize > -1) {
+ writer.write("MaxSize=" + maxSize + LINEFEED);
+ }
+ if (maxTempSize > -1) {
+ writer.write("MaxTempSize=" + maxTempSize + LINEFEED);
+ }
+ if (maxRetries >= -1) {
+ writer.write("MaxRetries=" + maxRetries + LINEFEED);
+ }
+ writer.write("PriorityClass=" + priorityClass.getValue() + LINEFEED);
+ writer.write("Persistence=" + persistence.getName() + LINEFEED);
+ if (clientToken != null) {
+ writer.write("ClientToken=" + clientToken + LINEFEED);
+ }
+ writer.write("Global=" + global + LINEFEED);
+ writer.write("BinaryBlob=" + binaryBlob + LINEFEED);
+ if (allowedMimeTypes != null) {
+ writer.write("AllowedMIMETypes=" + allowedMimeTypes + LINEFEED);
+ }
+ if (returnType == ReturnType.disk) {
+ writer.write("Filename=" + filename + LINEFEED);
+ if (tempFilename != null) {
+ writer.write("TempFilename=" + tempFilename + LINEFEED);
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ClientHello.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Implementation of the <code>ClientHello</code> command. This command must
+ * be sent as the first command on a connection ({@link de.todesbaum.util.freenet.fcp2.Connection#connect()}
+ * takes care of that) and must not be sent afterwards.
+ * <p>
+ * The node can answer with the following messages: <code>NodeHello</code>.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class ClientHello extends Command {
+
+ /** The name of the client. */
+ protected String name;
+
+ /** The version of the FCP protocol the client expects. */
+ protected String expectedVersion = "2.0";
+
+ /**
+ * Creates a new <code>ClientHello</code> command.
+ */
+ public ClientHello() {
+ super("ClientHello", "ClientHello-" + System.currentTimeMillis());
+ }
+
+ /**
+ * Returns the value of the <code>ExpectedVersion</code> parameter of this
+ * command. At the moment this value is not used by the node but in the
+ * future this may be used to enforce certain node versions.
+ *
+ * @return The expected version
+ */
+ public String getExpectedVersion() {
+ return expectedVersion;
+ }
+
+ /**
+ * Sets the value of the <code>ExpectedVersion</code> parameter of this
+ * command. At the moment this value is not used by the node but in the
+ * future this may be used to enforce certain node versions.
+ *
+ * @param expectedVersion
+ * The expected version
+ */
+ public void setExpectedVersion(String expectedVersion) {
+ this.expectedVersion = expectedVersion;
+ }
+
+ /**
+ * Returns the name of the client that is connecting.
+ *
+ * @return The name of the client
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the client that is connecting.
+ *
+ * @param name
+ * The name of the client
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ writer.write("Name=" + name + LINEFEED);
+ writer.write("ExpectedVersion=" + expectedVersion + LINEFEED);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ClientPut.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all put requests. It contains all parameters that put
+ * requests have in common.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public abstract class ClientPut extends Command {
+
+ /** The URI of this request. */
+ protected final String uri;
+
+ /** The client token of this request. */
+ protected String clientToken = null;
+
+ /** Whether this request should only create a CHK. */
+ protected boolean getCHKOnly = false;
+
+ /** Whether this request is a global request. */
+ protected boolean global = false;
+
+ /** Whether the node should not try to compress the file. */
+ protected boolean dontCompress = false;
+
+ /** The maximum number of retries of this command. */
+ protected int maxRetries = 0;
+
+ /** Whether to generate the keys early. */
+ protected boolean earlyEncode = false;
+
+ /** The persistence of this request. */
+ protected Persistence persistence = Persistence.CONNECTION;
+
+ /** The priority class of this request. */
+ protected PriorityClass priorityClass = PriorityClass.INTERACTIVE;
+
+ /** The verbosiry of this request. */
+ protected Verbosity verbosity = Verbosity.NONE;
+
+ /**
+ * Creates a new put request with the specified name, identifier and URI.
+ *
+ * @param name
+ * The name of this request
+ * @param identifier
+ * The identifier of this request
+ * @param uri
+ * The URI of this request
+ */
+ protected ClientPut(String name, String identifier, String uri) {
+ super(name, identifier);
+ this.uri = uri;
+ }
+
+ /**
+ * Returns whether the node should not try to compress the data.
+ *
+ * @return <code>true</code> if the node should <strong>not</strong> try
+ * to compress the data
+ */
+ public boolean isDontCompress() {
+ return dontCompress;
+ }
+
+ /**
+ * Sets whether the node should not try to compress the data. A client might
+ * set this hint on data that is clearly not compressible, like MPEG audio
+ * files, JPEG or PNG images, highly compressed movies, or compressed
+ * archives like ZIP files. Otherwise the node will try to compress the file
+ * which -- depending on the size of the data -- might take a lot of time
+ * and memory.
+ *
+ * @param dontCompress
+ * <code>true</code> if the node should <strong>not</strong>
+ * try to compress the data
+ */
+ public void setDontCompress(boolean dontCompress) {
+ this.dontCompress = dontCompress;
+ }
+
+ /**
+ * Returns whether this request should only return the CHK of the data.
+ * @return Whether this request should only return the CHK of the data
+ */
+ public boolean isGetCHKOnly() {
+ return getCHKOnly;
+ }
+
+ /**
+ * Sets whether this request should only return the CHK of the data.
+ * @param getCHKOnly
+ * <code>true</code> if this request should only return the CHK of the data
+ */
+ public void setGetCHKOnly(boolean getCHKOnly) {
+ this.getCHKOnly = getCHKOnly;
+ }
+
+ /**
+ * Returns whether this request is a global request.
+ * @return <code>true</code> if this request is a global request, <code>false</code> otherwise
+ */
+ public boolean isGlobal() {
+ return global;
+ }
+
+ /**
+ * Sets whether this request is a global request.
+ * @param global
+ * <code>true</code> if this request is a global request, <code>false</code> otherwise
+ */
+ public void setGlobal(boolean global) {
+ this.global = global;
+ }
+
+ /**
+ * Returns the maximum number of retries of this request.
+ * @return The maximum number of retries of this request
+ */
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ /**
+ * Sets the maximum number of retries of this request
+ * @param maxRetries
+ * The maximum number of retries of this request
+ */
+ public void setMaxRetries(int maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ /**
+ * Returns whether the data should be encoded early to generate the final
+ * key as fast as possible.
+ *
+ * @return {@code true} if the key should be generated early, {@code false}
+ * otherwise
+ */
+ public boolean isEarlyEncode() {
+ return earlyEncode;
+ }
+
+ /**
+ * Sets whether the data should be encoded early to generate the final key
+ * as fast as possible.
+ *
+ * @param earlyEncode
+ * {@code true} if the key should be generated early, {@code
+ * false} otherwise
+ */
+ public void setEarlyEncode(boolean earlyEncode) {
+ this.earlyEncode = earlyEncode;
+ }
+
+ /**
+ * Returns the priority class of this request.
+ * @return The priority class of this request
+ */
+ public PriorityClass getPriorityClass() {
+ return priorityClass;
+ }
+
+ /**
+ * Sets the priority class of this request.
+ * @param priorityClass
+ * The priority class of this request
+ */
+ public void setPriorityClass(PriorityClass priorityClass) {
+ this.priorityClass = priorityClass;
+ }
+
+ /**
+ * Returns the verbosity of this request.
+ * @return The verbosity of this request
+ */
+ public Verbosity getVerbosity() {
+ return verbosity;
+ }
+
+ /**
+ * Sets the verbosity of this request.
+ * @param verbosity
+ * The verbosity of this request
+ */
+ public void setVerbosity(Verbosity verbosity) {
+ this.verbosity = verbosity;
+ }
+
+ /**
+ * Returns the URI of this request
+ * @return The URI of this request.
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ super.write(writer);
+ writer.write("URI=" + uri + LINEFEED);
+ if (verbosity != null)
+ writer.write("Verbosity=" + verbosity.getValue() + LINEFEED);
+ if (maxRetries != 0)
+ writer.write("MaxRetries=" + maxRetries + LINEFEED);
+ writer.write("EarlyEncode=" + earlyEncode);
+ if (priorityClass != null)
+ writer.write("PriorityClass=" + priorityClass.getValue() + LINEFEED);
+ writer.write("GetCHKOnly=" + getCHKOnly + LINEFEED);
+ writer.write("Global=" + global + LINEFEED);
+ writer.write("DontCompress=" + dontCompress + LINEFEED);
+ if (clientToken != null)
+ writer.write("ClientToken=" + clientToken + LINEFEED);
+ if (persistence != null)
+ writer.write("Persistence=" + persistence.getName() + LINEFEED);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ClientPutComplexDir.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.todesbaum.util.io.Closer;
+
+/**
+ * Implementation of the <code>ClientPutComplexDir</code> command. This command
+ * can be used to insert directories that do not exist on disk.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class ClientPutComplexDir extends ClientPutDir<ClientPutComplexDir> {
+
+ /** The file entries of this directory. */
+ private List<FileEntry> fileEntries = new ArrayList<FileEntry>();
+
+ /** Whether this request has payload. */
+ private boolean hasPayload = false;
+
+ /** The input streams for the payload. */
+ private File payloadFile;
+
+ /** The total number of bytes of the payload. */
+ private long payloadLength = 0;
+
+ /** The temp directory to use. */
+ private final String tempDirectory;
+
+ /**
+ * Creates a new <code>ClientPutComplexDir</code> command with the specified
+ * identifier and URI.
+ *
+ * @param identifier
+ * The identifier of the command
+ * @param uri
+ * The URI of the command
+ */
+ public ClientPutComplexDir(String identifier, String uri) {
+ this(identifier, uri, null);
+ }
+
+ /**
+ * Creates a new <code>ClientPutComplexDir</code> command with the specified
+ * identifier and URI.
+ *
+ * @param identifier
+ * The identifier of the command
+ * @param uri
+ * The URI of the command
+ * @param tempDirectory
+ * The temp directory to use, or {@code null} to use the default
+ * temp directory
+ */
+ public ClientPutComplexDir(String identifier, String uri, String tempDirectory) {
+ super("ClientPutComplexDir", identifier, uri);
+ this.tempDirectory = tempDirectory;
+ }
+
+ /**
+ * Adds a file to the directory inserted by this request.
+ *
+ * @param fileEntry
+ * The file entry to add to the directory
+ * @throws IOException
+ * if an I/O error occurs when creating the payload stream
+ */
+ public void addFileEntry(FileEntry fileEntry) throws IOException {
+ if (fileEntry instanceof DirectFileEntry) {
+ if (payloadFile == null) {
+ try {
+ payloadFile = File.createTempFile("payload", ".dat", (tempDirectory != null) ? new File(tempDirectory) : null);
+ payloadFile.deleteOnExit();
+ } catch (IOException e) {
+ /* ignore. */
+ }
+ }
+ if (payloadFile != null) {
+ InputStream payloadInputStream = ((DirectFileEntry) fileEntry).getDataInputStream();
+ FileOutputStream payloadOutputStream = null;
+ try {
+ payloadOutputStream = new FileOutputStream(payloadFile, true);
+ byte[] buffer = new byte[65536];
+ int read = 0;
+ while ((read = payloadInputStream.read(buffer)) != -1) {
+ payloadOutputStream.write(buffer, 0, read);
+ }
+ payloadOutputStream.flush();
+ fileEntries.add(fileEntry);
+ } catch (IOException ioe1) {
+ payloadFile.delete();
+ throw ioe1;
+ } finally {
+ Closer.close(payloadOutputStream);
+ Closer.close(payloadInputStream);
+ }
+ }
+ } else {
+ fileEntries.add(fileEntry);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ super.write(writer);
+ int fileIndex = 0;
+ for (FileEntry fileEntry : fileEntries) {
+ writer.write("Files." + fileIndex + ".Name=" + fileEntry.getFilename() + LINEFEED);
+ if (fileEntry.getContentType() != null) {
+ writer.write("Files." + fileIndex + ".Metadata.ContentType=" + fileEntry.getContentType() + LINEFEED);
+ }
+ writer.write("Files." + fileIndex + ".UploadFrom=" + fileEntry.getName() + LINEFEED);
+ if (fileEntry instanceof DirectFileEntry) {
+ hasPayload = true;
+ writer.write("Files." + fileIndex + ".DataLength=" + ((DirectFileEntry) fileEntry).getDataLength() + LINEFEED);
+ payloadLength += ((DirectFileEntry) fileEntry).getDataLength();
+ } else if (fileEntry instanceof DiskFileEntry) {
+ writer.write("Files." + fileIndex + ".Filename=" + ((DiskFileEntry) fileEntry).getFilename() + LINEFEED);
+ } else if (fileEntry instanceof RedirectFileEntry) {
+ writer.write("Files." + fileIndex + ".TargetURI=" + ((RedirectFileEntry) fileEntry).getTargetURI() + LINEFEED);
+ }
+ fileIndex++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean hasPayload() {
+ return hasPayload;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected long getPayloadLength() {
+ return payloadLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected InputStream getPayload() {
+ if (payloadFile != null) {
+ try {
+ return new FileInputStream(payloadFile);
+ } catch (FileNotFoundException e) {
+ /* shouldn't occur. */
+ }
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ClientPutDir.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all put requests that insert a directory.
+ *
+ * @param <C>
+ * The type of the “ClientPutDir” command
+ * @author David Roden <droden@gmail.com>
+ */
+public class ClientPutDir<C extends ClientPutDir<?>> extends ClientPut {
+
+ /**
+ * All possible manifest putters. Manifest putters are used to distribute
+ * files of a directory insert to different containers, depending on size,
+ * type, and other factors.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+ public enum ManifestPutter {
+
+ /**
+ * Use the “simple” manifest putter. Despite its name this is currently
+ * the default manifest putter.
+ */
+ SIMPLE("simple"),
+
+ /** Use the “default” manifest putter. */
+ DEFAULT("default");
+
+ /** The name of the manifest putter. */
+ private final String name;
+
+ /**
+ * Creates a new manifest putter.
+ *
+ * @param name
+ * The name of the manifest putter
+ */
+ private ManifestPutter(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of the manifest putter.
+ *
+ * @return The name of the manifest putter
+ */
+ public String getName() {
+ return name;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return name.substring(0, 1).toUpperCase() + name.substring(1);
+ }
+
+ }
+
+ /** The default file of the directory. */
+ protected String defaultName;
+
+ /** The manifest putter to use. */
+ private ManifestPutter manifestPutter;
+
+ /**
+ * Creates a new request with the specified name, identifier, and URI.
+ *
+ * @param name
+ * The name of the request
+ * @param identifier
+ * The identifier of the request
+ * @param uri
+ * The URI of the request
+ */
+ public ClientPutDir(String name, String identifier, String uri) {
+ super(name, identifier, uri);
+ }
+
+ /**
+ * Returns the default name of the directory.
+ *
+ * @return The default name of the directory
+ */
+ public String getDefaultName() {
+ return defaultName;
+ }
+
+ /**
+ * Sets the default name of the directory. The default name of a directory
+ * is the name of the file that will be delivered if the directory was
+ * requested without a filename. It's about the same as the
+ * <code>index.html</code> file that gets delivered if you only request a
+ * directory from a webserver.
+ *
+ * @param defaultName
+ * The default name of the directory
+ */
+ public void setDefaultName(String defaultName) {
+ this.defaultName = defaultName;
+ }
+
+ /**
+ * Returns the current manifest putter.
+ *
+ * @return The current manifest putter (may be {@code null})
+ */
+ public ManifestPutter getManifestPutter() {
+ return manifestPutter;
+ }
+
+ /**
+ * Sets the manifest putter for the “ClientPutDir” command. If {@code null}
+ * is given the node will choose a manifest putter.
+ *
+ * @param manifestPutter
+ * The manifest putter to use for the command (may be
+ * {@code null})
+ * @return This ClientPutDir command
+ */
+ @SuppressWarnings("unchecked")
+ public C setManifestPutter(ManifestPutter manifestPutter) {
+ this.manifestPutter = manifestPutter;
+ return (C) this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void write(Writer writer) throws IOException {
+ super.write(writer);
+ if (defaultName != null)
+ writer.write("DefaultName=" + defaultName + LINEFEED);
+ if (manifestPutter != null) {
+ writer.write("ManifestPutter=" + manifestPutter.getName() + LINEFEED);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Command.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+
+/**
+ * Abstract base class for all commands.
+ * <p>
+ * In addition to the replies listed at the type comment of each specific
+ * command the node can <strong>always</strong> send the following messages:
+ * <code>ProtocolError</code> (if this library screws up),
+ * <code>CloseConnectionDuplicateClientName</code> (if a client with the same
+ * name of the {@link de.todesbaum.util.freenet.fcp2.Connection} connects). So
+ * when receiving messages from the node you should always be prepared for
+ * something you did not expect.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public abstract class Command {
+
+ /** The line feed sequence used by the library. */
+ protected static final String LINEFEED = "\r\n";
+
+ /**
+ * The name of the command. The name is sent to the node so it can not be
+ * chosen arbitrarily!
+ */
+ private final String commandName;
+
+ /**
+ * The identifier of the command. This identifier is used to identify
+ * replies that are caused by a command.
+ */
+ private final String identifier;
+
+ /**
+ * Creates a new command with the specified name and identifier.
+ *
+ * @param name
+ * The name of the command
+ * @param identifier
+ * The identifier of the command
+ */
+ public Command(String name, String identifier) {
+ this.commandName = name;
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns the name of this command.
+ *
+ * @return The name of this command
+ */
+ public String getCommandName() {
+ return commandName;
+ }
+
+ /**
+ * Return the identifier of this command.
+ *
+ * @return The identifier of this command
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Writes all parameters to the specified writer.
+ * <p>
+ * <strong>NOTE:</strong> Subclasses of Command <strong>must</strong> call
+ * <code>super.write(writer)</code> before or after writing their own
+ * parameters!
+ *
+ * @param writer
+ * The stream to write the parameters to
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ protected void write(Writer writer) throws IOException {
+ if (identifier != null)
+ writer.write("Identifier=" + identifier + LINEFEED);
+ }
+
+ /**
+ * Returns whether this command has payload to send after the message.
+ * Subclasses need to return <code>true</code> here if they need to send
+ * payload after the message.
+ *
+ * @return <code>true</code> if this command has payload to send,
+ * <code>false</code> otherwise
+ */
+ protected boolean hasPayload() {
+ return false;
+ }
+
+ /**
+ * Returns the payload of this command as an {@link InputStream}. This
+ * method is never called if {@link #hasPayload()} returns
+ * <code>false</code>.
+ *
+ * @return The payload of this command
+ */
+ protected InputStream getPayload() {
+ return null;
+ }
+
+ /**
+ * Returns the length of the payload. This method is never called if
+ * {@link #hasPayload()} returns <code>false</code>.
+ *
+ * @return The length of the payload
+ */
+ protected long getPayloadLength() {
+ return -1;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Connection.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.Socket;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.todesbaum.util.io.Closer;
+import de.todesbaum.util.io.LineInputStream;
+import de.todesbaum.util.io.StreamCopier;
+import de.todesbaum.util.io.StreamCopier.ProgressListener;
+import de.todesbaum.util.io.TempFileInputStream;
+
+/**
+ * A physical connection to a Freenet node.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class Connection {
+
+ /** The listeners that receive events from this connection. */
+ private List<ConnectionListener> connectionListeners = new ArrayList<ConnectionListener>();
+
+ /** The node this connection is connected to. */
+ private final Node node;
+
+ /** The name of this connection. */
+ private final String name;
+
+ /** The network socket of this connection. */
+ private Socket nodeSocket;
+
+ /** The input stream that reads from the socket. */
+ private InputStream nodeInputStream;
+
+ /** The output stream that writes to the socket. */
+ private OutputStream nodeOutputStream;
+
+ /** The thread that reads from the socket. */
+ private NodeReader nodeReader;
+
+ /** A writer for the output stream. */
+ private Writer nodeWriter;
+
+ /** The NodeHello message sent by the node on connect. */
+ protected Message nodeHello;
+
+ /** The temp directory to use. */
+ private String tempDirectory;
+
+ /**
+ * Creates a new connection to the specified node with the specified name.
+ *
+ * @param node
+ * The node to connect to
+ * @param name
+ * The name of this connection
+ */
+ public Connection(Node node, String name) {
+ this.node = node;
+ this.name = name;
+ }
+
+ /**
+ * Adds a listener that gets notified on connection events.
+ *
+ * @param connectionListener
+ * The listener to add
+ */
+ public void addConnectionListener(ConnectionListener connectionListener) {
+ connectionListeners.add(connectionListener);
+ }
+
+ /**
+ * Removes a listener from the list of registered listeners. Only the first
+ * matching listener is removed.
+ *
+ * @param connectionListener
+ * The listener to remove
+ * @see List#remove(java.lang.Object)
+ */
+ public void removeConnectionListener(ConnectionListener connectionListener) {
+ connectionListeners.remove(connectionListener);
+ }
+
+ /**
+ * Notifies listeners about a received message.
+ *
+ * @param message
+ * The received message
+ */
+ protected void fireMessageReceived(Message message) {
+ for (ConnectionListener connectionListener : connectionListeners) {
+ connectionListener.messageReceived(this, message);
+ }
+ }
+
+ /**
+ * Notifies listeners about the loss of the connection.
+ */
+ protected void fireConnectionTerminated() {
+ for (ConnectionListener connectionListener : connectionListeners) {
+ connectionListener.connectionTerminated(this);
+ }
+ }
+
+ /**
+ * Returns the name of the connection.
+ *
+ * @return The name of the connection
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the temp directory to use for creation of temporary files.
+ *
+ * @param tempDirectory
+ * The temp directory to use, or {@code null} to use the default
+ * temp directory
+ */
+ public void setTempDirectory(String tempDirectory) {
+ this.tempDirectory = tempDirectory;
+ }
+
+ /**
+ * Connects to the node.
+ *
+ * @return <code>true</code> if the connection succeeded and the node
+ * returned a NodeHello message
+ * @throws IOException
+ * if an I/O error occurs
+ * @see #getNodeHello()
+ */
+ public synchronized boolean connect() throws IOException {
+ nodeSocket = null;
+ nodeInputStream = null;
+ nodeOutputStream = null;
+ nodeWriter = null;
+ nodeReader = null;
+ try {
+ nodeSocket = new Socket(node.getHostname(), node.getPort());
+ nodeSocket.setReceiveBufferSize(65535);
+ nodeInputStream = nodeSocket.getInputStream();
+ nodeOutputStream = nodeSocket.getOutputStream();
+ nodeWriter = new OutputStreamWriter(nodeOutputStream, Charset.forName("UTF-8"));
+ nodeReader = new NodeReader(nodeInputStream);
+ Thread nodeReaderThread = new Thread(nodeReader);
+ nodeReaderThread.setDaemon(true);
+ nodeReaderThread.start();
+ ClientHello clientHello = new ClientHello();
+ clientHello.setName(name);
+ clientHello.setExpectedVersion("2.0");
+ execute(clientHello);
+ synchronized (this) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ return nodeHello != null;
+ } catch (IOException ioe1) {
+ disconnect();
+ throw ioe1;
+ }
+ }
+
+ /**
+ * Returns whether this connection is still connected to the node.
+ *
+ * @return <code>true</code> if this connection is still valid,
+ * <code>false</code> otherwise
+ */
+ public boolean isConnected() {
+ return (nodeHello != null) && (nodeSocket != null) && (nodeSocket.isConnected());
+ }
+
+ /**
+ * Returns the NodeHello message the node sent on connection.
+ *
+ * @return The NodeHello message of the node
+ */
+ public Message getNodeHello() {
+ return nodeHello;
+ }
+
+ /**
+ * Disconnects from the node.
+ */
+ public void disconnect() {
+ Closer.close(nodeWriter);
+ nodeWriter = null;
+ Closer.close(nodeOutputStream);
+ nodeOutputStream = null;
+ Closer.close(nodeInputStream);
+ nodeInputStream = null;
+ nodeInputStream = null;
+ Closer.close(nodeSocket);
+ nodeSocket = null;
+ synchronized (this) {
+ notify();
+ }
+ fireConnectionTerminated();
+ }
+
+ /**
+ * Executes the specified command.
+ *
+ * @param command
+ * The command to execute
+ * @throws IllegalStateException
+ * if the connection is not connected
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public synchronized void execute(Command command) throws IllegalStateException, IOException {
+ execute(command, null);
+ }
+
+ /**
+ * Executes the specified command.
+ *
+ * @param command
+ * The command to execute
+ * @param progressListener
+ * A progress listener for a payload transfer
+ * @throws IllegalStateException
+ * if the connection is not connected
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public synchronized void execute(Command command, ProgressListener progressListener) throws IllegalStateException, IOException {
+ if (nodeSocket == null) {
+ throw new IllegalStateException("connection is not connected");
+ }
+ nodeWriter.write(command.getCommandName() + Command.LINEFEED);
+ command.write(nodeWriter);
+ nodeWriter.write("EndMessage" + Command.LINEFEED);
+ nodeWriter.flush();
+ if (command.hasPayload()) {
+ InputStream payloadInputStream = null;
+ try {
+ payloadInputStream = command.getPayload();
+ StreamCopier.copy(payloadInputStream, nodeOutputStream, command.getPayloadLength(), progressListener);
+ } finally {
+ Closer.close(payloadInputStream);
+ }
+ nodeOutputStream.flush();
+ }
+ }
+
+ /**
+ * The reader thread for this connection. This is essentially a thread that
+ * reads lines from the node, creates messages from them and notifies
+ * listeners about the messages.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+ private class NodeReader implements Runnable {
+
+ /** The input stream to read from. */
+ @SuppressWarnings("hiding")
+ private InputStream nodeInputStream;
+
+ /**
+ * Creates a new reader that reads from the specified input stream.
+ *
+ * @param nodeInputStream
+ * The input stream to read from
+ */
+ public NodeReader(InputStream nodeInputStream) {
+ this.nodeInputStream = nodeInputStream;
+ }
+
+ /**
+ * Main loop of the reader. Lines are read and converted into
+ * {@link Message} objects.
+ */
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ LineInputStream nodeReader = null;
+ try {
+ nodeReader = new LineInputStream(nodeInputStream);
+ String line = "";
+ Message message = null;
+ while (line != null) {
+ line = nodeReader.readLine();
+ // System.err.println("> " + line);
+ if (line == null) {
+ break;
+ }
+ if (message == null) {
+ message = new Message(line);
+ continue;
+ }
+ if ("Data".equals(line)) {
+ /* need to read message from stream now */
+ File tempFile = null;
+ try {
+ tempFile = File.createTempFile("fcpv2", "data", (tempDirectory != null) ? new File(tempDirectory) : null);
+ tempFile.deleteOnExit();
+ FileOutputStream tempFileOutputStream = new FileOutputStream(tempFile);
+ long dataLength = Long.parseLong(message.get("DataLength"));
+ StreamCopier.copy(nodeInputStream, tempFileOutputStream, dataLength);
+ tempFileOutputStream.close();
+ message.setPayloadInputStream(new TempFileInputStream(tempFile));
+ } catch (IOException ioe1) {
+ ioe1.printStackTrace();
+ }
+ }
+ if ("Data".equals(line) || "EndMessage".equals(line)) {
+ if (message.getName().equals("NodeHello")) {
+ nodeHello = message;
+ synchronized (Connection.this) {
+ Connection.this.notify();
+ }
+ } else {
+ fireMessageReceived(message);
+ }
+ message = null;
+ continue;
+ }
+ int equalsPosition = line.indexOf('=');
+ if (equalsPosition > -1) {
+ String key = line.substring(0, equalsPosition).trim();
+ String value = line.substring(equalsPosition + 1).trim();
+ if (key.equals("Identifier")) {
+ message.setIdentifier(value);
+ } else {
+ message.put(key, value);
+ }
+ continue;
+ }
+ /* skip lines consisting of whitespace only */
+ if (line.trim().length() == 0) {
+ continue;
+ }
+ /* if we got here, some error occured! */
+ throw new IOException("Unexpected line: " + line);
+ }
+ } catch (IOException ioe1) {
+ // ioe1.printStackTrace();
+ } finally {
+ if (nodeReader != null) {
+ try {
+ nodeReader.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ if (nodeInputStream != null) {
+ try {
+ nodeInputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+ Connection.this.disconnect();
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * jSite - ConnectionListener.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.util.EventListener;
+
+/**
+ * Interface for clients that want to be notified when a message was received.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public interface ConnectionListener extends EventListener {
+
+ /**
+ * Notifies a client that a message was received.
+ *
+ * @param connection
+ * The connection the message was received on
+ * @param message
+ * The message that was received
+ */
+ public void messageReceived(Connection connection, Message message);
+
+ /**
+ * Notifies a client that the connection to the node has been lost.
+ *
+ * @param connection
+ * The connection that was lost
+ */
+ public void connectionTerminated(Connection connection);
+
+}
--- /dev/null
+/*
+ * jSite - DirectFileEntry.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * A {@link FileEntry} that sends its payload directly to the node, using the
+ * existing FCP connection.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class DirectFileEntry extends FileEntry {
+
+ /** The input stream to read the data for this file from. */
+ private final InputStream dataInputStream;
+
+ /** The length of the data. */
+ private final long dataLength;
+
+ /**
+ * Creates a new FileEntry with the specified name and content type that
+ * gets its data from the specified byte array.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file
+ * @param dataBytes
+ * The content of the file
+ */
+ public DirectFileEntry(String filename, String contentType, byte[] dataBytes) {
+ this(filename, contentType, new ByteArrayInputStream(dataBytes), dataBytes.length);
+ }
+
+ /**
+ * Creates a new FileEntry with the specified name and content type that
+ * gets its data from the specified input stream.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file
+ * @param dataInputStream
+ * The input stream to read the content from
+ * @param dataLength
+ * The length of the data input stream
+ */
+ public DirectFileEntry(String filename, String contentType, InputStream dataInputStream, long dataLength) {
+ super(filename, contentType);
+ this.dataInputStream = dataInputStream;
+ this.dataLength = dataLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return "direct";
+ }
+
+ /**
+ * Returns the input stream for the file's content.
+ *
+ * @return The input stream for the file's content
+ */
+ public InputStream getDataInputStream() {
+ return dataInputStream;
+ }
+
+ /**
+ * Returns the length of this file's content.
+ *
+ * @return The length of this file's content
+ */
+ public long getDataLength() {
+ return dataLength;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite - DiskFileEntry.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * A {@link FileEntry} that reads the content from a file on the disk.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class DiskFileEntry extends FileEntry {
+
+ /** The local file name. */
+ private final String localFilename;
+
+ /**
+ * Creates a new {@link FileEntry} with the specified name and content type
+ * that is read from the file specified by <code>localFilename</code>.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file
+ * @param localFilename
+ * The name of the local file that holds the content of the file
+ * to insert
+ */
+ public DiskFileEntry(String filename, String contentType, String localFilename) {
+ super(filename, contentType);
+ this.localFilename = localFilename;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return "disk";
+ }
+
+ /**
+ * Returns the name of the local file that holds the content for this file.
+ *
+ * @return The name of the local file
+ */
+ public String getLocalFilename() {
+ return localFilename;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite - FileEntry.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * Abstract base class of file entries that are used in the
+ * {@link de.todesbaum.util.freenet.fcp2.ClientPutComplexDir} command to define
+ * the files of an insert.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public abstract class FileEntry {
+
+ /** The name of the file. */
+ private final String filename;
+
+ /** The content type of the file. */
+ private final String contentType;
+
+ /**
+ * Creates a new file entry with the specified name and content type. The
+ * content type should be a standard MIME type with an additional charset
+ * specification for text-based types.
+ *
+ * @param filename
+ * The name of the file
+ * @param contentType
+ * The content type of the file, e.g.
+ * <code>"application/x-tar"</code> or
+ * <code>"text/html; charset=iso8859-15"</code>
+ */
+ protected FileEntry(String filename, String contentType) {
+ this.filename = filename;
+ this.contentType = contentType;
+ }
+
+ /**
+ * Returns the name of this entry's type. Can be one of <code>direct</code>,
+ * <code>disk</code>, or <code>redirect</code>. This method is
+ * implemented by the subclasses {@link DirectFileEntry},
+ * {@link DiskFileEntry}, and {@link RedirectFileEntry}, respectively.
+ *
+ * @return The name of this entry's type
+ */
+ public abstract String getName();
+
+ /**
+ * Returns the content type of this file.
+ *
+ * @return The content type of this file
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ /**
+ * Returns the name of this file.
+ *
+ * @return The name of this file
+ */
+ public String getFilename() {
+ return filename;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite - GenerateSSK.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * Implementation of the <code>GenerateSSK</code> command.
+ * <p>
+ * The node can answer with the following messages: <code>SSKKeypair</code>.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class GenerateSSK extends Command {
+
+ /**
+ * Creates a new <code>GenerateSSK</code> request.
+ */
+ public GenerateSSK() {
+ super("GenerateSSK", null);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Message.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Contains replies sent by the Freenet node. A message always has a name, and
+ * most of the messages also have an identifier which binds it to a specific
+ * command. Exceptions are among others <code>NodeHello</code>,
+ * <code>SSKKeypair</code>, and <code>EndListPersistentRequests</code>.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ * @see de.todesbaum.util.freenet.fcp2.Client
+ */
+public class Message {
+
+ /** The name of this message. */
+ private final String name;
+
+ /** The identifier of this message. */
+ private String identifier = "";
+
+ /** The parameters of this message. */
+ private Map<String, String> parameters = new HashMap<String, String>();
+
+ /** The payload. */
+ private InputStream payloadInputStream;
+
+ /**
+ * Creates a new message with the specified name.
+ *
+ * @param name
+ * The name of this message
+ */
+ public Message(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the identifier of this message.
+ *
+ * @return The identifier
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Sets the identifier of this message.
+ *
+ * @param identifier
+ * The identifier of this message
+ */
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns the name of this message.
+ *
+ * @return The name of this message
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Tests whether this message contains the parameter with the specified key.
+ * Key names are compared ignoring case.
+ *
+ * @param key
+ * The name of the parameter
+ * @return <code>true</code> if this parameter exists in this message,
+ * <code>false</code> otherwise
+ */
+ public boolean containsKey(String key) {
+ return parameters.containsKey(key.toLowerCase());
+ }
+
+ /**
+ * Returns all parameters of this message. The keys of the entries are all
+ * lower case so if you want to match the parameter names you have to watch
+ * out.
+ *
+ * @return All parameters of this message
+ */
+ public Set<Entry<String, String>> entrySet() {
+ return parameters.entrySet();
+ }
+
+ /**
+ * Returns the value of the parameter with the name specified by
+ * <code>key</code>.
+ *
+ * @param key
+ * The name of the parameter
+ * @return The value of the parameter
+ */
+ public String get(String key) {
+ return parameters.get(key.toLowerCase());
+ }
+
+ /**
+ * Stores the specified value as parameter with the name specified by
+ * <code>key</code>.
+ *
+ * @param key
+ * The name of the parameter
+ * @param value
+ * The value of the parameter
+ * @return The previous value, or <code>null</code> if there was no
+ * previous value
+ */
+ public String put(String key, String value) {
+ return parameters.put(key.toLowerCase(), value);
+ }
+
+ /**
+ * Returns the number of parameters in this message.
+ *
+ * @return The number of parameters
+ */
+ public int size() {
+ return parameters.size();
+ }
+
+ /**
+ * @return Returns the payloadInputStream.
+ */
+ public InputStream getPayloadInputStream() {
+ return payloadInputStream;
+ }
+
+ /**
+ * @param payloadInputStream
+ * The payloadInputStream to set.
+ */
+ public void setPayloadInputStream(InputStream payloadInputStream) {
+ this.payloadInputStream = payloadInputStream;
+ }
+
+ /**
+ * Returns a textual representation of this message, containing its name,
+ * the identifier, and the parameters.
+ *
+ * @return A textual representation of this message
+ */
+ @Override
+ public String toString() {
+ return name + "[identifier=" + identifier + ",parameters=" + parameters.toString() + "]";
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Node.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * Contains the hostname and port number of the Freenet node.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class Node {
+
+ /** The default port of FCPv2. */
+ public static final int DEFAULT_PORT = 9481;
+
+ /** The hostname of the node. */
+ protected String hostname;
+
+ /** The port number of the node. */
+ protected int port;
+
+ /**
+ * Creates a new node with the specified hostname and the default port
+ * number.
+ *
+ * @param hostname
+ * The hostname of the node
+ * @see #DEFAULT_PORT
+ */
+ public Node(String hostname) {
+ this(hostname, DEFAULT_PORT);
+ }
+
+ /**
+ * Creates a new node with the specified hostname and port number.
+ *
+ * @param hostname
+ * The hostname of the node
+ * @param port
+ * The port number of the node
+ */
+ public Node(String hostname, int port) {
+ this.hostname = hostname;
+ this.port = port;
+ }
+
+ /**
+ * Returns the hostname of the node.
+ *
+ * @return The hostname of the node
+ */
+ public String getHostname() {
+ return hostname;
+ }
+
+ /**
+ * Returns the port number of the node.
+ *
+ * @return The port number of the node
+ */
+ public int getPort() {
+ return port;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Persistence.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * The possible persistence options. This specify whether (and for how long) the
+ * node remembers to execute a request and the results. Possible values are
+ * <code>connection</code>, <code>reboot</code>, and <code>forever</code>.
+ * <code>connection</code> means that a request is aborted as soon as the
+ * connection to the node is severed. <code>reboot</code> means that a request
+ * is remembered as long as the node is running but not after restarts.
+ * <code>forever</code> finally means that a request persists until it is
+ * explicitely deleted.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ * @see de.todesbaum.util.freenet.fcp2.ModifyPersistentRequest
+ * @see de.todesbaum.util.freenet.fcp2.RemovePersistentRequest
+ */
+public final class Persistence {
+
+ /**
+ * Denotes that a request should be terminated if the connection to the node
+ * is severed.
+ */
+ public static final Persistence CONNECTION = new Persistence("connection");
+
+ /** Denotes that a request should be remembered until the node is restarted. */
+ public static final Persistence REBOOT = new Persistence("reboot");
+
+ /**
+ * Denotes that a request should be remembered until it is explicitely
+ * deleted.
+ */
+ public static final Persistence FOREVER = new Persistence("forever");
+
+ /** The name of this persistence option. */
+ private String name;
+
+ /**
+ * Private constructor that creates a persistence option with the specified
+ * name.
+ *
+ * @param name
+ * The name of the persistence option.
+ */
+ private Persistence(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of this persistence option.
+ *
+ * @return The name of this persistence option
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns a textual representation of this persistence option. The result
+ * is identical to calling {@link #getName()}.
+ *
+ * @return The name of this persistence option
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - PriorityClass.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * The possible priority classes. Possible values are, in order of descending
+ * priority: <code>maximum</code> (anything more important than fproxy),
+ * <code>interactive</code> (fproxy), <code>semi-interactive</code> (fproxy
+ * immediate mode large file downloads, not to disk), <code>updatable</code>
+ * (updatable site checks), <code>bulk</code> (large file downloads to disk),
+ * <code>prefetch</code>, <code>minimum</code>.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public final class PriorityClass {
+
+ /** Denotes <code>maximum</code> priority class. */
+ public static final PriorityClass MAXIMUM = new PriorityClass("maximum", 0);
+
+ /** Denotes <code>interactive</code> priority class. */
+ public static final PriorityClass INTERACTIVE = new PriorityClass("interactive", 1);
+
+ /** Denotes <code>semi-interactive</code> priority class. */
+ public static final PriorityClass SEMI_INTERACTIVE = new PriorityClass("semiInteractive", 2);
+
+ /** Denotes <code>updatable</code> priority class. */
+ public static final PriorityClass UPDATABLE = new PriorityClass("updatable", 3);
+
+ /** Denotes <code>bulk</code> priority class. */
+ public static final PriorityClass BULK = new PriorityClass("bulk", 4);
+
+ /** Denotes <code>prefetch</code> priority class. */
+ public static final PriorityClass PREFETCH = new PriorityClass("prefetch", 5);
+
+ /** Denotes <code>minimum</code> priority class. */
+ public static final PriorityClass MINIMUM = new PriorityClass("minimum", 6);
+
+ /** The name of the priority class. */
+ private String name;
+
+ /** The value of the priority class. */
+ private int value;
+
+ /**
+ * Creates a new priority class with the specified name and value.
+ *
+ * @param name
+ * The name of the priority class
+ * @param value
+ * The value of the priority class
+ */
+ private PriorityClass(String name, int value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns the name of this priority class.
+ *
+ * @return The name of this priority class
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of this priority class.
+ *
+ * @return The value of this priority class
+ */
+ public int getValue() {
+ return value;
+ }
+
+ //
+ // STATIC METHODS
+ //
+
+ /**
+ * Returns the priority class with the given name, matched case-insensitive.
+ *
+ * @param value
+ * The name of the priority
+ * @return The priority with the given name, or {@code null} if no priority
+ * matches the given name
+ */
+ public static PriorityClass valueOf(String value) {
+ for (PriorityClass priorityClass : new PriorityClass[] { MINIMUM, PREFETCH, BULK, UPDATABLE, SEMI_INTERACTIVE, INTERACTIVE, MAXIMUM }) {
+ if (priorityClass.getName().equalsIgnoreCase(value)) {
+ return priorityClass;
+ }
+ }
+ return null;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - RedirectFileEntry.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+public class RedirectFileEntry extends FileEntry {
+
+ final String targetURI;
+
+ public RedirectFileEntry(String filename, String contentType, String targetURI) {
+ super(filename, contentType);
+ this.targetURI = targetURI;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return "redirect";
+ }
+
+ /**
+ * @return Returns the targetURI.
+ */
+ public String getTargetURI() {
+ return targetURI;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * jSite - ReturnType.java - Copyright © 2008–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * Enumeration for the different return types a {@link ClientGet} request can
+ * have.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+public enum ReturnType {
+
+ /** The data is returned as payload. */
+ direct,
+
+ /** The data is written to disk. */
+ disk,
+
+ /** The data is not returned at all. */
+ none
+
+}
--- /dev/null
+/*
+ * jSite - Verbosity.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.freenet.fcp2;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public final class Verbosity {
+
+ public static final Verbosity PROGRESS = new Verbosity(1);
+ public static final Verbosity COMPRESSION = new Verbosity(512);
+
+ public static final Verbosity NONE = new Verbosity(0);
+ public static final Verbosity ALL = new Verbosity(PROGRESS, COMPRESSION);
+
+ private final int value;
+
+ private Verbosity(int value) {
+ this.value = value;
+ }
+
+ private Verbosity(Verbosity verbosity1, Verbosity verbosity2) {
+ this(verbosity1.value | verbosity2.value);
+ }
+
+ /**
+ * @return Returns the value.
+ */
+ public int getValue() {
+ return value;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - IconLoader.java - Copyright © 2006–2012 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 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.image;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+/**
+ * @author <a href="mailto:droden@gmail.com">David Roden</a>
+ * @version $Id$
+ */
+public class IconLoader {
+
+ public static Icon loadIcon(String resourceName) {
+ try {
+ InputStream resourceStream = IconLoader.class.getResourceAsStream(resourceName);
+ if (resourceStream == null) {
+ return null;
+ }
+ ByteArrayOutputStream imageOutput = new ByteArrayOutputStream();
+ byte[] buffer = new byte[16384];
+ int r = 0;
+ while ((r = resourceStream.read(buffer)) != -1) {
+ imageOutput.write(buffer, 0, r);
+ }
+ imageOutput.flush();
+ return new ImageIcon(imageOutput.toByteArray());
+ } catch (IOException e) {
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - Closer.java - Copyright © 2006–2012 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 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * Helper class that can close all kinds of resources without throwing exception
+ * so that clean-up code can be written with less code. All methods check that
+ * the given resource is not <code>null</code> before invoking the close()
+ * method of the respective type.
+ *
+ * @author <a href="mailto:bombe@freenetproject.org">David ‘Bombe&squo;
+ * Roden</a>
+ * @version $Id$
+ */
+public class Closer {
+
+ /**
+ * Closes the given result set.
+ *
+ * @param resultSet
+ * The result set to close
+ * @see ResultSet#close()
+ */
+ public static void close(ResultSet resultSet) {
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (SQLException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given statement.
+ *
+ * @param statement
+ * The statement to close
+ * @see Statement#close()
+ */
+ public static void close(Statement statement) {
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given connection.
+ *
+ * @param connection
+ * The connection to close
+ * @see Connection#close()
+ */
+ public static void close(Connection connection) {
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (SQLException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given server socket.
+ *
+ * @param serverSocket
+ * The server socket to close
+ * @see ServerSocket#close()
+ */
+ public static void close(ServerSocket serverSocket) {
+ if (serverSocket != null) {
+ try {
+ serverSocket.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given socket.
+ *
+ * @param socket
+ * The socket to close
+ * @see Socket#close()
+ */
+ public static void close(Socket socket) {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given input stream.
+ *
+ * @param inputStream
+ * The input stream to close
+ * @see InputStream#close()
+ */
+ public static void close(InputStream inputStream) {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given output stream.
+ *
+ * @param outputStream
+ * The output stream to close
+ * @see OutputStream#close()
+ */
+ public static void close(OutputStream outputStream) {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given reader.
+ *
+ * @param reader
+ * The reader to close
+ * @see Reader#close()
+ */
+ public static void close(Reader reader) {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+
+ /**
+ * Closes the given writer.
+ *
+ * @param writer
+ * The write to close
+ * @see Writer#close()
+ */
+ public static void close(Writer writer) {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - LineInputStream.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class LineInputStream extends FilterInputStream {
+
+ private boolean skipLinefeed = false;
+ private StringBuffer lineBuffer = new StringBuffer();
+
+ /**
+ * @param in
+ */
+ public LineInputStream(InputStream in) {
+ super(in);
+ }
+
+ public synchronized String readLine() throws IOException {
+ lineBuffer.setLength(0);
+ int c = 0;
+ while (c != -1) {
+ c = read();
+ if ((c == -1) && lineBuffer.length() == 0)
+ return null;
+ if (skipLinefeed && (c == '\n')) {
+ skipLinefeed = false;
+ continue;
+ }
+ skipLinefeed = (c == '\r');
+ if ((c == '\r') || (c == '\n')) {
+ c = -1;
+ } else {
+ lineBuffer.append((char) c);
+ }
+ }
+ return lineBuffer.toString();
+ }
+
+}
--- /dev/null
+/*
+ * jSite - StreamCopier.java - Copyright © 2006–2012 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 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.EventListener;
+
+/**
+ * Copies input from an {@link InputStream} to an {@link OutputStream}.
+ *
+ * @author <a href="mailto:droden@gmail.com">David Roden</a>
+ * @version $Id$
+ */
+public class StreamCopier {
+
+ /**
+ * The default size of the buffer.
+ */
+ private static final int BUFFER_SIZE = 64 * 1024;
+
+ /**
+ * The {@link InputStream} to read from.
+ */
+ private InputStream inputStream;
+
+ /**
+ * The {@link OutputStream} to write to.
+ */
+ private OutputStream outputStream;
+
+ /**
+ * The number of bytes to copy.
+ */
+ private long length;
+
+ /**
+ * The size of the buffer.
+ */
+ private int bufferSize;
+
+ /**
+ * Creates a new StreamCopier with the specified parameters and the default
+ * buffer size.
+ *
+ * @param inputStream
+ * The {@link InputStream} to read from
+ * @param outputStream
+ * The {@link OutputStream} to write to
+ * @param length
+ * The number of bytes to copy
+ */
+ public StreamCopier(InputStream inputStream, OutputStream outputStream, long length) {
+ this(inputStream, outputStream, length, BUFFER_SIZE);
+ }
+
+ /**
+ * Creates a new StreamCopier with the specified parameters and the default
+ * buffer size.
+ *
+ * @param inputStream
+ * The {@link InputStream} to read from
+ * @param outputStream
+ * The {@link OutputStream} to write to
+ * @param length
+ * The number of bytes to copy
+ * @param bufferSize
+ * The number of bytes to copy at a time
+ */
+ public StreamCopier(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) {
+ this.inputStream = inputStream;
+ this.outputStream = outputStream;
+ this.length = length;
+ this.bufferSize = bufferSize;
+ }
+
+ /**
+ * Copies the stream data. If the input stream is depleted before the
+ * requested number of bytes have been read an {@link EOFException} is
+ * thrown.
+ *
+ * @throws EOFException
+ * if the input stream is depleted before the requested number
+ * of bytes has been read
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public void copy() throws EOFException, IOException {
+ copy(inputStream, outputStream, length, bufferSize);
+ }
+
+ /**
+ * Copies the stream data. If the input stream is depleted before the
+ * requested number of bytes have been read an {@link EOFException} is
+ * thrown.
+ *
+ * @param progressListener
+ * The progress listener (may be {@code null})
+ * @throws EOFException
+ * if the input stream is depleted before the requested number
+ * of bytes has been read
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public void copy(ProgressListener progressListener) throws EOFException, IOException {
+ copy(inputStream, outputStream, length, bufferSize, progressListener);
+ }
+
+ /**
+ * Copies <code>length</code> bytes from the <code>inputStream</code> to
+ * the <code>outputStream</code>.
+ *
+ * @param inputStream
+ * The input stream to read from
+ * @param outputStream
+ * The output stream to write to
+ * @param length
+ * The number of bytes to copy
+ * @throws IOException
+ * if an I/O exception occurs
+ */
+ public static void copy(InputStream inputStream, OutputStream outputStream, long length) throws IOException {
+ copy(inputStream, outputStream, length, BUFFER_SIZE);
+ }
+
+ /**
+ * Copies <code>length</code> bytes from the <code>inputStream</code> to
+ * the <code>outputStream</code>.
+ *
+ * @param inputStream
+ * The input stream to read from
+ * @param outputStream
+ * The output stream to write to
+ * @param length
+ * The number of bytes to copy
+ * @param progressListener
+ * The progress listener (may be {@code null})
+ * @throws IOException
+ * if an I/O exception occurs
+ */
+ public static void copy(InputStream inputStream, OutputStream outputStream, long length, ProgressListener progressListener) throws IOException {
+ copy(inputStream, outputStream, length, BUFFER_SIZE, progressListener);
+ }
+
+ /**
+ * Copies <code>length</code> bytes from the <code>inputStream</code> to
+ * the <code>outputStream</code> using a buffer with the specified size
+ *
+ * @param inputStream
+ * The input stream to read from
+ * @param outputStream
+ * The output stream to write to
+ * @param length
+ * The number of bytes to copy
+ * @param bufferSize
+ * The size of the copy buffer
+ * @throws IOException
+ * if an I/O exception occurs
+ */
+ public static void copy(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) throws IOException {
+ copy(inputStream, outputStream, length, bufferSize, null);
+ }
+
+ /**
+ * Copies <code>length</code> bytes from the <code>inputStream</code> to
+ * the <code>outputStream</code> using a buffer with the specified size
+ *
+ * @param inputStream
+ * The input stream to read from
+ * @param outputStream
+ * The output stream to write to
+ * @param length
+ * The number of bytes to copy
+ * @param bufferSize
+ * The size of the copy buffer
+ * @param progressListener
+ * The progress listener (may be {@code null})
+ * @throws IOException
+ * if an I/O exception occurs
+ */
+ public static void copy(InputStream inputStream, OutputStream outputStream, long length, int bufferSize, ProgressListener progressListener) throws IOException {
+ long remaining = length;
+ byte[] buffer = new byte[bufferSize];
+ while (remaining > 0) {
+ int read = inputStream.read(buffer, 0, (int) Math.min(Integer.MAX_VALUE, Math.min(bufferSize, remaining)));
+ if (read == -1) {
+ throw new EOFException();
+ }
+ outputStream.write(buffer, 0, read);
+ remaining -= read;
+ if (progressListener != null) {
+ progressListener.onProgress(length - remaining, length);
+ }
+ }
+ }
+
+ /**
+ * Interface for objects that want to be notified about the progress of a
+ * {@link StreamCopier#copy()} operation.
+ *
+ * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
+ */
+ public static interface ProgressListener extends EventListener {
+
+ /**
+ * Notifiies a listener that a copy process made some progress.
+ *
+ * @param copied
+ * The number of bytes that have already been copied
+ * @param length
+ * The total number of bytes that will be copied
+ */
+ public void onProgress(long copied, long length);
+
+ }
+
+}
--- /dev/null
+/*
+ * jSite - TeeOutputStream.java - Copyright © 2010 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
+ * the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * {@link OutputStream} that sends all data it receives to multiple other output
+ * streams. If an error occurs during a {@link #write(int)} to one of the
+ * underlying output streams no guarantees are made about how much data is sent
+ * to each stream, i.e. there is no good way to recover from such an error.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class TeeOutputStream extends OutputStream {
+
+ /** The output streams. */
+ private final OutputStream[] outputStreams;
+
+ /**
+ * Creates a new tee output stream that sends all to all given output
+ * streams.
+ *
+ * @param outputStreams
+ * The output streams to send all data to
+ */
+ public TeeOutputStream(OutputStream... outputStreams) {
+ this.outputStreams = outputStreams;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * An effort is made to close all output streams. If multiple exceptions
+ * occur, only the first exception is thrown after all output streams have
+ * been tried to close.
+ */
+ @Override
+ public void close() throws IOException {
+ IOException occuredException = null;
+ for (OutputStream outputStream : outputStreams) {
+ try {
+ outputStream.flush();
+ } catch (IOException ioe1) {
+ if (occuredException == null) {
+ occuredException = ioe1;
+ }
+ }
+ }
+ if (occuredException != null) {
+ throw occuredException;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * An effort is made to flush all output streams. If multiple exceptions
+ * occur, only the first exception is thrown after all output streams have
+ * been tried to flush.
+ */
+ @Override
+ public void flush() throws IOException {
+ IOException occuredException = null;
+ for (OutputStream outputStream : outputStreams) {
+ try {
+ outputStream.flush();
+ } catch (IOException ioe1) {
+ if (occuredException == null) {
+ occuredException = ioe1;
+ }
+ }
+ }
+ if (occuredException != null) {
+ throw occuredException;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ for (OutputStream outputStream : outputStreams) {
+ outputStream.write(buffer);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(byte[] buffer, int offset, int length) throws IOException {
+ for (OutputStream outputStream : outputStreams) {
+ outputStream.write(buffer, offset, length);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(int data) throws IOException {
+ for (OutputStream outputStream : outputStreams) {
+ outputStream.write(data);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * jSite - TempFileInputStream.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class TempFileInputStream extends FileInputStream {
+
+ private File tempFile;
+
+ /**
+ * @param name
+ * @throws FileNotFoundException
+ */
+ public TempFileInputStream(String name) throws FileNotFoundException {
+ this(new File(name));
+ }
+
+ /**
+ * @param file
+ * @throws FileNotFoundException
+ */
+ public TempFileInputStream(File file) throws FileNotFoundException {
+ super(file);
+ tempFile = file;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ tempFile.delete();
+ }
+
+}
--- /dev/null
+/* taken from freenet (http://www.freenetproject.org/) */
+package de.todesbaum.util.mime;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * Holds the default MIME types.
+ */
+public class DefaultMIMETypes {
+
+ /** Default MIME type - what to set it to if we don't know any better */
+ public static final String DEFAULT_MIME_TYPE = "application/octet-stream";
+
+ /** MIME types: number -> name */
+ private static List<String> mimeTypesByNumber = new Vector<String>();
+
+ /** MIME types: name -> number */
+ private static Map<String, Short> mimeTypesByName = new HashMap<String, Short>();
+
+ /** MIME types by extension. One extension maps to one MIME type, but not necessarily
+ * the other way around. */
+ private static Map<String, Short> mimeTypesByExtension = new HashMap<String, Short>();
+
+ /** Primary extension by MIME type number. */
+ private static Map<Short, String> primaryExtensionByMimeNumber = new HashMap<Short, String>();
+
+ /**
+ * Add a MIME type, without any extensions.
+ * @param number The number of the MIME type for compression. This *must not change*
+ * for a given type, or the metadata format will be affected.
+ * @param type The actual MIME type string. Do not include ;charset= etc; these are
+ * parameters and there is a separate mechanism for them.
+ */
+ protected static synchronized void addMIMEType(short number, String type) {
+ if(mimeTypesByNumber.size() > number) {
+ String s = mimeTypesByNumber.get(number);
+ if(s != null) throw new IllegalArgumentException("Already used: "+number);
+ } else {
+ mimeTypesByNumber.add(number, null);
+ }
+ mimeTypesByNumber.set(number, type);
+ mimeTypesByName.put(type, new Short(number));
+ }
+
+ /**
+ * Add a MIME type.
+ * @param number The number of the MIME type for compression. This *must not change*
+ * for a given type, or the metadata format will be affected.
+ * @param type The actual MIME type string. Do not include ;charset= etc; these are
+ * parameters and there is a separate mechanism for them.
+ * @param extensions An array of common extensions for files of this type. Must be
+ * unique for the type.
+ */
+ protected static synchronized void addMIMEType(short number, String type, String[] extensions, String outExtension) {
+ addMIMEType(number, type);
+ Short t = new Short(number);
+ if(extensions != null) {
+ for(int i=0;i<extensions.length;i++) {
+ String ext = extensions[i].toLowerCase();
+ if(mimeTypesByExtension.containsKey(ext)) {
+ // No big deal
+ //Short s = mimeTypesByExtension.get(ext);
+ } else {
+ // If only one, make it primary
+ if(outExtension == null && extensions.length == 1)
+ primaryExtensionByMimeNumber.put(t, ext);
+ mimeTypesByExtension.put(ext, t);
+ }
+ }
+ }
+ if(outExtension != null)
+ primaryExtensionByMimeNumber.put(t, outExtension);
+
+ }
+
+ /**
+ * Add a MIME type, with extensions separated by spaces. This is more or less
+ * the format in /etc/mime-types.
+ */
+ protected static synchronized void addMIMEType(short number, String type, String extensions) {
+ addMIMEType(number, type, extensions.split(" "), null);
+ }
+
+ /**
+ * Add a MIME type, with extensions separated by spaces. This is more or less
+ * the format in /etc/mime-types.
+ */
+ protected static synchronized void addMIMEType(short number, String type, String extensions, String outExtension) {
+ addMIMEType(number, type, extensions.split(" "), outExtension);
+ }
+
+ /**
+ * Get a known MIME type by number.
+ */
+ public static String byNumber(short x) {
+ if(x > mimeTypesByNumber.size() || x < 0)
+ return null;
+ return mimeTypesByNumber.get(x);
+ }
+
+ /**
+ * Get the number of a MIME type, or -1 if it is not in the table of known MIME
+ * types, in which case it will have to be sent uncompressed.
+ */
+ public static short byName(String s) {
+ Short x = mimeTypesByName.get(s);
+ if(x != null) return x.shortValue();
+ return -1;
+ }
+
+ /* From toad's /etc/mime.types
+ * cat /etc/mime.types | sed "/^$/d;/#/d" | tr --squeeze '\t' ' ' |
+ * (y=0; while read x; do echo "$x" |
+ * sed -n "s/^\([^ ]*\)$/addMIMEType\($y, \"\1\"\);/p;s/^\([^ (),]\+\) \(.*\)$/addMIMEType\($y, \"\1\", \"\2\"\);/p;"; y=$((y+1)); done)
+ */
+
+ static {
+ addMIMEType((short) 0, "application/activemessage");
+ addMIMEType((short) 1, "application/andrew-inset", "ez");
+ addMIMEType((short) 2, "application/applefile");
+ addMIMEType((short) 3, "application/atomicmail");
+ addMIMEType((short) 4, "application/batch-SMTP");
+ addMIMEType((short) 5, "application/beep+xml");
+ addMIMEType((short) 6, "application/cals-1840");
+ addMIMEType((short) 7, "application/commonground");
+ addMIMEType((short) 8, "application/cu-seeme", "cu");
+ addMIMEType((short) 9, "application/cybercash");
+ addMIMEType((short) 10, "application/dca-rft");
+ addMIMEType((short) 11, "application/dec-dx");
+ addMIMEType((short) 12, "application/docbook+xml");
+ addMIMEType((short) 13, "application/dsptype", "tsp");
+ addMIMEType((short) 14, "application/dvcs");
+ addMIMEType((short) 15, "application/edi-consent");
+ addMIMEType((short) 16, "application/edi-x12");
+ addMIMEType((short) 17, "application/edifact");
+ addMIMEType((short) 18, "application/eshop");
+ addMIMEType((short) 19, "application/font-tdpfr");
+ addMIMEType((short) 20, "application/futuresplash", "spl");
+ addMIMEType((short) 21, "application/ghostview");
+ addMIMEType((short) 22, "application/hta", "hta");
+ addMIMEType((short) 23, "application/http");
+ addMIMEType((short) 24, "application/hyperstudio");
+ addMIMEType((short) 25, "application/iges");
+ addMIMEType((short) 26, "application/index");
+ addMIMEType((short) 27, "application/index.cmd");
+ addMIMEType((short) 28, "application/index.obj");
+ addMIMEType((short) 29, "application/index.response");
+ addMIMEType((short) 30, "application/index.vnd");
+ addMIMEType((short) 31, "application/iotp");
+ addMIMEType((short) 32, "application/ipp");
+ addMIMEType((short) 33, "application/isup");
+ addMIMEType((short) 34, "application/java-archive", "jar");
+ addMIMEType((short) 35, "application/java-serialized-object", "ser");
+ addMIMEType((short) 36, "application/java-vm", "class");
+ addMIMEType((short) 37, "application/mac-binhex40", "hqx");
+ addMIMEType((short) 38, "application/mac-compactpro", "cpt");
+ addMIMEType((short) 39, "application/macwriteii");
+ addMIMEType((short) 40, "application/marc");
+ addMIMEType((short) 41, "application/mathematica", "nb");
+ addMIMEType((short) 42, "application/mathematica-old");
+ addMIMEType((short) 43, "application/msaccess", "mdb");
+ addMIMEType((short) 44, "application/msword", "doc dot");
+ addMIMEType((short) 45, "application/news-message-id");
+ addMIMEType((short) 46, "application/news-transmission");
+ addMIMEType((short) 47, "application/ocsp-request");
+ addMIMEType((short) 48, "application/ocsp-response");
+ addMIMEType((short) 49, "application/octet-stream", "bin");
+ addMIMEType((short) 50, "application/oda", "oda");
+ addMIMEType((short) 51, "application/ogg", "ogg");
+ addMIMEType((short) 52, "application/parityfec");
+ addMIMEType((short) 53, "application/pdf", "pdf");
+ addMIMEType((short) 54, "application/pgp-encrypted");
+ addMIMEType((short) 55, "application/pgp-keys", "key");
+ addMIMEType((short) 56, "application/pgp-signature", "pgp");
+ addMIMEType((short) 57, "application/pics-rules", "prf");
+ addMIMEType((short) 58, "application/pkcs10");
+ addMIMEType((short) 59, "application/pkcs7-mime");
+ addMIMEType((short) 60, "application/pkcs7-signature");
+ addMIMEType((short) 61, "application/pkix-cert");
+ addMIMEType((short) 62, "application/pkix-crl");
+ addMIMEType((short) 63, "application/pkixcmp");
+ addMIMEType((short) 64, "application/postscript", "ps ai eps");
+ addMIMEType((short) 65, "application/prs.alvestrand.titrax-sheet");
+ addMIMEType((short) 66, "application/prs.cww");
+ addMIMEType((short) 67, "application/prs.nprend");
+ addMIMEType((short) 68, "application/qsig");
+ addMIMEType((short) 69, "application/rar", "rar");
+ addMIMEType((short) 70, "application/rdf+xml", "rdf");
+ addMIMEType((short) 71, "application/remote-printing");
+ addMIMEType((short) 72, "application/riscos");
+ addMIMEType((short) 73, "application/rss+xml", "rss");
+ addMIMEType((short) 74, "application/rtf");
+ addMIMEType((short) 75, "application/sdp");
+ addMIMEType((short) 76, "application/set-payment");
+ addMIMEType((short) 77, "application/set-payment-initiation");
+ addMIMEType((short) 78, "application/set-registration");
+ addMIMEType((short) 79, "application/set-registration-initiation");
+ addMIMEType((short) 80, "application/sgml");
+ addMIMEType((short) 81, "application/sgml-open-catalog");
+ addMIMEType((short) 82, "application/sieve");
+ addMIMEType((short) 83, "application/slate");
+ addMIMEType((short) 84, "application/smil", "smi smil");
+ addMIMEType((short) 85, "application/timestamp-query");
+ addMIMEType((short) 86, "application/timestamp-reply");
+ addMIMEType((short) 87, "application/vemmi");
+ addMIMEType((short) 88, "application/whoispp-query");
+ addMIMEType((short) 89, "application/whoispp-response");
+ addMIMEType((short) 90, "application/wita");
+ addMIMEType((short) 91, "application/wordperfect", "wpd");
+ addMIMEType((short) 92, "application/wordperfect5.1", "wp5");
+ addMIMEType((short) 93, "application/x400-bp");
+ addMIMEType((short) 94, "application/xhtml+xml", "xhtml xht");
+ addMIMEType((short) 95, "application/xml", "xml xsl");
+ addMIMEType((short) 96, "application/xml-dtd");
+ addMIMEType((short) 97, "application/xml-external-parsed-entity");
+ addMIMEType((short) 98, "application/zip", "zip");
+ addMIMEType((short) 99, "application/vnd.3M.Post-it-Notes");
+ addMIMEType((short) 100, "application/vnd.accpac.simply.aso");
+ addMIMEType((short) 101, "application/vnd.accpac.simply.imp");
+ addMIMEType((short) 102, "application/vnd.acucobol");
+ addMIMEType((short) 103, "application/vnd.aether.imp");
+ addMIMEType((short) 104, "application/vnd.anser-web-certificate-issue-initiation");
+ addMIMEType((short) 105, "application/vnd.anser-web-funds-transfer-initiation");
+ addMIMEType((short) 106, "application/vnd.audiograph");
+ addMIMEType((short) 107, "application/vnd.bmi");
+ addMIMEType((short) 108, "application/vnd.businessobjects");
+ addMIMEType((short) 109, "application/vnd.canon-cpdl");
+ addMIMEType((short) 110, "application/vnd.canon-lips");
+ addMIMEType((short) 111, "application/vnd.cinderella", "cdy");
+ addMIMEType((short) 112, "application/vnd.claymore");
+ addMIMEType((short) 113, "application/vnd.commerce-battelle");
+ addMIMEType((short) 114, "application/vnd.commonspace");
+ addMIMEType((short) 115, "application/vnd.comsocaller");
+ addMIMEType((short) 116, "application/vnd.contact.cmsg");
+ addMIMEType((short) 117, "application/vnd.cosmocaller");
+ addMIMEType((short) 118, "application/vnd.ctc-posml");
+ addMIMEType((short) 119, "application/vnd.cups-postscript");
+ addMIMEType((short) 120, "application/vnd.cups-raster");
+ addMIMEType((short) 121, "application/vnd.cups-raw");
+ addMIMEType((short) 122, "application/vnd.cybank");
+ addMIMEType((short) 123, "application/vnd.dna");
+ addMIMEType((short) 124, "application/vnd.dpgraph");
+ addMIMEType((short) 125, "application/vnd.dxr");
+ addMIMEType((short) 126, "application/vnd.ecdis-update");
+ addMIMEType((short) 127, "application/vnd.ecowin.chart");
+ addMIMEType((short) 128, "application/vnd.ecowin.filerequest");
+ addMIMEType((short) 129, "application/vnd.ecowin.fileupdate");
+ addMIMEType((short) 130, "application/vnd.ecowin.series");
+ addMIMEType((short) 131, "application/vnd.ecowin.seriesrequest");
+ addMIMEType((short) 132, "application/vnd.ecowin.seriesupdate");
+ addMIMEType((short) 133, "application/vnd.enliven");
+ addMIMEType((short) 134, "application/vnd.epson.esf");
+ addMIMEType((short) 135, "application/vnd.epson.msf");
+ addMIMEType((short) 136, "application/vnd.epson.quickanime");
+ addMIMEType((short) 137, "application/vnd.epson.salt");
+ addMIMEType((short) 138, "application/vnd.epson.ssf");
+ addMIMEType((short) 139, "application/vnd.ericsson.quickcall");
+ addMIMEType((short) 140, "application/vnd.eudora.data");
+ addMIMEType((short) 141, "application/vnd.fdf");
+ addMIMEType((short) 142, "application/vnd.ffsns");
+ addMIMEType((short) 143, "application/vnd.flographit");
+ addMIMEType((short) 144, "application/vnd.framemaker");
+ addMIMEType((short) 145, "application/vnd.fsc.weblaunch");
+ addMIMEType((short) 146, "application/vnd.fujitsu.oasys");
+ addMIMEType((short) 147, "application/vnd.fujitsu.oasys2");
+ addMIMEType((short) 148, "application/vnd.fujitsu.oasys3");
+ addMIMEType((short) 149, "application/vnd.fujitsu.oasysgp");
+ addMIMEType((short) 150, "application/vnd.fujitsu.oasysprs");
+ addMIMEType((short) 151, "application/vnd.fujixerox.ddd");
+ addMIMEType((short) 152, "application/vnd.fujixerox.docuworks");
+ addMIMEType((short) 153, "application/vnd.fujixerox.docuworks.binder");
+ addMIMEType((short) 154, "application/vnd.fut-misnet");
+ addMIMEType((short) 155, "application/vnd.grafeq");
+ addMIMEType((short) 156, "application/vnd.groove-account");
+ addMIMEType((short) 157, "application/vnd.groove-identity-message");
+ addMIMEType((short) 158, "application/vnd.groove-injector");
+ addMIMEType((short) 159, "application/vnd.groove-tool-message");
+ addMIMEType((short) 160, "application/vnd.groove-tool-template");
+ addMIMEType((short) 161, "application/vnd.groove-vcard");
+ addMIMEType((short) 162, "application/vnd.hhe.lesson-player");
+ addMIMEType((short) 163, "application/vnd.hp-HPGL");
+ addMIMEType((short) 164, "application/vnd.hp-PCL");
+ addMIMEType((short) 165, "application/vnd.hp-PCLXL");
+ addMIMEType((short) 166, "application/vnd.hp-hpid");
+ addMIMEType((short) 167, "application/vnd.hp-hps");
+ addMIMEType((short) 168, "application/vnd.httphone");
+ addMIMEType((short) 169, "application/vnd.hzn-3d-crossword");
+ addMIMEType((short) 170, "application/vnd.ibm.MiniPay");
+ addMIMEType((short) 171, "application/vnd.ibm.afplinedata");
+ addMIMEType((short) 172, "application/vnd.ibm.modcap");
+ addMIMEType((short) 173, "application/vnd.informix-visionary");
+ addMIMEType((short) 174, "application/vnd.intercon.formnet");
+ addMIMEType((short) 175, "application/vnd.intertrust.digibox");
+ addMIMEType((short) 176, "application/vnd.intertrust.nncp");
+ addMIMEType((short) 177, "application/vnd.intu.qbo");
+ addMIMEType((short) 178, "application/vnd.intu.qfx");
+ addMIMEType((short) 179, "application/vnd.irepository.package+xml");
+ addMIMEType((short) 180, "application/vnd.is-xpr");
+ addMIMEType((short) 181, "application/vnd.japannet-directory-service");
+ addMIMEType((short) 182, "application/vnd.japannet-jpnstore-wakeup");
+ addMIMEType((short) 183, "application/vnd.japannet-payment-wakeup");
+ addMIMEType((short) 184, "application/vnd.japannet-registration");
+ addMIMEType((short) 185, "application/vnd.japannet-registration-wakeup");
+ addMIMEType((short) 186, "application/vnd.japannet-setstore-wakeup");
+ addMIMEType((short) 187, "application/vnd.japannet-verification");
+ addMIMEType((short) 188, "application/vnd.japannet-verification-wakeup");
+ addMIMEType((short) 189, "application/vnd.koan");
+ addMIMEType((short) 190, "application/vnd.lotus-1-2-3");
+ addMIMEType((short) 191, "application/vnd.lotus-approach");
+ addMIMEType((short) 192, "application/vnd.lotus-freelance");
+ addMIMEType((short) 193, "application/vnd.lotus-notes");
+ addMIMEType((short) 194, "application/vnd.lotus-organizer");
+ addMIMEType((short) 195, "application/vnd.lotus-screencam");
+ addMIMEType((short) 196, "application/vnd.lotus-wordpro");
+ addMIMEType((short) 197, "application/vnd.mcd");
+ addMIMEType((short) 198, "application/vnd.mediastation.cdkey");
+ addMIMEType((short) 199, "application/vnd.meridian-slingshot");
+ addMIMEType((short) 200, "application/vnd.mif");
+ addMIMEType((short) 201, "application/vnd.minisoft-hp3000-save");
+ addMIMEType((short) 202, "application/vnd.mitsubishi.misty-guard.trustweb");
+ addMIMEType((short) 203, "application/vnd.mobius.daf");
+ addMIMEType((short) 204, "application/vnd.mobius.dis");
+ addMIMEType((short) 205, "application/vnd.mobius.msl");
+ addMIMEType((short) 206, "application/vnd.mobius.plc");
+ addMIMEType((short) 207, "application/vnd.mobius.txf");
+ addMIMEType((short) 208, "application/vnd.motorola.flexsuite");
+ addMIMEType((short) 209, "application/vnd.motorola.flexsuite.adsi");
+ addMIMEType((short) 210, "application/vnd.motorola.flexsuite.fis");
+ addMIMEType((short) 211, "application/vnd.motorola.flexsuite.gotap");
+ addMIMEType((short) 212, "application/vnd.motorola.flexsuite.kmr");
+ addMIMEType((short) 213, "application/vnd.motorola.flexsuite.ttc");
+ addMIMEType((short) 214, "application/vnd.motorola.flexsuite.wem");
+ addMIMEType((short) 215, "application/vnd.mozilla.xul+xml", "xul");
+ addMIMEType((short) 216, "application/vnd.ms-artgalry");
+ addMIMEType((short) 217, "application/vnd.ms-asf");
+ addMIMEType((short) 218, "application/vnd.ms-excel", "xls xlb xlt");
+ addMIMEType((short) 219, "application/vnd.ms-lrm");
+ addMIMEType((short) 220, "application/vnd.ms-pki.seccat", "cat");
+ addMIMEType((short) 221, "application/vnd.ms-pki.stl", "stl");
+ addMIMEType((short) 222, "application/vnd.ms-powerpoint", "ppt pps");
+ addMIMEType((short) 223, "application/vnd.ms-project");
+ addMIMEType((short) 224, "application/vnd.ms-tnef");
+ addMIMEType((short) 225, "application/vnd.ms-works");
+ addMIMEType((short) 226, "application/vnd.mseq");
+ addMIMEType((short) 227, "application/vnd.msign");
+ addMIMEType((short) 228, "application/vnd.music-niff");
+ addMIMEType((short) 229, "application/vnd.musician");
+ addMIMEType((short) 230, "application/vnd.netfpx");
+ addMIMEType((short) 231, "application/vnd.noblenet-directory");
+ addMIMEType((short) 232, "application/vnd.noblenet-sealer");
+ addMIMEType((short) 233, "application/vnd.noblenet-web");
+ addMIMEType((short) 234, "application/vnd.novadigm.EDM");
+ addMIMEType((short) 235, "application/vnd.novadigm.EDX");
+ addMIMEType((short) 236, "application/vnd.novadigm.EXT");
+ addMIMEType((short) 237, "application/vnd.oasis.opendocument.chart", "odc");
+ addMIMEType((short) 238, "application/vnd.oasis.opendocument.database", "odb");
+ addMIMEType((short) 239, "application/vnd.oasis.opendocument.formula", "odf");
+ addMIMEType((short) 240, "application/vnd.oasis.opendocument.graphics", "odg");
+ addMIMEType((short) 241, "application/vnd.oasis.opendocument.graphics-template", "otg");
+ addMIMEType((short) 242, "application/vnd.oasis.opendocument.image", "odi");
+ addMIMEType((short) 243, "application/vnd.oasis.opendocument.presentation", "odp");
+ addMIMEType((short) 244, "application/vnd.oasis.opendocument.presentation-template", "otp");
+ addMIMEType((short) 245, "application/vnd.oasis.opendocument.spreadsheet", "ods");
+ addMIMEType((short) 246, "application/vnd.oasis.opendocument.spreadsheet-template", "ots");
+ addMIMEType((short) 247, "application/vnd.oasis.opendocument.text", "odt");
+ addMIMEType((short) 248, "application/vnd.oasis.opendocument.text-master", "odm");
+ addMIMEType((short) 249, "application/vnd.oasis.opendocument.text-template", "ott");
+ addMIMEType((short) 250, "application/vnd.oasis.opendocument.text-web", "oth");
+ addMIMEType((short) 251, "application/vnd.osa.netdeploy");
+ addMIMEType((short) 252, "application/vnd.palm");
+ addMIMEType((short) 253, "application/vnd.pg.format");
+ addMIMEType((short) 254, "application/vnd.pg.osasli");
+ addMIMEType((short) 255, "application/vnd.powerbuilder6");
+ addMIMEType((short) 256, "application/vnd.powerbuilder6-s");
+ addMIMEType((short) 257, "application/vnd.powerbuilder7");
+ addMIMEType((short) 258, "application/vnd.powerbuilder7-s");
+ addMIMEType((short) 259, "application/vnd.powerbuilder75");
+ addMIMEType((short) 260, "application/vnd.powerbuilder75-s");
+ addMIMEType((short) 261, "application/vnd.previewsystems.box");
+ addMIMEType((short) 262, "application/vnd.publishare-delta-tree");
+ addMIMEType((short) 263, "application/vnd.pvi.ptid1");
+ addMIMEType((short) 264, "application/vnd.pwg-xhtml-print+xml");
+ addMIMEType((short) 265, "application/vnd.rapid");
+ addMIMEType((short) 266, "application/vnd.rim.cod", "cod");
+ addMIMEType((short) 267, "application/vnd.s3sms");
+ addMIMEType((short) 268, "application/vnd.seemail");
+ addMIMEType((short) 269, "application/vnd.shana.informed.formdata");
+ addMIMEType((short) 270, "application/vnd.shana.informed.formtemplate");
+ addMIMEType((short) 271, "application/vnd.shana.informed.interchange");
+ addMIMEType((short) 272, "application/vnd.shana.informed.package");
+ addMIMEType((short) 273, "application/vnd.smaf", "mmf");
+ addMIMEType((short) 274, "application/vnd.sss-cod");
+ addMIMEType((short) 275, "application/vnd.sss-dtf");
+ addMIMEType((short) 276, "application/vnd.sss-ntf");
+ addMIMEType((short) 277, "application/vnd.stardivision.calc", "sdc");
+ addMIMEType((short) 278, "application/vnd.stardivision.draw", "sda");
+ addMIMEType((short) 279, "application/vnd.stardivision.impress", "sdd sdp");
+ addMIMEType((short) 280, "application/vnd.stardivision.math", "smf");
+ addMIMEType((short) 281, "application/vnd.stardivision.writer", "sdw vor");
+ addMIMEType((short) 282, "application/vnd.stardivision.writer-global", "sgl");
+ addMIMEType((short) 283, "application/vnd.street-stream");
+ addMIMEType((short) 284, "application/vnd.sun.xml.calc", "sxc");
+ addMIMEType((short) 285, "application/vnd.sun.xml.calc.template", "stc");
+ addMIMEType((short) 286, "application/vnd.sun.xml.draw", "sxd");
+ addMIMEType((short) 287, "application/vnd.sun.xml.draw.template", "std");
+ addMIMEType((short) 288, "application/vnd.sun.xml.impress", "sxi");
+ addMIMEType((short) 289, "application/vnd.sun.xml.impress.template", "sti");
+ addMIMEType((short) 290, "application/vnd.sun.xml.math", "sxm");
+ addMIMEType((short) 291, "application/vnd.sun.xml.writer", "sxw");
+ addMIMEType((short) 292, "application/vnd.sun.xml.writer.global", "sxg");
+ addMIMEType((short) 293, "application/vnd.sun.xml.writer.template", "stw");
+ addMIMEType((short) 294, "application/vnd.svd");
+ addMIMEType((short) 295, "application/vnd.swiftview-ics");
+ addMIMEType((short) 296, "application/vnd.symbian.install", "sis");
+ addMIMEType((short) 297, "application/vnd.triscape.mxs");
+ addMIMEType((short) 298, "application/vnd.trueapp");
+ addMIMEType((short) 299, "application/vnd.truedoc");
+ addMIMEType((short) 300, "application/vnd.tve-trigger");
+ addMIMEType((short) 301, "application/vnd.ufdl");
+ addMIMEType((short) 302, "application/vnd.uplanet.alert");
+ addMIMEType((short) 303, "application/vnd.uplanet.alert-wbxml");
+ addMIMEType((short) 304, "application/vnd.uplanet.bearer-choice");
+ addMIMEType((short) 305, "application/vnd.uplanet.bearer-choice-wbxml");
+ addMIMEType((short) 306, "application/vnd.uplanet.cacheop");
+ addMIMEType((short) 307, "application/vnd.uplanet.cacheop-wbxml");
+ addMIMEType((short) 308, "application/vnd.uplanet.channel");
+ addMIMEType((short) 309, "application/vnd.uplanet.channel-wbxml");
+ addMIMEType((short) 310, "application/vnd.uplanet.list");
+ addMIMEType((short) 311, "application/vnd.uplanet.list-wbxml");
+ addMIMEType((short) 312, "application/vnd.uplanet.listcmd");
+ addMIMEType((short) 313, "application/vnd.uplanet.listcmd-wbxml");
+ addMIMEType((short) 314, "application/vnd.uplanet.signal");
+ addMIMEType((short) 315, "application/vnd.vcx");
+ addMIMEType((short) 316, "application/vnd.vectorworks");
+ addMIMEType((short) 317, "application/vnd.vidsoft.vidconference");
+ addMIMEType((short) 318, "application/vnd.visio", "vsd");
+ addMIMEType((short) 319, "application/vnd.vividence.scriptfile");
+ addMIMEType((short) 320, "application/vnd.wap.sic");
+ addMIMEType((short) 321, "application/vnd.wap.slc");
+ addMIMEType((short) 322, "application/vnd.wap.wbxml", "wbxml");
+ addMIMEType((short) 323, "application/vnd.wap.wmlc", "wmlc");
+ addMIMEType((short) 324, "application/vnd.wap.wmlscriptc", "wmlsc");
+ addMIMEType((short) 325, "application/vnd.webturbo");
+ addMIMEType((short) 326, "application/vnd.wrq-hp3000-labelled");
+ addMIMEType((short) 327, "application/vnd.wt.stf");
+ addMIMEType((short) 328, "application/vnd.xara");
+ addMIMEType((short) 329, "application/vnd.xfdl");
+ addMIMEType((short) 330, "application/vnd.yellowriver-custom-menu");
+ addMIMEType((short) 331, "application/x-123", "wk");
+ addMIMEType((short) 332, "application/x-abiword", "abw");
+ addMIMEType((short) 333, "application/x-apple-diskimage", "dmg");
+ addMIMEType((short) 334, "application/x-bcpio", "bcpio");
+ addMIMEType((short) 335, "application/x-bittorrent", "torrent");
+ addMIMEType((short) 336, "application/x-cdf", "cdf");
+ addMIMEType((short) 337, "application/x-cdlink", "vcd");
+ addMIMEType((short) 338, "application/x-chess-pgn", "pgn");
+ addMIMEType((short) 339, "application/x-core");
+ addMIMEType((short) 340, "application/x-cpio", "cpio");
+ addMIMEType((short) 341, "application/x-csh", "csh");
+ addMIMEType((short) 342, "application/x-debian-package", "deb udeb");
+ addMIMEType((short) 343, "application/x-director", "dcr dir dxr");
+ addMIMEType((short) 344, "application/x-dms", "dms");
+ addMIMEType((short) 345, "application/x-doom", "wad");
+ addMIMEType((short) 346, "application/x-dvi", "dvi");
+ addMIMEType((short) 347, "application/x-executable");
+ addMIMEType((short) 348, "application/x-flac", "flac");
+ addMIMEType((short) 349, "application/x-font", "pfa pfb gsf pcf pcf.Z");
+ addMIMEType((short) 350, "application/x-freemind", "mm");
+ addMIMEType((short) 351, "application/x-futuresplash", "spl");
+ addMIMEType((short) 352, "application/x-gnumeric", "gnumeric");
+ addMIMEType((short) 353, "application/x-go-sgf", "sgf");
+ addMIMEType((short) 354, "application/x-graphing-calculator", "gcf");
+ addMIMEType((short) 355, "application/x-gtar", "gtar tgz taz");
+ addMIMEType((short) 356, "application/x-hdf", "hdf");
+ addMIMEType((short) 357, "application/x-httpd-php", "phtml pht php");
+ addMIMEType((short) 358, "application/x-httpd-php-source", "phps");
+ addMIMEType((short) 359, "application/x-httpd-php3", "php3");
+ addMIMEType((short) 360, "application/x-httpd-php3-preprocessed", "php3p");
+ addMIMEType((short) 361, "application/x-httpd-php4", "php4");
+ addMIMEType((short) 362, "application/x-ica", "ica");
+ addMIMEType((short) 363, "application/x-internet-signup", "ins isp");
+ addMIMEType((short) 364, "application/x-iphone", "iii");
+ addMIMEType((short) 365, "application/x-iso9660-image", "iso");
+ addMIMEType((short) 366, "application/x-java-applet");
+ addMIMEType((short) 367, "application/x-java-bean");
+ addMIMEType((short) 368, "application/x-java-jnlp-file", "jnlp");
+ addMIMEType((short) 369, "application/x-javascript", "js");
+ addMIMEType((short) 370, "application/x-jmol", "jmz");
+ addMIMEType((short) 371, "application/x-kchart", "chrt");
+ addMIMEType((short) 372, "application/x-kdelnk");
+ addMIMEType((short) 373, "application/x-killustrator", "kil");
+ addMIMEType((short) 374, "application/x-koan", "skp skd skt skm");
+ addMIMEType((short) 375, "application/x-kpresenter", "kpr kpt");
+ addMIMEType((short) 376, "application/x-kspread", "ksp");
+ addMIMEType((short) 377, "application/x-kword", "kwd kwt");
+ addMIMEType((short) 378, "application/x-latex", "latex");
+ addMIMEType((short) 379, "application/x-lha", "lha");
+ addMIMEType((short) 380, "application/x-lzh", "lzh");
+ addMIMEType((short) 381, "application/x-lzx", "lzx");
+ addMIMEType((short) 382, "application/x-maker", "frm maker frame fm fb book fbdoc");
+ addMIMEType((short) 383, "application/x-mif", "mif");
+ addMIMEType((short) 384, "application/x-ms-wmd", "wmd");
+ addMIMEType((short) 385, "application/x-ms-wmz", "wmz");
+ addMIMEType((short) 386, "application/x-msdos-program", "com exe bat dll");
+ addMIMEType((short) 387, "application/x-msi", "msi");
+ addMIMEType((short) 388, "application/x-netcdf", "nc");
+ addMIMEType((short) 389, "application/x-ns-proxy-autoconfig", "pac");
+ addMIMEType((short) 390, "application/x-nwc", "nwc");
+ addMIMEType((short) 391, "application/x-object", "o");
+ addMIMEType((short) 392, "application/x-oz-application", "oza");
+ addMIMEType((short) 393, "application/x-pkcs7-certreqresp", "p7r");
+ addMIMEType((short) 394, "application/x-pkcs7-crl", "crl");
+ addMIMEType((short) 395, "application/x-python-code", "pyc pyo");
+ addMIMEType((short) 396, "application/x-quicktimeplayer", "qtl");
+ addMIMEType((short) 397, "application/x-redhat-package-manager", "rpm");
+ addMIMEType((short) 398, "application/x-rx");
+ addMIMEType((short) 399, "application/x-sh", "sh");
+ addMIMEType((short) 400, "application/x-shar", "shar");
+ addMIMEType((short) 401, "application/x-shellscript");
+ addMIMEType((short) 402, "application/x-shockwave-flash", "swf swfl");
+ addMIMEType((short) 403, "application/x-stuffit", "sit");
+ addMIMEType((short) 404, "application/x-sv4cpio", "sv4cpio");
+ addMIMEType((short) 405, "application/x-sv4crc", "sv4crc");
+ addMIMEType((short) 406, "application/x-tar", "tar");
+ addMIMEType((short) 407, "application/x-tcl", "tcl");
+ addMIMEType((short) 408, "application/x-tex-gf", "gf");
+ addMIMEType((short) 409, "application/x-tex-pk", "pk");
+ addMIMEType((short) 410, "application/x-texinfo", "texinfo texi");
+ addMIMEType((short) 411, "application/x-trash", "~ % bak old sik");
+ addMIMEType((short) 412, "application/x-troff", "t tr roff");
+ addMIMEType((short) 413, "application/x-troff-man", "man");
+ addMIMEType((short) 414, "application/x-troff-me", "me");
+ addMIMEType((short) 415, "application/x-troff-ms", "ms");
+ addMIMEType((short) 416, "application/x-ustar", "ustar");
+ addMIMEType((short) 417, "application/x-videolan");
+ addMIMEType((short) 418, "application/x-wais-source", "src");
+ addMIMEType((short) 419, "application/x-wingz", "wz");
+ addMIMEType((short) 420, "application/x-x509-ca-cert", "crt");
+ addMIMEType((short) 421, "application/x-xcf", "xcf");
+ addMIMEType((short) 422, "application/x-xfig", "fig");
+ addMIMEType((short) 423, "application/x-xpinstall", "xpi");
+ addMIMEType((short) 424, "audio/32kadpcm");
+ addMIMEType((short) 425, "audio/basic", "au snd");
+ addMIMEType((short) 426, "audio/g.722.1");
+ addMIMEType((short) 427, "audio/l16");
+ addMIMEType((short) 428, "audio/midi", "mid midi kar");
+ addMIMEType((short) 429, "audio/mp4a-latm");
+ addMIMEType((short) 430, "audio/mpa-robust");
+ addMIMEType((short) 431, "audio/mpeg", "mpga mpega mp2 mp3 m4a");
+ addMIMEType((short) 432, "audio/mpegurl", "m3u");
+ addMIMEType((short) 433, "audio/parityfec");
+ addMIMEType((short) 434, "audio/prs.sid", "sid");
+ addMIMEType((short) 435, "audio/telephone-event");
+ addMIMEType((short) 436, "audio/tone");
+ addMIMEType((short) 437, "audio/vnd.cisco.nse");
+ addMIMEType((short) 438, "audio/vnd.cns.anp1");
+ addMIMEType((short) 439, "audio/vnd.cns.inf1");
+ addMIMEType((short) 440, "audio/vnd.digital-winds");
+ addMIMEType((short) 441, "audio/vnd.everad.plj");
+ addMIMEType((short) 442, "audio/vnd.lucent.voice");
+ addMIMEType((short) 443, "audio/vnd.nortel.vbk");
+ addMIMEType((short) 444, "audio/vnd.nuera.ecelp4800");
+ addMIMEType((short) 445, "audio/vnd.nuera.ecelp7470");
+ addMIMEType((short) 446, "audio/vnd.nuera.ecelp9600");
+ addMIMEType((short) 447, "audio/vnd.octel.sbc");
+ addMIMEType((short) 448, "audio/vnd.qcelp");
+ addMIMEType((short) 449, "audio/vnd.rhetorex.32kadpcm");
+ addMIMEType((short) 450, "audio/vnd.vmx.cvsd");
+ addMIMEType((short) 451, "audio/x-aiff", "aif aiff aifc");
+ addMIMEType((short) 452, "audio/x-gsm", "gsm");
+ addMIMEType((short) 453, "audio/x-mpegurl", "m3u");
+ addMIMEType((short) 454, "audio/x-ms-wma", "wma");
+ addMIMEType((short) 455, "audio/x-ms-wax", "wax");
+ addMIMEType((short) 456, "audio/x-pn-realaudio-plugin");
+ addMIMEType((short) 457, "audio/x-pn-realaudio", "ra rm ram");
+ addMIMEType((short) 458, "audio/x-realaudio", "ra");
+ addMIMEType((short) 459, "audio/x-scpls", "pls");
+ addMIMEType((short) 460, "audio/x-sd2", "sd2");
+ addMIMEType((short) 461, "audio/x-wav", "wav");
+ addMIMEType((short) 462, "chemical/x-alchemy", "alc");
+ addMIMEType((short) 463, "chemical/x-cache", "cac cache");
+ addMIMEType((short) 464, "chemical/x-cache-csf", "csf");
+ addMIMEType((short) 465, "chemical/x-cactvs-binary", "cbin cascii ctab");
+ addMIMEType((short) 466, "chemical/x-cdx", "cdx");
+ addMIMEType((short) 467, "chemical/x-cerius", "cer");
+ addMIMEType((short) 468, "chemical/x-chem3d", "c3d");
+ addMIMEType((short) 469, "chemical/x-chemdraw", "chm");
+ addMIMEType((short) 470, "chemical/x-cif", "cif");
+ addMIMEType((short) 471, "chemical/x-cmdf", "cmdf");
+ addMIMEType((short) 472, "chemical/x-cml", "cml");
+ addMIMEType((short) 473, "chemical/x-compass", "cpa");
+ addMIMEType((short) 474, "chemical/x-crossfire", "bsd");
+ addMIMEType((short) 475, "chemical/x-csml", "csml csm");
+ addMIMEType((short) 476, "chemical/x-ctx", "ctx");
+ addMIMEType((short) 477, "chemical/x-cxf", "cxf cef");
+ addMIMEType((short) 478, "chemical/x-embl-dl-nucleotide", "emb embl");
+ addMIMEType((short) 479, "chemical/x-galactic-spc", "spc");
+ addMIMEType((short) 480, "chemical/x-gamess-input", "inp gam gamin");
+ addMIMEType((short) 481, "chemical/x-gaussian-checkpoint", "fch fchk");
+ addMIMEType((short) 482, "chemical/x-gaussian-cube", "cub");
+ addMIMEType((short) 483, "chemical/x-gaussian-input", "gau gjc gjf");
+ addMIMEType((short) 484, "chemical/x-gaussian-log", "gal");
+ addMIMEType((short) 485, "chemical/x-gcg8-sequence", "gcg");
+ addMIMEType((short) 486, "chemical/x-genbank", "gen");
+ addMIMEType((short) 487, "chemical/x-hin", "hin");
+ addMIMEType((short) 488, "chemical/x-isostar", "istr ist");
+ addMIMEType((short) 489, "chemical/x-jcamp-dx", "jdx dx");
+ addMIMEType((short) 490, "chemical/x-kinemage", "kin");
+ addMIMEType((short) 491, "chemical/x-macmolecule", "mcm");
+ addMIMEType((short) 492, "chemical/x-macromodel-input", "mmd mmod");
+ addMIMEType((short) 493, "chemical/x-mdl-molfile", "mol");
+ addMIMEType((short) 494, "chemical/x-mdl-rdfile", "rd");
+ addMIMEType((short) 495, "chemical/x-mdl-rxnfile", "rxn");
+ addMIMEType((short) 496, "chemical/x-mdl-sdfile", "sd sdf");
+ addMIMEType((short) 497, "chemical/x-mdl-tgf", "tgf");
+ addMIMEType((short) 498, "chemical/x-mmcif", "mcif");
+ addMIMEType((short) 499, "chemical/x-mol2", "mol2");
+ addMIMEType((short) 500, "chemical/x-molconn-Z", "b");
+ addMIMEType((short) 501, "chemical/x-mopac-graph", "gpt");
+ addMIMEType((short) 502, "chemical/x-mopac-input", "mop mopcrt mpc dat zmt");
+ addMIMEType((short) 503, "chemical/x-mopac-out", "moo");
+ addMIMEType((short) 504, "chemical/x-mopac-vib", "mvb");
+ addMIMEType((short) 505, "chemical/x-ncbi-asn1", "asn");
+ addMIMEType((short) 506, "chemical/x-ncbi-asn1-ascii", "prt ent");
+ addMIMEType((short) 507, "chemical/x-ncbi-asn1-binary", "val aso");
+ addMIMEType((short) 508, "chemical/x-ncbi-asn1-spec", "asn");
+ addMIMEType((short) 509, "chemical/x-pdb", "pdb ent");
+ addMIMEType((short) 510, "chemical/x-rosdal", "ros");
+ addMIMEType((short) 511, "chemical/x-swissprot", "sw");
+ addMIMEType((short) 512, "chemical/x-vamas-iso14976", "vms");
+ addMIMEType((short) 513, "chemical/x-vmd", "vmd");
+ addMIMEType((short) 514, "chemical/x-xtel", "xtel");
+ addMIMEType((short) 515, "chemical/x-xyz", "xyz");
+ addMIMEType((short) 516, "image/cgm");
+ addMIMEType((short) 517, "image/g3fax");
+ addMIMEType((short) 518, "image/gif", "gif");
+ addMIMEType((short) 519, "image/ief", "ief");
+ addMIMEType((short) 520, "image/jpeg", "jpeg jpg jpe");
+ addMIMEType((short) 521, "image/naplps");
+ addMIMEType((short) 522, "image/pcx", "pcx");
+ addMIMEType((short) 523, "image/png", "png");
+ addMIMEType((short) 524, "image/prs.btif");
+ addMIMEType((short) 525, "image/prs.pti");
+ addMIMEType((short) 526, "image/svg+xml", "svg svgz");
+ addMIMEType((short) 527, "image/tiff", "tiff tif");
+ addMIMEType((short) 528, "image/vnd.cns.inf2");
+ addMIMEType((short) 529, "image/vnd.djvu", "djvu djv");
+ addMIMEType((short) 530, "image/vnd.dwg");
+ addMIMEType((short) 531, "image/vnd.dxf");
+ addMIMEType((short) 532, "image/vnd.fastbidsheet");
+ addMIMEType((short) 533, "image/vnd.fpx");
+ addMIMEType((short) 534, "image/vnd.fst");
+ addMIMEType((short) 535, "image/vnd.fujixerox.edmics-mmr");
+ addMIMEType((short) 536, "image/vnd.fujixerox.edmics-rlc");
+ addMIMEType((short) 537, "image/vnd.mix");
+ addMIMEType((short) 538, "image/vnd.net-fpx");
+ addMIMEType((short) 539, "image/vnd.svf");
+ addMIMEType((short) 540, "image/vnd.wap.wbmp", "wbmp");
+ addMIMEType((short) 541, "image/vnd.xiff");
+ addMIMEType((short) 542, "image/x-cmu-raster", "ras");
+ addMIMEType((short) 543, "image/x-coreldraw", "cdr");
+ addMIMEType((short) 544, "image/x-coreldrawpattern", "pat");
+ addMIMEType((short) 545, "image/x-coreldrawtemplate", "cdt");
+ addMIMEType((short) 546, "image/x-corelphotopaint", "cpt");
+ addMIMEType((short) 547, "image/x-icon", "ico");
+ addMIMEType((short) 548, "image/x-jg", "art");
+ addMIMEType((short) 549, "image/x-jng", "jng");
+ addMIMEType((short) 550, "image/x-ms-bmp", "bmp");
+ addMIMEType((short) 551, "image/x-photoshop", "psd");
+ addMIMEType((short) 552, "image/x-portable-anymap", "pnm");
+ addMIMEType((short) 553, "image/x-portable-bitmap", "pbm");
+ addMIMEType((short) 554, "image/x-portable-graymap", "pgm");
+ addMIMEType((short) 555, "image/x-portable-pixmap", "ppm");
+ addMIMEType((short) 556, "image/x-rgb", "rgb");
+ addMIMEType((short) 557, "image/x-xbitmap", "xbm");
+ addMIMEType((short) 558, "image/x-xpixmap", "xpm");
+ addMIMEType((short) 559, "image/x-xwindowdump", "xwd");
+ addMIMEType((short) 560, "inode/chardevice");
+ addMIMEType((short) 561, "inode/blockdevice");
+ addMIMEType((short) 562, "inode/directory-locked");
+ addMIMEType((short) 563, "inode/directory");
+ addMIMEType((short) 564, "inode/fifo");
+ addMIMEType((short) 565, "inode/socket");
+ addMIMEType((short) 566, "message/delivery-status");
+ addMIMEType((short) 567, "message/disposition-notification");
+ addMIMEType((short) 568, "message/external-body");
+ addMIMEType((short) 569, "message/http");
+ addMIMEType((short) 570, "message/s-http");
+ addMIMEType((short) 571, "message/news");
+ addMIMEType((short) 572, "message/partial");
+ addMIMEType((short) 573, "message/rfc822");
+ addMIMEType((short) 574, "model/iges", "igs iges");
+ addMIMEType((short) 575, "model/mesh", "msh mesh silo");
+ addMIMEType((short) 576, "model/vnd.dwf");
+ addMIMEType((short) 577, "model/vnd.flatland.3dml");
+ addMIMEType((short) 578, "model/vnd.gdl");
+ addMIMEType((short) 579, "model/vnd.gs-gdl");
+ addMIMEType((short) 580, "model/vnd.gtw");
+ addMIMEType((short) 581, "model/vnd.mts");
+ addMIMEType((short) 582, "model/vnd.vtu");
+ addMIMEType((short) 583, "model/vrml", "wrl vrml");
+ addMIMEType((short) 584, "multipart/alternative");
+ addMIMEType((short) 585, "multipart/appledouble");
+ addMIMEType((short) 586, "multipart/byteranges");
+ addMIMEType((short) 587, "multipart/digest");
+ addMIMEType((short) 588, "multipart/encrypted");
+ addMIMEType((short) 589, "multipart/form-data");
+ addMIMEType((short) 590, "multipart/header-set");
+ addMIMEType((short) 591, "multipart/mixed");
+ addMIMEType((short) 592, "multipart/parallel");
+ addMIMEType((short) 593, "multipart/related");
+ addMIMEType((short) 594, "multipart/report");
+ addMIMEType((short) 595, "multipart/signed");
+ addMIMEType((short) 596, "multipart/voice-message");
+ addMIMEType((short) 597, "text/calendar", "ics icz");
+ addMIMEType((short) 598, "text/comma-separated-values", "csv");
+ addMIMEType((short) 599, "text/css", "css");
+ addMIMEType((short) 600, "text/directory");
+ addMIMEType((short) 601, "text/english");
+ addMIMEType((short) 602, "text/enriched");
+ addMIMEType((short) 603, "text/h323", "323");
+ addMIMEType((short) 604, "text/html", "html htm shtml");
+ addMIMEType((short) 605, "text/iuls", "uls");
+ addMIMEType((short) 606, "text/mathml", "mml");
+ addMIMEType((short) 607, "text/parityfec");
+ addMIMEType((short) 608, "text/plain", "asc txt text diff pot");
+ addMIMEType((short) 609, "text/prs.lines.tag");
+ addMIMEType((short) 610, "text/x-psp", "psp");
+ addMIMEType((short) 611, "text/rfc822-headers");
+ addMIMEType((short) 612, "text/richtext", "rtx");
+ addMIMEType((short) 613, "text/rtf", "rtf");
+ addMIMEType((short) 614, "text/scriptlet", "sct wsc");
+ addMIMEType((short) 615, "text/t140");
+ addMIMEType((short) 616, "text/texmacs", "tm ts");
+ addMIMEType((short) 617, "text/tab-separated-values", "tsv");
+ addMIMEType((short) 618, "text/uri-list");
+ addMIMEType((short) 619, "text/vnd.abc");
+ addMIMEType((short) 620, "text/vnd.curl");
+ addMIMEType((short) 621, "text/vnd.DMClientScript");
+ addMIMEType((short) 622, "text/vnd.flatland.3dml");
+ addMIMEType((short) 623, "text/vnd.fly");
+ addMIMEType((short) 624, "text/vnd.fmi.flexstor");
+ addMIMEType((short) 625, "text/vnd.in3d.3dml");
+ addMIMEType((short) 626, "text/vnd.in3d.spot");
+ addMIMEType((short) 627, "text/vnd.IPTC.NewsML");
+ addMIMEType((short) 628, "text/vnd.IPTC.NITF");
+ addMIMEType((short) 629, "text/vnd.latex-z");
+ addMIMEType((short) 630, "text/vnd.motorola.reflex");
+ addMIMEType((short) 631, "text/vnd.ms-mediapackage");
+ addMIMEType((short) 632, "text/vnd.sun.j2me.app-descriptor", "jad");
+ addMIMEType((short) 633, "text/vnd.wap.si");
+ addMIMEType((short) 634, "text/vnd.wap.sl");
+ addMIMEType((short) 635, "text/vnd.wap.wml", "wml");
+ addMIMEType((short) 636, "text/vnd.wap.wmlscript", "wmls");
+ addMIMEType((short) 637, "text/x-bibtex", "bib");
+ addMIMEType((short) 638, "text/x-c++hdr", "h++ hpp hxx hh");
+ addMIMEType((short) 639, "text/x-c++src", "c++ cpp cxx cc");
+ addMIMEType((short) 640, "text/x-chdr", "h");
+ addMIMEType((short) 641, "text/x-crontab");
+ addMIMEType((short) 642, "text/x-csh", "csh");
+ addMIMEType((short) 643, "text/x-csrc", "c");
+ addMIMEType((short) 644, "text/x-haskell", "hs");
+ addMIMEType((short) 645, "text/x-java", "java");
+ addMIMEType((short) 646, "text/x-literate-haskell", "lhs");
+ addMIMEType((short) 647, "text/x-makefile");
+ addMIMEType((short) 648, "text/x-moc", "moc");
+ addMIMEType((short) 649, "text/x-pascal", "p pas");
+ addMIMEType((short) 650, "text/x-pcs-gcd", "gcd");
+ addMIMEType((short) 651, "text/x-perl", "pl pm");
+ addMIMEType((short) 652, "text/x-python", "py");
+ addMIMEType((short) 653, "text/x-server-parsed-html");
+ addMIMEType((short) 654, "text/x-setext", "etx");
+ addMIMEType((short) 655, "text/x-sh", "sh");
+ addMIMEType((short) 656, "text/x-tcl", "tcl tk");
+ addMIMEType((short) 657, "text/x-tex", "tex ltx sty cls");
+ addMIMEType((short) 658, "text/x-vcalendar", "vcs");
+ addMIMEType((short) 659, "text/x-vcard", "vcf");
+ addMIMEType((short) 660, "video/dl", "dl");
+ addMIMEType((short) 661, "video/dv", "dif dv");
+ addMIMEType((short) 662, "video/fli", "fli");
+ addMIMEType((short) 663, "video/gl", "gl");
+ addMIMEType((short) 664, "video/mpeg", "mpeg mpg mpe");
+ addMIMEType((short) 665, "video/mp4", "mp4");
+ addMIMEType((short) 666, "video/quicktime", "qt mov");
+ addMIMEType((short) 667, "video/mp4v-es");
+ addMIMEType((short) 668, "video/parityfec");
+ addMIMEType((short) 669, "video/pointer");
+ addMIMEType((short) 670, "video/vnd.fvt");
+ addMIMEType((short) 671, "video/vnd.motorola.video");
+ addMIMEType((short) 672, "video/vnd.motorola.videop");
+ addMIMEType((short) 673, "video/vnd.mpegurl", "mxu");
+ addMIMEType((short) 674, "video/vnd.mts");
+ addMIMEType((short) 675, "video/vnd.nokia.interleaved-multimedia");
+ addMIMEType((short) 676, "video/vnd.vivo");
+ addMIMEType((short) 677, "video/x-la-asf", "lsf lsx");
+ addMIMEType((short) 678, "video/x-mng", "mng");
+ addMIMEType((short) 679, "video/x-ms-asf", "asf asx");
+ addMIMEType((short) 680, "video/x-ms-wm", "wm");
+ addMIMEType((short) 681, "video/x-ms-wmv", "wmv");
+ addMIMEType((short) 682, "video/x-ms-wmx", "wmx");
+ addMIMEType((short) 683, "video/x-ms-wvx", "wvx");
+ addMIMEType((short) 684, "video/x-msvideo", "avi");
+ addMIMEType((short) 685, "video/x-sgi-movie", "movie");
+ addMIMEType((short) 686, "x-conference/x-cooltalk", "ice");
+ addMIMEType((short) 687, "x-world/x-vrml", "vrm vrml wrl");
+ }
+
+ /** Guess a MIME type from a filename */
+ public static String guessMIMEType(String arg) {
+ int x = arg.lastIndexOf('.');
+ if(x == -1 || x == arg.length()-1)
+ return DEFAULT_MIME_TYPE;
+ String ext = arg.substring(x+1).toLowerCase();
+ Short mimeIndexOb = mimeTypesByExtension.get(ext);
+ if(mimeIndexOb != null) {
+ return mimeTypesByNumber.get(mimeIndexOb.intValue());
+ }
+ return DEFAULT_MIME_TYPE;
+ }
+
+ public static String getExtension(String type) {
+ short typeNumber = byName(type);
+ if(typeNumber < 0) return null;
+ return primaryExtensionByMimeNumber.get(typeNumber);
+ }
+
+ public static String[] getAllMIMETypes() {
+ return mimeTypesByNumber.toArray(new String[mimeTypesByNumber.size()]);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - SortedListModel.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.swing.AbstractListModel;
+
+/**
+ * @param <T>
+ * The type of the elements
+ * @author David Roden <droden@gmail.com>
+ */
+public class SortedListModel<T extends Comparable<T>> extends AbstractListModel implements List<T> {
+
+ /** The elements. */
+ private List<T> elements = new ArrayList<T>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSize() {
+ return size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getElementAt(int index) {
+ return elements.get(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void add(int index, T element) {
+ elements.add(index, element);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean add(T o) {
+ boolean result = elements.add(o);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addAll(Collection<? extends T> c) {
+ boolean result = elements.addAll(c);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addAll(int index, Collection<? extends T> c) {
+ boolean result = elements.addAll(index, c);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clear() {
+ elements.clear();
+ fireContentsChanged(this, 0, size());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean contains(Object o) {
+ return elements.contains(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean containsAll(Collection<?> c) {
+ return elements.containsAll(c);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object o) {
+ return elements.equals(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public T get(int index) {
+ return elements.get(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return elements.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int indexOf(Object o) {
+ return elements.indexOf(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return elements.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<T> iterator() {
+ return elements.iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int lastIndexOf(Object o) {
+ return elements.lastIndexOf(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ListIterator<T> listIterator() {
+ return elements.listIterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ListIterator<T> listIterator(int index) {
+ return elements.listIterator(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public T remove(int index) {
+ fireContentsChanged(this, 0, size());
+ return elements.remove(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean remove(Object o) {
+ fireContentsChanged(this, 0, size());
+ return elements.remove(o);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean removeAll(Collection<?> c) {
+ fireContentsChanged(this, 0, size());
+ return elements.removeAll(c);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean retainAll(Collection<?> c) {
+ fireContentsChanged(this, 0, size());
+ return elements.retainAll(c);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public T set(int index, T element) {
+ T result = elements.set(index, element);
+ Collections.sort(elements);
+ fireContentsChanged(this, 0, size());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size() {
+ return elements.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<T> subList(int fromIndex, int toIndex) {
+ return elements.subList(fromIndex, toIndex);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object[] toArray() {
+ return elements.toArray();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public <U extends Object> U[] toArray(U[] a) {
+ return elements.toArray(a);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - TLabel.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.awt.Component;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class TLabel extends JLabel {
+
+ public TLabel() {
+ super();
+ }
+
+ public TLabel(int mnemonic, Component labelFor) {
+ super();
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(Icon image) {
+ super(image);
+ }
+
+ public TLabel(Icon image, int mnemonic, Component labelFor) {
+ super(image);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(Icon image, int horizontalAlignment) {
+ super(image);
+ }
+
+ public TLabel(Icon image, int horizontalAlignment, int mnemonic, Component labelFor) {
+ super(image);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(String text) {
+ super(text);
+ }
+
+ public TLabel(String text, int mnemonic, Component labelFor) {
+ super(text);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ setAlignmentX(0.0f);
+ }
+
+ public TLabel(String text, Icon icon, int horizontalAlignment) {
+ super(text, icon, horizontalAlignment);
+ }
+
+ public TLabel(String text, Icon icon, int horizontalAlignment, int mnemonic, Component labelFor) {
+ super(text, icon, horizontalAlignment);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+ public TLabel(String text, int horizontalAlignment) {
+ super(text, horizontalAlignment);
+ }
+
+ public TLabel(String text, int horizontalAlignment, int mnemonic, Component labelFor) {
+ super(text, horizontalAlignment);
+ setDisplayedMnemonic(mnemonic);
+ setLabelFor(labelFor);
+ }
+
+}
--- /dev/null
+/*
+ * jSite - TWizard.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class TWizard extends JFrame implements WindowListener {
+
+ protected List<WizardListener> wizardListeners = new ArrayList<WizardListener>();
+
+ private Action previousAction;
+ private Action nextAction;
+ private Action quitAction;
+ private JLabel pageIcon;
+ private JPanel pagePanel;
+ private JLabel pageHeading;
+ private JLabel pageDescription;
+
+ @Override
+ protected void frameInit() {
+ super.frameInit();
+ setResizable(false);
+ addWindowListener(this);
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ createActions();
+
+ pageIcon = new JLabel();
+ pageIcon.setVerticalAlignment(SwingConstants.TOP);
+ pageHeading = new JLabel();
+ pageHeading.setFont(pageHeading.getFont().deriveFont(pageHeading.getFont().getSize() * 2.0f).deriveFont(Font.BOLD));
+ pageDescription = new JLabel();
+
+ JPanel contentPane = new JPanel(new BorderLayout(12, 12));
+ contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
+
+ JPanel topPanel = new JPanel(new BorderLayout(12, 12));
+ contentPane.add(topPanel, BorderLayout.PAGE_START);
+
+ topPanel.add(pageIcon, BorderLayout.LINE_START);
+
+ JPanel textPanel = new JPanel(new BorderLayout(12, 12));
+ topPanel.add(textPanel, BorderLayout.CENTER);
+ textPanel.add(pageHeading, BorderLayout.PAGE_START);
+ textPanel.add(pageDescription, BorderLayout.CENTER);
+
+ pagePanel = new JPanel(new BorderLayout(12, 12));
+ contentPane.add(pagePanel, BorderLayout.CENTER);
+
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
+ buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12));
+ buttonPanel.add(new JButton(previousAction));
+ buttonPanel.add(new JButton(nextAction));
+ buttonPanel.add(new JButton(quitAction));
+ contentPane.add(buttonPanel, BorderLayout.PAGE_END);
+
+ setContentPane(contentPane);
+ }
+
+ @Override
+ public void pack() {
+ super.pack();
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2);
+ // System.out.println("resized to: " + getWidth() + "x" + getHeight());
+ }
+
+ private void createActions() {
+ previousAction = new AbstractAction("Previous") {
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionPrevious();
+ }
+ };
+
+ nextAction = new AbstractAction("Next") {
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionNext();
+ }
+ };
+
+ quitAction = new AbstractAction("Quit") {
+ public void actionPerformed(ActionEvent actionEvent) {
+ actionQuit();
+ }
+ };
+ }
+
+ public void addWizardListener(WizardListener wizardListener) {
+ wizardListeners.add(wizardListener);
+ }
+
+ public void removeWizardListener(WizardListener wizardListener) {
+ wizardListeners.remove(wizardListener);
+ }
+
+ protected void fireWizardPreviousPressed() {
+ for (WizardListener wizardListener: wizardListeners) {
+ wizardListener.wizardPreviousPressed(this);
+ }
+ }
+
+ protected void fireWizardNextPressed() {
+ for (WizardListener wizardListener: wizardListeners) {
+ wizardListener.wizardNextPressed(this);
+ }
+ }
+
+ protected void fireWizardQuitPressed() {
+ for (WizardListener wizardListener: wizardListeners) {
+ wizardListener.wizardQuitPressed(this);
+ }
+ }
+
+ public void setIcon(Icon icon) {
+ pageIcon.setIcon(icon);
+ }
+
+ public void setPage(TWizardPage page) {
+ setVisible(false);
+ pageHeading.setText(page.getHeading());
+ pageDescription.setText(page.getDescription());
+ if (pagePanel.getComponentCount() > 0) {
+ if (pagePanel.getComponent(0) instanceof TWizardPage) {
+ ((TWizardPage) pagePanel.getComponent(0)).pageDeleted(this);
+ }
+ }
+ pagePanel.removeAll();
+ pagePanel.add(page, BorderLayout.CENTER);
+ page.pageAdded(this);
+ pack();
+ setTitle(page.getHeading());
+ setVisible(true);
+ }
+
+ public TWizardPage getPage() {
+ return (TWizardPage) pagePanel.getComponent(0);
+ }
+
+ public void setPreviousEnabled(boolean previousEnabled) {
+ previousAction.setEnabled(previousEnabled);
+ }
+
+ public void setPreviousName(String previousName) {
+ previousAction.putValue(Action.NAME, previousName);
+ }
+
+ public void setNextEnabled(boolean nextEnabled) {
+ nextAction.setEnabled(nextEnabled);
+ }
+
+ public void setNextName(String nextName) {
+ nextAction.putValue(Action.NAME, nextName);
+ }
+
+ public void setQuitEnabled(boolean quitEnabled) {
+ quitAction.setEnabled(quitEnabled);
+ }
+
+ public void setQuitName(String quitName) {
+ quitAction.putValue(Action.NAME, quitName);
+ }
+
+ protected void actionPrevious() {
+ fireWizardPreviousPressed();
+ }
+
+ protected void actionNext() {
+ fireWizardNextPressed();
+ }
+
+ protected void actionQuit() {
+ fireWizardQuitPressed();
+ }
+
+ //
+ // INTERFACE WindowListener
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowOpened(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowClosing(WindowEvent e) {
+ fireWizardQuitPressed();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowClosed(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowIconified(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowDeiconified(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowActivated(WindowEvent e) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void windowDeactivated(WindowEvent e) {
+ }
+
+}
--- /dev/null
+/*
+ * jSite - TWizardPage.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import javax.swing.JPanel;
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public class TWizardPage extends JPanel {
+
+ protected final TWizard wizard;
+ protected String heading;
+ protected String description;
+
+ public TWizardPage(final TWizard wizard) {
+ this.wizard = wizard;
+ }
+
+ public TWizardPage(final TWizard wizard, String heading) {
+ this.wizard = wizard;
+ this.heading = heading;
+ }
+
+ public TWizardPage(final TWizard wizard, String heading, String description) {
+ this(wizard, heading);
+ this.description = description;
+ }
+
+ /**
+ * @return Returns the description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * @param description
+ * The description to set.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * @return Returns the heading.
+ */
+ public String getHeading() {
+ return heading;
+ }
+
+ /**
+ * @param heading
+ * The heading to set.
+ */
+ public void setHeading(String heading) {
+ this.heading = heading;
+ }
+
+ public void pageAdded(TWizard wizard) {
+ }
+
+ public void pageDeleted(TWizard wizard) {
+ }
+
+}
--- /dev/null
+/*
+ * jSite - WizardListener.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.swing;
+
+import java.util.EventListener;
+
+
+/**
+ * @author David Roden <droden@gmail.com>
+ * @version $Id$
+ */
+public interface WizardListener extends EventListener {
+
+ public void wizardNextPressed(TWizard wizard);
+ public void wizardPreviousPressed(TWizard wizard);
+ public void wizardQuitPressed(TWizard wizard);
+
+}
--- /dev/null
+/*
+ * jSite - SimpleXML.java - Copyright © 2006–2012 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
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.xml;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+/**
+ * SimpleXML is a helper class to construct XML trees in a fast and simple way.
+ * Construct a new XML tree by calling {@link #SimpleXML(String)} and append new
+ * nodes by calling {@link #append(String)}.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id:SimpleXML.java 221 2006-03-06 14:46:49Z bombe $
+ */
+public class SimpleXML {
+
+ /**
+ * A {@link List} containing all child nodes of this node.
+ */
+ private List<SimpleXML> children = new ArrayList<SimpleXML>();
+
+ /**
+ * The name of this node.
+ */
+ private String name = null;
+
+ /**
+ * The value of this node.
+ */
+ private String value = null;
+
+ /**
+ * Constructs a new XML node without a name.
+ */
+ public SimpleXML() {
+ super();
+ }
+
+ /**
+ * Constructs a new XML node with the specified name.
+ *
+ * @param name
+ * The name of the new node
+ */
+ public SimpleXML(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the child node of this node with the specified name. If there are
+ * several child nodes with the specified name only the first node is
+ * returned.
+ *
+ * @param nodeName
+ * The name of the child node
+ * @return The child node, or <code>null</code> if there is no child node
+ * with the specified name
+ */
+ public SimpleXML getNode(String nodeName) {
+ for (int index = 0, count = children.size(); index < count; index++) {
+ if (children.get(index).name.equals(nodeName)) {
+ return children.get(index);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the child node that is specified by the names. The first element
+ * of <code>nodeNames</code> is the name of the child node of this node, the
+ * second element of <code>nodeNames</code> is the name of a child node's
+ * child node, and so on. By using this method you can descend into an XML
+ * tree pretty fast.
+ *
+ * <pre>
+ *
+ * SimpleXML deepNode = topNode.getNodes(new String[] { "person", "address", "number" });
+ * </pre>
+ *
+ * @param nodeNames
+ * @return A node that is a deep child of this node, or <code>null</code> if
+ * the specified node does not eixst
+ */
+ public SimpleXML getNode(String[] nodeNames) {
+ SimpleXML node = this;
+ for (String nodeName : nodeNames) {
+ node = node.getNode(nodeName);
+ }
+ return node;
+ }
+
+ /**
+ * Returns all child nodes of this node.
+ *
+ * @return All child nodes of this node
+ */
+ public SimpleXML[] getNodes() {
+ return getNodes(null);
+ }
+
+ /**
+ * Returns all child nodes of this node with the specified name. If there
+ * are no child nodes with the specified name an empty array is returned.
+ *
+ * @param nodeName
+ * The name of the nodes to retrieve, or <code>null</code> to
+ * retrieve all nodes
+ * @return All child nodes with the specified name
+ */
+ public SimpleXML[] getNodes(String nodeName) {
+ List<SimpleXML> resultList = new ArrayList<SimpleXML>();
+ for (SimpleXML child : children) {
+ if ((nodeName == null) || child.name.equals(nodeName)) {
+ resultList.add(child);
+ }
+ }
+ return resultList.toArray(new SimpleXML[resultList.size()]);
+ }
+
+ /**
+ * Appends a new XML node with the specified name and returns the new node.
+ * With this method you can create deep structures very fast.
+ *
+ * <pre>
+ *
+ * SimpleXML mouseNode = topNode.append("computer").append("bus").append("usb").append("mouse");
+ * </pre>
+ *
+ * @param nodeName
+ * The name of the node to append as a child to this node
+ * @return The new node
+ */
+ public SimpleXML append(String nodeName) {
+ return append(new SimpleXML(nodeName));
+ }
+
+ /**
+ * Appends a new XML node with the specified name and value and returns the
+ * new node.
+ *
+ * @param nodeName
+ * The name of the node to append
+ * @param nodeValue
+ * The value of the node to append
+ * @return The newly appended node
+ */
+ public SimpleXML append(String nodeName, String nodeValue) {
+ return append(nodeName).setValue(nodeValue);
+ }
+
+ /**
+ * Appends the node with all its child nodes to this node and returns the
+ * child node.
+ *
+ * @param newChild
+ * The node to append as a child
+ * @return The child node that was appended
+ */
+ public SimpleXML append(SimpleXML newChild) {
+ children.add(newChild);
+ return newChild;
+ }
+
+ public void remove(SimpleXML child) {
+ children.remove(child);
+ }
+
+ public void remove(String childName) {
+ SimpleXML child = getNode(childName);
+ if (child != null) {
+ remove(child);
+ }
+ }
+
+ public void replace(String childName, String value) {
+ remove(childName);
+ append(childName, value);
+ }
+
+ public void replace(SimpleXML childNode) {
+ remove(childNode.getName());
+ append(childNode);
+ }
+
+ public void removeAll() {
+ children.clear();
+ }
+
+ /**
+ * Sets the value of this node.
+ *
+ * @param nodeValue
+ * The new value of this node
+ * @return This node
+ */
+ public SimpleXML setValue(String nodeValue) {
+ value = nodeValue;
+ return this;
+ }
+
+ /**
+ * Returns the name of this node.
+ *
+ * @return The name of this node
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value of this node.
+ *
+ * @return The value of this node
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Returns the value of this node. If the node does not have a value, the
+ * given default value is returned.
+ *
+ *@param defaultValue
+ * The default value to return if the node does not have a value
+ * @return The value of this node
+ */
+ public String getValue(String defaultValue) {
+ return (value == null) ? defaultValue : value;
+ }
+
+ /**
+ * Creates a {@link Document} from this node and all its child nodes.
+ *
+ * @return The {@link Document} created from this node
+ */
+ public Document getDocument() {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ try {
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document document = documentBuilder.newDocument();
+ Element rootElement = document.createElement(name);
+ document.appendChild(rootElement);
+ addChildren(rootElement);
+ return document;
+ } catch (ParserConfigurationException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Appends all children of this node to the specified {@link Element}. If a
+ * node has a value that is not <code>null</code> the value is appended as a
+ * text node.
+ *
+ * @param rootElement
+ * The element to attach this node's children to
+ */
+ private void addChildren(Element rootElement) {
+ for (SimpleXML child : children) {
+ Element childElement = rootElement.getOwnerDocument().createElement(child.name);
+ rootElement.appendChild(childElement);
+ if (child.value != null) {
+ Text childText = rootElement.getOwnerDocument().createTextNode(child.value);
+ childElement.appendChild(childText);
+ } else {
+ child.addChildren(childElement);
+ }
+ }
+ }
+
+ /**
+ * Creates a SimpleXML node from the specified {@link Document}. The
+ * SimpleXML node of the document's top-level node is returned.
+ *
+ * @param document
+ * The {@link Document} to create a SimpleXML node from
+ * @return The SimpleXML node created from the document's top-level node
+ */
+ public static SimpleXML fromDocument(Document document) {
+ SimpleXML xmlDocument = new SimpleXML(document.getFirstChild().getNodeName());
+ document.normalizeDocument();
+ return addDocumentChildren(xmlDocument, document.getFirstChild());
+ }
+
+ /**
+ * Appends the child nodes of the specified {@link Document} to this node.
+ * Text nodes are converted into a node's value.
+ *
+ * @param xmlDocument
+ * The SimpleXML node to append the child nodes to
+ * @param document
+ * The document whose child nodes to append
+ * @return The SimpleXML node the child nodes were appended to
+ */
+ private static SimpleXML addDocumentChildren(SimpleXML xmlDocument, Node document) {
+ NodeList childNodes = document.getChildNodes();
+ for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; childIndex++) {
+ Node childNode = childNodes.item(childIndex);
+ if ((childNode.getChildNodes().getLength() == 1) && (childNode.getFirstChild().getNodeName().equals("#text"))) {
+ xmlDocument.append(childNode.getNodeName(), childNode.getFirstChild().getNodeValue());
+ } else {
+ if (!childNode.getNodeName().equals("#text") || (childNode.getChildNodes().getLength() != 0)) {
+ SimpleXML newXML = xmlDocument.append(childNode.getNodeName());
+ addDocumentChildren(newXML, childNode);
+ }
+ }
+ }
+ return xmlDocument;
+ }
+
+}
--- /dev/null
+/*
+ * jSite - XML.java - Copyright © 2006–2012 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 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package de.todesbaum.util.xml;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Document;
+
+
+/**
+ * Contains method to transform DOM XML trees to byte arrays and vice versa.
+ *
+ * @author David Roden <droden@gmail.com>
+ * @version $Id:XML.java 221 2006-03-06 14:46:49Z bombe $
+ */
+public class XML {
+
+ /** Cached document builder factory. */
+ private static DocumentBuilderFactory documentBuilderFactory = null;
+
+ /** Cached document builder. */
+ private static DocumentBuilder documentBuilder = null;
+
+ /** Cached transformer factory. */
+ private static TransformerFactory transformerFactory = null;
+
+ /** Does nothing. */
+ private XML() {
+ }
+
+ /**
+ * Returns a document builder factory. If possible the cached instance will be returned.
+ *
+ * @return A document builder factory
+ */
+ private static DocumentBuilderFactory getDocumentBuilderFactory() {
+ if (documentBuilderFactory != null) {
+ return documentBuilderFactory;
+ }
+ documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ return documentBuilderFactory;
+ }
+
+ /**
+ * Returns a document builder. If possible the cached instance will be returned.
+ *
+ * @return A document builder
+ */
+ private static DocumentBuilder getDocumentBuilder() {
+ if (documentBuilder != null) {
+ return documentBuilder;
+ }
+ try {
+ documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ }
+ return documentBuilder;
+ }
+
+ /**
+ * Returns a transformer factory. If possible the cached instance will be returned.
+ *
+ * @return A transformer factory
+ */
+ private static TransformerFactory getTransformerFactory() {
+ if (transformerFactory != null) {
+ return transformerFactory;
+ }
+ transformerFactory = TransformerFactory.newInstance();
+ return transformerFactory;
+ }
+
+ /**
+ * Creates a new XML document.
+ *
+ * @return A new XML document
+ */
+ public static Document createDocument() {
+ return getDocumentBuilder().newDocument();
+ }
+
+ /**
+ * Transforms the DOM XML document into a byte array.
+ *
+ * @param document
+ * The document to transform
+ * @return The byte array containing the XML representation
+ */
+ public static byte[] transformToByteArray(Document document) {
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
+ OutputStreamWriter converter = new OutputStreamWriter(byteOutput, Charset.forName("UTF-8"));
+ Result transformResult = new StreamResult(converter);
+ Source documentSource = new DOMSource(document);
+ try {
+ Transformer transformer = getTransformerFactory().newTransformer();
+ transformer.transform(documentSource, transformResult);
+ byteOutput.close();
+ return byteOutput.toByteArray();
+ } catch (IOException ioe1) {
+ } catch (TransformerConfigurationException tce1) {
+ } catch (TransformerException te1) {
+ } finally {
+ try {
+ byteOutput.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Transforms the byte array into a DOM XML document.
+ *
+ * @param data
+ * The byte array to parse
+ * @return The DOM XML document
+ */
+ public static Document transformToDocument(byte[] data) {
+ ByteArrayInputStream byteInput = new ByteArrayInputStream(data);
+ InputStreamReader converter = new InputStreamReader(byteInput, Charset.forName("UTF-8"));
+ Source xmlSource = new StreamSource(converter);
+ Result xmlResult = new DOMResult();
+ try {
+ Transformer transformer = getTransformerFactory().newTransformer();
+ transformer.transform(xmlSource, xmlResult);
+ return (Document) ((DOMResult) xmlResult).getNode();
+ } catch (TransformerConfigurationException tce1) {
+ } catch (TransformerException te1) {
+ } finally {
+ if (byteInput != null)
+ try {
+ byteInput.close();
+ } catch (IOException ioe1) {
+ }
+ if (converter != null)
+ try {
+ converter.close();
+ } catch (IOException ioe1) {
+ }
+ }
+ return null;
+ }
+
+}
--- /dev/null
+#
+# jSite - jSite.properties - Copyright © 2006–2012 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
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# English language file by David Roden <droden@gmail.com>
+
+# Attention, translators! Most of the strings here are used directly.
+# However, some of them are parsed by MessageFormat
+# (http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html)
+# and thus have to adhere to some rules (check the URL above). This is the
+# case when a line contains placeholders like {0} or {0,number}! In these
+# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
+# otherwise the placeholder will not be replaced!
+
+jsite.general.ok=OK
+jsite.general.cancel=Cancel
+
+jsite.wizard.previous=Previous
+jsite.wizard.next=Next
+jsite.wizard.quit=Quit
+
+jsite.quit.question=Do you really want to quit?
+jsite.quit.question.title=Really quit?
+jsite.quit.overwrite-configuration=<html><b>Overwrite configuration?</b><br><br>A configuration file already exists:<br><code>{0}</code><br><br>Should it be overwritten?</html>
+jsite.quit.overwrite-configuration.title=Overwrite configuration?
+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
+jsite.menu.language.en=English
+jsite.menu.language.de=Deutsch
+jsite.menu.language.fr=Fran\u00e7ais
+jsite.menu.language.it=Italiano
+jsite.menu.language.pl=Polski
+jsite.menu.nodes=Nodes
+jsite.menu.nodes.manage-nodes=Manage nodes
+jsite.menu.options=Options
+jsite.menu.options.preferences=Preferences
+jsite.menu.help=Help
+jsite.menu.help.check-for-updates=Check for Updates
+jsite.menu.help.about=About
+
+jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006\u20132012 David Roden<br>Released under the GNU General Public License</html>
+
+jsite.node-manager.heading=Node Manager
+jsite.node-manager.description=Manage your nodes here.
+jsite.node-manager.node-information=Node Information
+jsite.node-manager.add-node=Add Node
+jsite.node-manager.new-node=New Node
+jsite.node-manager.delete-node=Delete Node
+jsite.node-manager.delete-node.warning=<html><b>Confirm node deletion</b><br><br>Really delete this node?</html>
+jsite.node-manager.name=Name
+jsite.node-manager.hostname=Hostname
+jsite.node-manager.port=Port
+
+jsite.preferences.heading=Preferences
+jsite.preferences.description=Use this page to manage some global settings.
+jsite.preferences.temp-directory=Directory for temporary files
+jsite.preferences.temp-directory.default=Default (chosen by system)
+jsite.preferences.temp-directory.custom=Custom
+jsite.preferences.temp-directory.choose=Choose
+jsite.preferences.temp-directory.choose.approve=Choose
+jsite.preferences.config-directory=Location of configuration file
+jsite.preferences.config-directory.jar=Next to the JAR file
+jsite.preferences.config-directory.home=Home directory
+jsite.preferences.config-directory.custom=Custom directory
+jsite.preferences.insert-options=Insert options
+jsite.preferences.insert-options.use-early-encode=Generate final URI early
+jsite.preferences.insert-options.priority=Priority
+jsite.preferences.insert-options.manifest-putter=Manifest Putter
+
+jsite.insert.heading=Project insert
+jsite.insert.description=Please wait while the project is being inserted.
+jsite.insert.project-information=Project information
+jsite.insert.request-uri=Freesite
+jsite.insert.start-time=Start time
+jsite.insert.starting=Starting\u2026
+jsite.insert.done=Done.
+jsite.insert.done.title=Insert done
+jsite.insert.insert-aborted=The insert was aborted.
+jsite.insert.insert-aborted.title=Insert Aborted
+jsite.insert.progress=Progress
+jsite.insert.k-per-s=KB/s
+jsite.insert.insert-failed=<html><b>Insert failed</b><br><br>The insert of the project failed.<br>Some files could not be inserted.</html>
+jsite.insert.insert-failed-with-cause=<html><b>Insert failed</b><br><br>The insert of the project failed.<br>Some files could not be inserted.<br>The following error occured:<br><br><code>{0}</code></html>
+jsite.insert.insert-failed.title=Insert Failed
+jsite.insert.inserted=<html><b>Project inserted</b><br><br>Your project was inserted successfully.</html>
+jsite.insert.okay-copy-uri=Copy URI to Clipboard
+jsite.insert.reinserted-edition=<html><b>Edition Reinserted</b><br><br>The edition you are just inserting<br>has already been inserted before.</html>
+jsite.insert.reinserted-edition.title=Edition Reinserted
+
+jsite.file-scanner.can-not-read-directory=Can not read directory
+
+jsite.project.heading=Select a Project
+jsite.project.description=Select a project to process from the list below, or create a new project.
+jsite.project.action.browse=Browse
+jsite.project.action.browse.choose=Choose
+jsite.project.action.browse.tooltip=Browse for directory
+jsite.project.action.add-project=Add project
+jsite.project.action.add-project.tooltip=Add a new project
+jsite.project.new-project.name=New Project
+jsite.project.action.delete-project=Delete project
+jsite.project.action.delete-project.tooltip=Delete a project
+jsite.project.action.delete-project.confirm=<html><b>Confirm deletion</b><br><br>The project \u201c{0}\u201d will be deleted!<br>Do you want to continue?</html>
+jsite.project.action.clone-project=Clone project
+jsite.project.action.clone-project.copy=Copy of {0}
+jsite.project.action.clone-project.tooltip=Clone the selected project
+jsite.project.action.copy-uri=Copy URI to Clipboard
+jsite.project.action.copy-uri.tooltip=Copies the URI of the project to the clipboard
+jsite.project.action.manage-keys=Manage Keys
+jsite.project.action.manage-keys.tooltip=Manages the keys of this project
+jsite.project.action.reset-edition=Reset Edition
+jsite.project.action.reset-edition.tooltip=Resets the edition number of the project
+jsite.project.project.information=Project Information
+jsite.project.project.name=Name
+jsite.project.project.description=Description
+jsite.project.project.local-path=Local path
+jsite.project.project.address=Address
+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.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!<br>Also, the edition will be reset.</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>
+
+jsite.project-files.heading=Project Files
+jsite.project-files.description=<html>On this page you can specify parameters for the files within the project, such as<br>externally generated keys or MIME types, if the automatic detection failed.</html>
+jsite.project-files.action.rescan=Re-scan
+jsite.project-files.action.rescan.tooltip=Re-scan the project directory for new files
+jsite.project-files.ignore-hidden-files=Ignore hidden files
+jsite.project-files.ignore-hidden-files.tooltip=When selected, hidden files are not inserted
+jsite.project-files.file-options=File Options
+jsite.project-files.default=Default file
+jsite.project-files.default.tooltip=Specify that this file is the project\u2019s index file
+jsite.project-files.insert=Insert
+jsite.project-files.insert.tooltip=Uncheck if you do not want to insert this file
+jsite.project-files.force-insert=Force insert
+jsite.project-files.force-insert.tooltip=Forces the insert of this file even it is not modified
+jsite.project-files.insert-redirect=Redirect
+jsite.project-files.insert-redirect.tooltip=Check if you want to insert a redirect for this file
+jsite.project-files.custom-key=Custom key
+jsite.project-files.custom-key.tooltip=The externally created key for the file
+jsite.project-files.rename=Rename
+jsite.project-files.rename.tooltip=Renames the file in the uploaded site
+jsite.project-files.mime-type=MIME type
+jsite.project-files.mime-type.tooltip=Select the correct MIME type here if the detection failed
+jsite.project-files.container=Container
+jsite.project-files.container.tooltip=Selects a container for the current file
+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.insert-now=Insert now
+jsite.project-files.invalid-default-file=Only files in the root directory may be selected as default files.
+
+jsite.update-checker.found-version.title=Found New Version
+jsite.update-checker.found-version.message=<html>A new version was found.<br><br>Version {0} (released {1,date})</html>
+jsite.update-checker.latest-version.title=Update Check
+jsite.update-checker.latest-version.newer.message=<html>You are running version {0} but a newer<br>version ({1}) has been found!</html>
+jsite.update-checker.latest-version.older.message=<html>You are running version {0} but the<br>latest version seems to be {1}.</html>
+jsite.update-checker.latest-version.okay.message=<html>You are currently running version {0}<br>which is the latest version.</html>
+
+jsite.key-dialog.title=Manage Project Keys
+jsite.key-dialog.button.ok.tooltip=Accepts the changes
+jsite.key-dialog.button.cancel.tooltip=Discards the changes
+jsite.key-dialog.button.generate=Regenerate Keys
+jsite.key-dialog.button.generate.tooltip=Create a new key pair
+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.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.warning.site-larger-than-2-mib=<html><b>Site is larger than 2 MiB!</b><br><br>Your site contains more than 2 megabytes of data.<br>Due to bugs in Freenet it will probably not load correctly.<br>Try to reduce the size of your site, or continue at your own peril.</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>
+jsite.error.duplicate-file=<html><b>Duplicate file</b><br><br>The file <code>{0}</code> is inserted twice!<br>Please check your filenames and redirects.</html>
--- /dev/null
+#
+# jSite - jSite_de.properties - Copyright © 2006–2012 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
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# German language file by David Roden <droden@gmail.com>
+
+# Attention, translators! Most of the strings here are used directly.
+# However, some of them are parsed by MessageFormat
+# (http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html)
+# and thus have to adhere to some rules (check the URL above). This is the
+# case when a line contains placeholders like {0} or {0,number}! In these
+# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
+# otherwise the placeholder will not be replaced!
+
+jsite.general.ok=OK
+jsite.general.cancel=Abbrechen
+
+jsite.wizard.previous=Zur\u00fcck
+jsite.wizard.next=Vorw\u00e4rts
+jsite.wizard.quit=Beenden
+
+jsite.quit.question=M\u00f6chten Sie jSite wirklich beenden?
+jsite.quit.question.title=Wirklich beenden?
+jsite.quit.overwrite-configuration=<html><b>Konfiguration \u00fcberschreiben?</b><br><br>Es existiert bereits eine Konfigurationsdatei unter:<br><code>{0}</code><br><br>Soll sie \u00fcberschrieben werden?</html>
+jsite.quit.overwrite-configuration.title=Konfiguration \u00fcberschreiben?
+jsite.quit.config-not-saved=<html><b>Konfiguration nicht gespeichert</b><br><br>Die Konfiguration konnte nicht gespeichert werden.<br>Soll jSite trotzdem beendet werden?</html>
+
+jsite.menu.languages=Sprachen
+jsite.menu.language.en=English
+jsite.menu.language.de=Deutsch
+jsite.menu.language.fr=Fran\u00e7ais
+jsite.menu.language.it=Italiano
+jsite.menu.language.pl=Polski
+jsite.menu.nodes=Nodes
+jsite.menu.nodes.manage-nodes=Nodes verwalten
+jsite.menu.options=Optionen
+jsite.menu.options.preferences=Einstellungen
+jsite.menu.help=Hilfe
+jsite.menu.help.check-for-updates=Auf Updates pr\u00fcfen
+jsite.menu.help.about=\u00dcber
+
+jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006\u20132012 David Roden<br>Ver\u00f6ffentlicht unter der GNU General Public License</html>
+
+jsite.node-manager.heading=Nodeverwaltung
+jsite.node-manager.description=Verwalten Sie hier Ihre Nodes.
+jsite.node-manager.node-information=Nodeinformation
+jsite.node-manager.add-node=Node hinzuf\u00fcgen
+jsite.node-manager.new-node=Neuer Node
+jsite.node-manager.delete-node=Node l\u00f6schen
+jsite.node-manager.delete-node.warning=<html><b>Nodel\u00f6schung best\u00e4tigen</b><br><br>Wollen Sie diesen Node wirklich l\u00f6schen?</html>
+jsite.node-manager.name=Name
+jsite.node-manager.hostname=Hostname
+jsite.node-manager.port=Port
+
+jsite.preferences.heading=Einstellungen
+jsite.preferences.description=Auf dieser Seite k\u00f6nnen einige globale Einstellungen vorgenommen werden.
+jsite.preferences.temp-directory=Verzeichnis f\u00fcr tempor\u00e4re Dateien
+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.preferences.insert-options=Einf\u00fcgeoptionen
+jsite.preferences.insert-options.use-early-encode=Endg\u00fcltige URI fr\u00fcher berechnen
+jsite.preferences.insert-options.priority=Priorit\u00e4t
+jsite.preferences.insert-options.manifest-putter=Manifesterstellung
+
+jsite.insert.heading=Projekt einf\u00fcgen
+jsite.insert.description=Bitte warten Sie, w\u00e4hrend das Projekt eingef\u00fcgt wird.
+jsite.insert.project-information=Projektinformationen
+jsite.insert.request-uri=Freesite
+jsite.insert.start-time=Beginn
+jsite.insert.starting=Beginne\u2026
+jsite.insert.done=Fertig.
+jsite.insert.done.title=Einf\u00fcgen abgeschlossen
+jsite.insert.insert-aborted=Das Einf\u00fcgen wurde abgebrochen.
+jsite.insert.insert-aborted.title=Einf\u00fcgen abgebrochen
+jsite.insert.progress=Fortschritt
+jsite.insert.k-per-s=KB/s
+jsite.insert.insert-failed=<html><b>Einf\u00fcgen fehlgeschlagen</b><br><br>Das Einf\u00fcgen des Projektes ist fehlgeschlagen, da<br>einige Dateien nicht eingef\u00fcgt werden konnten.</html>
+jsite.insert.insert-failed-with-cause=<html><b>Einf\u00fcgen fehlgeschlagen</b><br><br>Das Einf\u00fcgen des Projektes ist fehlgeschlagen, da<br>einige Dateien nicht eingef\u00fcgt werden konnten.<br>Folgender Fehler trat auf:<br><br><code>{0}</code></html>
+jsite.insert.insert-failed.title=Einf\u00fcgen fehlgeschlagen
+jsite.insert.inserted=<html><b>Projekt eingef\u00fcgt</b><br><br>Ihr Projekt wurde erfolgreich eingef\u00fcgt.</html>
+jsite.insert.okay-copy-uri=URI kopieren
+jsite.insert.reinserted-edition=<html><b>Edition bereits eingef\u00fcgt</b><br><br>Die Edition, die gerade eingef\u00fcgt wird,<br>ist schon einmal eingef\u00fcgt worden.</html>
+jsite.insert.reinserted-edition.title=Edition bereits eingef\u00fcgt
+
+jsite.file-scanner.can-not-read-directory=Kann Verzeichnis nicht lesen
+
+jsite.project.heading=Projekt ausw\u00e4hlen
+jsite.project.description=W\u00e4hlen Sie das Projekt aus, welches sie einf\u00fcgen m\u00f6chten, oder erstellen Sie ein neues Projekt.
+jsite.project.action.browse=Durchsuchen
+jsite.project.action.browse.choose=Ausw\u00e4hlen
+jsite.project.action.browse.tooltip=Lokalen Pfad f\u00fcr Projekt ausw\u00e4hlen
+jsite.project.action.add-project=Projekt erstellen
+jsite.project.action.add-project.tooltip=Ein neues Projekt erstellen
+jsite.project.new-project.name=Neues Projekt
+jsite.project.action.delete-project=Projekt l\u00f6schen
+jsite.project.action.delete-project.tooltip=Ein Projekt l\u00f6schen
+jsite.project.action.delete-project.confirm=<html><b>L\u00f6schung best\u00e4tigen</b><br><br>Das Projekt \u201e{0}\u201c wird gel\u00f6scht!<br>M\u00f6chten Sie fortfahren?</html>
+jsite.project.action.clone-project=Projekt duplizieren
+jsite.project.action.clone-project.copy=Kopie von {0}
+jsite.project.action.clone-project.tooltip=Das ausgew\u00e4hlte Projekt duplizieren
+jsite.project.action.copy-uri=URI kopieren
+jsite.project.action.copy-uri.tooltip=Kopiert die URI des ausgew\u00e4hlten Projektes in die Zwischenablage
+jsite.project.action.manage-keys=Schl\u00fcsselverwaltung
+jsite.project.action.manage-keys.tooltip=Verwaltet die Schl\u00fcssel des Projekts
+jsite.project.action.reset-edition=Edition zur\u00fccksetzen
+jsite.project.action.reset-edition.tooltip=Setzt die Editionsnummer des Projekts zur\u00fcck
+jsite.project.project.information=Projektinformation
+jsite.project.project.name=Name
+jsite.project.project.description=Beschreibung
+jsite.project.project.local-path=Lokaler Pfad
+jsite.project.project.address=Adresse
+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.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! Au\u00dferdem wird die Edition zur\u00fcckgesetzt.</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>
+
+jsite.project-files.heading=Projektdateien
+jsite.project-files.description=<html>Auf dieser Seite k\u00f6nnen Parameter f\u00fcr die einzelnen Dateien dieses Projekts angegeben werden, z.B.<br>extern erstellte Schl\u00fcssel oder der korrekte MIME-Typ, wenn er nicht automatisch richtig erkannt wurde.</html>
+jsite.project-files.action.rescan=Erneut einlesen
+jsite.project-files.action.rescan.tooltip=Die Liste mit Dateien dieses Projekts neu einlesen
+jsite.project-files.ignore-hidden-files=Versteckte Dateien ignorieren
+jsite.project-files.ignore-hidden-files.tooltip=Verhindert, dass versteckte Dateien hochgeladen werden
+jsite.project-files.file-options=Dateioptionen
+jsite.project-files.default=Index-Datei
+jsite.project-files.default.tooltip=Lege Index-Datei f\u00fcr Projekt fest
+jsite.project-files.insert=Einf\u00fcgen
+jsite.project-files.insert.tooltip=jSite f\u00fcgt diese Datei ein
+jsite.project-files.force-insert=Einf\u00fcgen erzwingen
+jsite.project-files.force-insert.tooltip=F\u00fcgt diese Datei ein, auch wenn sie nicht modifiziert wurde
+jsite.project-files.insert-redirect=Umleitung
+jsite.project-files.insert-redirect.tooltip=F\u00fcgt eine Umleitung ein
+jsite.project-files.custom-key=Extern erstellter Schl\u00fcssel
+jsite.project-files.custom-key.tooltip=Der extern erstellte Schl\u00fcssel f\u00fcr diese Datei
+jsite.project-files.rename=Umbenennen
+jsite.project-files.rename.tooltip=Benennt die Datei in der eingef\u00fcgten Seite um
+jsite.project-files.mime-type=MIME-Typ
+jsite.project-files.mime-type.tooltip=Den richtigen MIME-Typ hier ausw\u00e4hlen, wenn die automatische Erkennenung falsch ist
+jsite.project-files.container=Container
+jsite.project-files.container.tooltip=W\u00e4hlt einen Container f\u00fcr diese Datei aus
+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.insert-now=Jetzt einf\u00fcgen
+jsite.project-files.invalid-default-file=Nur Dateien im obersten Verzeichnis d\u00fcrfen als Index-Dateien ausgew\u00e4hlt werden.
+
+jsite.update-checker.found-version.title=Neue Version gefunden
+jsite.update-checker.found-version.message=<html>Eine neue Version wurde gefunden.<br><br>Version {0} (ver\u00f6ffentlicht {1,date})</html>
+jsite.update-checker.latest-version.title=Update\u00fcberpr\u00fcfung
+jsite.update-checker.latest-version.newer.message=<html>Es l\u00e4uft momentan Version {0}, aber eine<br>neue Version ({1}) wurde bereits gefunden!</html>
+jsite.update-checker.latest-version.older.message=<html>Es l\u00e4uft momentan Version {0}, aber die<br>aktuelle Version ist erst {1}.</html>
+jsite.update-checker.latest-version.okay.message=<html>Es l\u00e4uft momentan Version {0},<br>und diese Version ist aktuell.</html>
+
+jsite.key-dialog.title=Projektschl\u00fcsselverwaltung
+jsite.key-dialog.button.ok.tooltip=\u00c4nderungen akzeptieren
+jsite.key-dialog.button.cancel.tooltip=\u00c4nderungen verwerfen
+jsite.key-dialog.button.generate=Schl\u00fcssel neu generieren
+jsite.key-dialog.button.generate.tooltip=Generiert ein neues Schl\u00fcsselpaar
+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.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.warning.site-larger-than-2-mib=<html><b>Ihr Projekt ist gr\u00f6\u00dfer als 2 Megabyte!</b><br><br>Ihr Projekt enth\u00e4lt mehr als 2 Megabyte an Daten. Aufgrund<br>eines Fehlers in Freenet wird die Seite wahrscheinlich nicht<br>korrekt angezeigt werden. Bitte reduzieren Sie die Gr\u00f6\u00dfe<br>Ihres Projektes, oder fahren Sie auf eigene Gefahr fort.</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>
+jsite.error.duplicate-file=<html><b>Doppelte Datei</b><br><br>Die Datei <code>{0}</code> wird zweimal eingef\u00fcgt!<br>Bitte \u00fcberpr\u00fcfen Sie Ihre Umleitungen und Dateinamen!</html>
--- /dev/null
+#
+# jSite - jSite_fr.properties - Copyright © 2006–2012 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
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# French language file by Florent Daigni\u00e8re <nextgens@freenetproject.org>, Julien Cornuwel <batosai@batosai.net>, and Clement Vollet <cvollet@gmail.com>.
+
+# Attention, translators! Most of the strings here are used directly.
+# However, some of them are parsed by MessageFormat
+# (http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html)
+# and thus have to adhere to some rules (check the URL above). This is the
+# case when a line contains placeholders like {0} or {0,number}! In these
+# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
+# otherwise the placeholder will not be replaced!
+
+jsite.general.ok=OK
+jsite.general.cancel=Annuler
+
+jsite.wizard.previous=Pr\u00e9c\u00e9dent
+jsite.wizard.next=Suivant
+jsite.wizard.quit=Quitter
+
+jsite.quit.question=Voulez-vous r\u00e9ellement quitter?
+jsite.quit.question.title=Souhaitez vous quitter?
+jsite.quit.overwrite-configuration=<html><b>Ecraser la configuration?</b><br><br>Un fichier de configuration \u00e9xiste d\u00e9j\u00e0:<br><code>{0}</code><br><br>Doit-il \u00eatre \u00e9cras\u00e9 ?</html>
+jsite.quit.overwrite-configuration.title=Ecraser la configuration?
+jsite.quit.config-not-saved=<html><b>Configuration non sauvegard\u00e9e</b><br><br>La configuration n'a pas pu \u00eatre sauv\u00e9e.<br>Voulez vous quitter tout de m\u00eame?</html>
+
+jsite.menu.languages=Langue
+jsite.menu.language.en=English
+jsite.menu.language.de=Deutsch
+jsite.menu.language.fr=Fran\u00e7ais
+jsite.menu.language.it=Italiano
+jsite.menu.language.pl=Polski
+jsite.menu.nodes=Noeud
+jsite.menu.nodes.manage-nodes=G\u00e9rer les noeuds
+jsite.menu.options=Options
+jsite.menu.options.preferences=Pr\u00e9f\u00e9rences
+jsite.menu.help=Aide
+jsite.menu.help.check-for-updates=Mises \u00e0 jour
+jsite.menu.help.about=A propos de jSite
+
+jsite.about.message=<html><big><b>jSite {0}</b></big><br><br>Copyright \u00a9 2006\u20132012 David Roden<br>Publi\u00e9 sous GNU General Public License</html>
+
+jsite.node-manager.heading=Gestionnaire de noeud
+jsite.node-manager.description=G\u00e9rez vos noeuds.
+jsite.node-manager.node-information=Information sur le noeud
+jsite.node-manager.add-node=Ajouter un noeud
+jsite.node-manager.new-node=Nouveau noeud
+jsite.node-manager.delete-node=Supprimer un noeud
+jsite.node-manager.delete-node.warning=<html><b>Confirmer la suppression</b><br><br>Supprimer r\u00e9ellement ce noeud?</html>
+jsite.node-manager.name=Nom
+jsite.node-manager.hostname=Nom de machine
+jsite.node-manager.port=Port
+
+jsite.preferences.heading=Pr\u00e9f\u00e9rences
+jsite.preferences.description=Utilisez cette page pour g\u00e9rer quelques param\u00e8tres globaux.
+jsite.preferences.temp-directory=R\u00e9pertoire des fichiers temporaires
+jsite.preferences.temp-directory.default=D\u00e9faut (choix syst\u00e8mes)
+jsite.preferences.temp-directory.custom=Personnalis\u00e9
+jsite.preferences.temp-directory.choose=Choisir
+jsite.preferences.temp-directory.choose.approve=Choisir
+jsite.preferences.config-directory=Chemin du fichier de configuration
+jsite.preferences.config-directory.jar=Suivant, le fichier JAR
+jsite.preferences.config-directory.home=Acceuil
+jsite.preferences.config-directory.custom=R\u00e9pertoire personnel
+jsite.preferences.insert-options=Options d'insertion
+jsite.preferences.insert-options.use-early-encode=G\u00e9n\u00e9rer d'abord l'URI
+jsite.preferences.insert-options.priority=Priorit\u00e9
+jsite.preferences.insert-options.manifest-putter=Ajout de Manifest
+
+jsite.insert.heading=Projet d'insertion
+jsite.insert.description=Veuillez attendre durant l'insertion du projet.
+jsite.insert.project-information=Information \u00e0 propos du projet.
+jsite.insert.request-uri=Freesite
+jsite.insert.start-time=Commenc\u00e9 \u00e0
+jsite.insert.starting=D\u00e9marrage\u2026
+jsite.insert.done=Termin\u00e9.
+jsite.insert.done.title=Insertion effectu\u00e9e
+jsite.insert.insert-aborted=L'insertion a \u00e9t\u00e9 annul\u00e9e.
+jsite.insert.insert-aborted.title=Insertion Annul\u00e9e
+jsite.insert.progress=Avancement
+jsite.insert.k-per-s=Ko/s
+jsite.insert.insert-failed=<html><b>Insertion \u00e9chou\u00e9e</b><br><br>L'insertion du projet \u00e0 \u00e9chou\u00e9e.<br>Certain fichiers n'ont pas \u00e9t\u00e9 ins\u00e9r\u00e9s.</html>
+jsite.insert.insert-failed-with-cause=<html><b>Insertion \u00e9chou\u00e9e</b><br><br>L'insertion du projet \u00e0 \u00e9chou\u00e9e.<br>Certain fichiers n'ont pas \u00e9t\u00e9 ins\u00e9r\u00e9s.<br>L'erreur suivante s'est produite:<br><br><code>{0}</code></html>
+jsite.insert.insert-failed.title=Insertion Echou\u00e9e
+jsite.insert.inserted=<html><b>Projet ins\u00e9r\u00e9!</b><br><br>Votre projet \u00e0 \u00e9t\u00e9 correctement ins\u00e9r\u00e9.</html>
+jsite.insert.okay-copy-uri=Copier l'URI vers le presse-papiers
+jsite.insert.reinserted-edition=<html><b>Edition r\u00e9ins\u00e9r\u00e9e</b><br><br>L'\u00e9dition que vous \u00eates en train d'ins\u00e9rer<br>a d\u00e9j\u00e0 \u00e9t\u00e9 ins\u00e9r\u00e9e avant.</html>
+jsite.insert.reinserted-edition.title=Edition r\u00e9ins\u00e9r\u00e9e
+
+jsite.file-scanner.can-not-read-directory=Impossible de lire le r\u00e9pertoire
+
+jsite.project.heading=S\u00e9lectionnez un projet
+jsite.project.description=S\u00e9lectionnez un projet de la liste ou cr\u00e9ez en un nouveau.
+jsite.project.action.browse=Naviguer
+jsite.project.action.browse.choose=Choisir
+jsite.project.action.browse.tooltip=Choisir un r\u00e9pertoire
+jsite.project.action.add-project=Ajouter un projet
+jsite.project.action.add-project.tooltip=Ajouter un projet
+jsite.project.new-project.name=Nouveau projet
+jsite.project.action.delete-project=D\u00e9truire le projet
+jsite.project.action.delete-project.tooltip=D\u00e9truire le projet
+jsite.project.action.delete-project.confirm=<html><b>Confirmez la suppression</b><br><br>Le projet \u201c{0}\u201d va \u00eatre d\u00e9truit!<br>Voulez vous poursuivre?</html>
+jsite.project.action.clone-project=Cloner le projet
+jsite.project.action.clone-project.copy=Copie de {0}
+jsite.project.action.clone-project.tooltip=Cloner le projet s\u00e9lectionn\u00e9
+jsite.project.action.copy-uri=Copier l'URI dans le presse-papier
+jsite.project.action.copy-uri.tooltip=Copie l'URI du projet dans le presse-papier
+jsite.project.action.generate-new-key=G\u00e9n\u00e9rer une nouvelle cl\u00e9
+jsite.project.action.generate-new-key.tooltip=Cr\u00e9e une nouvelle cl\u00e9 pour ce projet
+jsite.project.action.reset-edition=Remettre \u00e0 z\u00e9ro l'\u00e9dition
+jsite.project.action.reset-edition.tooltip=Remettre \u00e0 z\u00e9ro l'\u00e9dition du projet
+jsite.project.project.information=Informations concernant le projet
+jsite.project.project.name=Nom
+jsite.project.project.description=Description
+jsite.project.project.local-path=Chemin local
+jsite.project.project.address=Adresse
+jsite.project.project.path=Chemin du freesite
+jsite.project.project.edition=Edition
+jsite.project.project.uri=URI
+jsite.project.keygen.io-error=<html><b>Erreur de communication avec le noeud</b><br><br>La communication avec le noeud \u00e0 \u00e9chou\u00e9e<br>Erreur:<br><br><code>{0}</code><br><br>Assurez vous que les informations saisies dans la page de configuration sont correctes.</html>
+jsite.project.warning.generate-new-key=<html><b>G\u00e9n\u00e9rer une nouvelle cl\u00e9 ?</b><br><br>Si vous g\u00e9n\u00e9rez une nouvelle cl\u00e9, votre site sera publi\u00e9<br>avec cette nouvelle cl\u00e9. La confiance que les autres<br>utilisateurs pla\u00e7aient dans l'ancienne cl\u00e9 sera perdue !</html>
+jsite.project.warning.reset-edition=<html><b>Remettre \u00e0 z\u00e9ro l'\u00e9dition ?</b><br><br>Remettre \u00e0 z\u00e9ro l'\u00e9dition peut faire \u00e9chouer l'insertion<br> ou poser des probl\u00e8mes si vous n'avez pas chang\u00e9<br>le chemin ou les cl\u00e9s du projet !</html>
+jsite.project.warning.use-clipboard-now=<html><b>URI copi\u00e9e</b><br><br>Veuillez noter qu'il est possible qu'en quittant jSite<br>maintenant le presse-papiers soit vid\u00e9. Merci d'utiliser<br>l'URI copi\u00e9e imm\u00e9diatement dans une autre fen\u00eatre !</html>
+
+jsite.project-files.heading=Fichiers du projet
+jsite.project-files.description=<html>Dans cette page vous pouvez sp\u00e9cifier les informations concernant la configuration des noeuds telles que:<br>Le type de contenu mime si l'auto d\u00e9tection \u00e0 \u00e9chou\u00e9e.</html>
+jsite.project-files.action.rescan=Re-scan
+jsite.project-files.action.rescan.tooltip=V\u00e9rifier la pr\u00e9sence de nouveau fichiers
+jsite.project-files.ignore-hidden-files=Ignorer les fichiers cach\u00e9s
+jsite.project-files.ignore-hidden-files.tooltip=Si s\u00e9lectionn\u00e9, les fichiers cach\u00e9s ne sont pas ins\u00e9r\u00e9s
+jsite.project-files.file-options=Option des fichiers
+jsite.project-files.default=Fichier par d\u00e9faut
+jsite.project-files.default.tooltip=Est-ce l'index?
+jsite.project-files.insert=Ins\u00e9rer
+jsite.project-files.insert.tooltip=D\u00e9cochez si vous ne voulez pas ins\u00e9rer ce fichier
+jsite.project-files.force-insert=Forcer l'insertion
+jsite.project-files.force-insert.tooltip=Forcer l'insertion de ce fichier tant qu'il n'est pas modifi\u00e9
+jsite.project-files.insert-redirect=Redirection
+jsite.project-files.insert-redirect.tooltip=Cochez si vous voulez ins\u00e9rer une redirection pour ce fichier
+jsite.project-files.custom-key=Clef existante
+jsite.project-files.custom-key.tooltip=Utiliser une clef existante pour ce fichier
+jsite.project-files.rename=Renommer
+jsite.project-files.rename.tooltip=Renomme le fichier dans le site ins\u00e9r\u00e9
+jsite.project-files.mime-type=MIME type
+jsite.project-files.mime-type.tooltip=S\u00e9lectionez le type MIME du fichier si la d\u00e9tection \u00e0 \u00e9chou\u00e9e
+jsite.project-files.container=Container
+jsite.project-files.container.tooltip=S\u00e9lectionnez un container pour le fichier
+jsite.project-files.scan-error=<html><b>Erreur lors du parcours des fichiers</b><br><br>Soit le r\u00e9pertoire du projet n'existe pas,<br>ou des fichiers/r\u00e9pertoires sont inaccessibles.<br>Veuillez revenir en arri\u00e8re et s\u00e9lectionner un autre r\u00e9pertoire.</html>
+jsite.project-files.insert-now=Ins\u00e9rer
+jsite.project-files.invalid-default-file=Seulement les fichiers de la racine peuvent \u00eatre selectionn\u00e9s comme fichiers par defaut
+
+jsite.update-checker.found-version.title=Nouvelle version disponible
+jsite.update-checker.found-version.message=<html>Une nouvelle version est disponible.<br><br>Version {0} (publi\u00e9e le {1,date})</html>
+jsite.update-checker.latest-version.title=Recherche de mises \u00e0 jour
+jsite.update-checker.latest-version.newer.message=<html>Vous utilisez la version {0} mais une version<br>plus r\u00e9cente ({1}) est disponible!</html>
+jsite.update-checker.latest-version.older.message=<html>Vous utilisez la version {0} mais la<br>derni\u00e8re version semble \u00eatre la {1}.</html>
+jsite.update-checker.latest-version.okay.message=<html>Vous utilisez la version {0}<br>qui semble \u00eatre la derni\u00e8re.</html>
+
+jsite.key-dialog.title=G\u00e9rer les cl\u00e9s des projets
+jsite.key-dialog.button.ok.tooltip=Accepter les changements
+jsite.key-dialog.button.cancel.tooltip=Annuler les changements
+jsite.key-dialog.button.generate=Reg\u00e9n\u00e9rer les cl\u00e9s
+jsite.key-dialog.button.generate.tooltip=Cr\u00e9er une nouvelle paire de cl\u00e9s
+jsite.key-dialog.label.keys=<html><b>Cl\u00e9s</b></html>
+jsite.key-dialog.label.private-key=Cl\u00e9 priv\u00e9e
+jsite.key-dialog.label.public-key=Cl\u00e9 publique
+jsite.key-dialog.label.actions=<html><b>Actions</b></html>
+
+jsite.warning.empty-index=<html><b>Pas de fichier par d\u00e9faut</b><br><br>Avez vous sp\u00e9cifi\u00e9 un fichier par d\u00e9faut pour le projet?<br>M\u00eame s'il est possible de ne pas en sp\u00e9cifier, c'est g\u00e9n\u00e9ralement une mauvaise id\u00e9e.</html>
+jsite.warning.index-not-html=<html><b>Le fichier principal n'est pas un fichier HTML!</b><br><br>Votre fichier par d\u00e9faut n'est pas du type MIME "text/html"!<br>Chargez ce type de fichiers dans un navigateur peut \u00eatre dangereux.</html>
+
+jsite.error.no-node-selected=<html><b>Pas de noeud s\u00e9lectionn\u00e9</b><br><br>S\u00e9lectionnez un noeud dans le menu!</html>
+jsite.error.no-node-running=<html><b>Ce noeud n'est pas actif!</b><br><br>Vous ne pouvez pas utiliser jSite sans noeud actif.<br>Veuillez d\u00e9marrer votre noeud et r\u00e9essayer.</html>
+jsite.error.no-local-path=<html><b>Pas de chemin local sp\u00e9cifi\u00e9</b><br><br>Vous avez omis de sp\u00e9cifier le chemin local \u00e0 ins\u00e9rer.</html>
+jsite.error.no-path=<html><b>Vous n'avez pas sp\u00e9cifi\u00e9 de chemin dans le freesite</b><br><br>Vous n'avez pas sp\u00e9cifi\u00e9 de chemin dans le freesite.<br>Ce champ est n\u00e9cessaire.</html>
+jsite.error.index-missing=<html>Votre fichier par d\u00e9faut est manquant</b><br><br>Un fichier par d\u00e9faut est sp\u00e9cifi\u00e9 mais il<br>n'existe plus ! S\u00e9lectionnez un nouveau<br>fichier par d\u00e9faut dans la liste.</html>
+jsite.error.index-not-inserted=<html><b>Fichier par d\u00e9faut non ins\u00e9r\u00e9</b><br><br>Vous avez choisi de ne pas ins\u00e9rer le fichier par d\u00e9faut !<br>Vous devez soit l'ins\u00e9rer soit choisir<br>un fichier par d\u00e9faut diff\u00e9rent !</html>
+jsite.error.no-custom-key=<html><b>Pas de clef existante sp\u00e9cifi\u00e9e pour ce fichier</b><br><br>Vous avez sp\u00e9cifier de ne pas ins\u00e9rer <code>{0}</code><br> mais n'avez pas sp\u00e9cifier de clef ou rediriger!</html>
+jsite.error.no-files-to-insert=<html><b>Aucun fichier \u00e0 ins\u00e9rer</b><br><br>Vous n'avez s\u00e9lectionn\u00e9 aucun fichier pour l'insertion !<br>Veuillez s\u00e9lectionner au moins un fichier \u00e0 ins\u00e9rer.</html>
+jsite.error.duplicate-file=<html><b>Fichier dupliqu\u00e9</b><br><br>Le fichier <code>{0}</code> est ins\u00e9r\u00e9 deux fois !<br>Veuillez v\u00e9rifier les noms de fichier et les redirections.</html>