</target>
<target name="compile-maintainer" depends="prepare" if="maintainer-build">
- <javac destdir="${bin.dir}" debug="false" optimize="true">
+ <javac destdir="${bin.dir}" debug="${javac.debug}" optimize="true">
<src path="${src.dir}" />
<sourcepath path="${todesbaum.src}" />
</javac>
</target>
<target name="compile-non-maintainer" depends="prepare" unless="maintainer-build">
- <javac destdir="${bin.dir}" debug="false" optimize="true">
+ <javac destdir="${bin.dir}" debug="${javac.debug}" optimize="true">
<src path="${src.dir}" />
<sourcepath path="${todesbaum.src}" />
</javac>
/*
- * jSite - AbortedException.java - Copyright © 2010 David Roden
+ * 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
/*
- * jSite - a tool for uploading websites into Freenet Copyright (C) 2006 David
- * Roden
+ * 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
/** The default changed name. */
private static final String DEFAULT_CHANGED_NAME = null;
- /** The default container. */
- private static final String DEFAULT_CONTAINER = "";
-
- /** The default edition range. */
- private static final int DEFAULT_EDITION_RANGE = 3;
-
- /** The default for the replace edition state. */
- private static final boolean DEFAULT_REPLACE_EDITION = false;
-
/** 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 current MIME type. */
private String mimeType;
- /** The container. */
- private String container;
-
- /** The edition range. */
- private int editionRange;
-
- /** The replace edition state. */
- private boolean replaceEdition;
-
/**
* Creates new file options.
*
changedName = DEFAULT_CHANGED_NAME;
this.defaultMimeType = defaultMimeType;
mimeType = defaultMimeType;
- container = DEFAULT_CONTAINER;
- editionRange = DEFAULT_EDITION_RANGE;
- replaceEdition = DEFAULT_REPLACE_EDITION;
}
/**
}
/**
+ * 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
}
/**
+ * 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}.
*
}
/**
- * Returns the name of the container this file should be put in.
- *
- * @return The name of the container
- */
- public String getContainer() {
- return container;
- }
-
- /**
- * Sets the name of the container this file should be put in.
- *
- * @param container
- * The name of the container
- */
- public void setContainer(String container) {
- if (container == null) {
- this.container = DEFAULT_CONTAINER;
- } else {
- this.container = container;
- }
- }
-
- /**
- * Sets whether the file should have “$[EDITION+<i>n</i>]” tags replaced.
- *
- * @param replaceEdition
- * <code>true</code> to replace tags, <code>false</code> not to
- * replace
- */
- public void setReplaceEdition(boolean replaceEdition) {
- this.replaceEdition = replaceEdition;
- }
-
- /**
- * Returns whether the file should have “$[EDITION+<i>n</i>]” tags replaced.
- *
- * @return <code>true</code> if tags should be replaced, <code>false</code>
- * otherwise
- */
- public boolean getReplaceEdition() {
- return replaceEdition;
- }
-
- /**
- * Sets the range of editions that should be replaced.
- *
- * @param editionRange
- * The range editions to replace
- */
- public void setEditionRange(int editionRange) {
- this.editionRange = editionRange;
- }
-
- /**
- * Returns the range of editions that should be replaced.
- *
- * @return The range of editions to replace
- */
- public int getEditionRange() {
- return editionRange;
- }
-
- /**
* Returns whether the options for this file have been modified, i.e. are
* not at their default values.
*
if (!defaultMimeType.equals(mimeType)) {
return true;
}
- if (!DEFAULT_CONTAINER.equals(container)) {
- return true;
- }
- if (replaceEdition != DEFAULT_REPLACE_EDITION) {
- return true;
- }
- if (editionRange != DEFAULT_EDITION_RANGE) {
- return true;
- }
if (insertRedirect != DEFAULT_INSERT_REDIRECT) {
return true;
}
/*
- * jSite -
- * Copyright (C) 2006 David Roden
+ * 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
*/
public String[] generateKeyPair() throws IOException {
if (!isNodePresent()) {
- return null;
+ throw new IOException("Node is offline.");
}
GenerateSSK generateSSK = new GenerateSSK();
Client client = new Client(connection, generateSSK);
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * jSite - KeyDialog.java - Copyright © 2010 David Roden
+ * 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
/*
- * jSite-0.7 -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * jSite - a tool for uploading websites into Freenet Copyright (C) 2006 David
- * Roden
+ * 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
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import de.todesbaum.util.mime.DefaultMIMETypes;
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);
+ }
+ }
+
}
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
package de.todesbaum.jsite.application;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
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.Closer;
-import de.todesbaum.util.io.ReplacingOutputStream;
-import de.todesbaum.util.io.StreamCopier;
+import de.todesbaum.util.io.StreamCopier.ProgressListener;
/**
* Manages project inserts.
/** 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.
*
}
/**
+ * 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() {
+ public void start(ProgressListener progressListener) {
cancelled = false;
+ this.progressListener = progressListener;
fileScanner = new FileScanner(project);
fileScanner.addFileScannerListener(this);
new Thread(fileScanner).start();
private InputStream createFileInputStream(String filename, FileOption fileOption, int edition, long[] length) throws IOException {
File file = new File(project.getLocalPath(), filename);
length[0] = file.length();
- if (!fileOption.getReplaceEdition()) {
- return new FileInputStream(file);
- }
- ByteArrayOutputStream filteredByteOutputStream = new ByteArrayOutputStream(Math.min(Integer.MAX_VALUE, (int) length[0]));
- ReplacingOutputStream outputStream = new ReplacingOutputStream(filteredByteOutputStream);
- FileInputStream fileInput = new FileInputStream(file);
- try {
- outputStream.addReplacement("$[EDITION]", String.valueOf(edition));
- outputStream.addReplacement("$[URI]", project.getFinalRequestURI(0));
- for (int index = 1; index <= fileOption.getEditionRange(); index++) {
- outputStream.addReplacement("$[URI+" + index + "]", project.getFinalRequestURI(index));
- outputStream.addReplacement("$[EDITION+" + index + "]", String.valueOf(edition + index));
- }
- StreamCopier.copy(fileInput, outputStream, length[0]);
- } finally {
- Closer.close(fileInput);
- Closer.close(outputStream);
- Closer.close(filteredByteOutputStream);
- }
- byte[] filteredBytes = filteredByteOutputStream.toByteArray();
- length[0] = filteredBytes.length;
- return new ByteArrayInputStream(filteredBytes);
- }
-
- /**
- * Creates an input stream for a container.
- *
- * @param containerFiles
- * All container definitions
- * @param containerName
- * The name of the container to create
- * @param edition
- * The current edition
- * @param containerLength
- * An array containing a single long which is used to
- * <em>return</em> the final length of the container stream,
- * after all replacements
- * @return The input stream for the container
- * @throws IOException
- * if an I/O error occurs
- */
- private InputStream createContainerInputStream(Map<String, List<String>> containerFiles, String containerName, int edition, long[] containerLength) throws IOException {
- File tempFile = File.createTempFile("jsite", ".zip", (tempDirectory == null) ? null : new File(tempDirectory));
- tempFile.deleteOnExit();
- FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
- ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
- try {
- for (String filename : containerFiles.get(containerName)) {
- File dataFile = new File(project.getLocalPath(), filename);
- if (dataFile.exists()) {
- ZipEntry zipEntry = new ZipEntry(filename);
- long[] fileLength = new long[1];
- InputStream wrappedInputStream = createFileInputStream(filename, project.getFileOption(filename), edition, fileLength);
- try {
- zipOutputStream.putNextEntry(zipEntry);
- StreamCopier.copy(wrappedInputStream, zipOutputStream, fileLength[0]);
- } finally {
- zipOutputStream.closeEntry();
- wrappedInputStream.close();
- }
- }
- }
- } finally {
- zipOutputStream.closeEntry();
- Closer.close(zipOutputStream);
- Closer.close(fileOutputStream);
- }
-
- containerLength[0] = tempFile.length();
- return new FileInputStream(tempFile);
+ return new FileInputStream(file);
}
/**
* Creates a file entry suitable for handing in to
* {@link ClientPutComplexDir#addFileEntry(FileEntry)}.
*
- * @param filename
- * The name of the file to insert
+ * @param file
+ * The name and hash of the file to insert
* @param edition
* The current edition
- * @param containerFiles
- * The container definitions
* @return A file entry for the given file
*/
- private FileEntry createFileEntry(String filename, int edition, Map<String, List<String>> containerFiles) {
+ private FileEntry createFileEntry(ScannedFile file, int edition) {
FileEntry fileEntry = null;
+ String filename = file.getFilename();
FileOption fileOption = project.getFileOption(filename);
- if (filename.startsWith("/container/:")) {
- String containerName = filename.substring("/container/:".length());
+ 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[] containerLength = new long[1];
- InputStream containerInputStream = createContainerInputStream(containerFiles, containerName, edition, containerLength);
- fileEntry = new DirectFileEntry(containerName + ".zip", "application/zip", containerInputStream, containerLength[0]);
+ 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.isInsert()) {
- try {
- long[] fileLength = new long[1];
- InputStream fileEntryInputStream = createFileInputStream(filename, fileOption, edition, fileLength);
- fileEntry = new DirectFileEntry(filename, project.getFileOption(filename).getMimeType(), fileEntryInputStream, fileLength[0]);
- } catch (IOException ioe1) {
- /* ignore, null is returned. */
- }
- } else {
- if (fileOption.isInsertRedirect()) {
- fileEntry = new RedirectFileEntry(filename, fileOption.getMimeType(), fileOption.getCustomKey());
- }
+ if (fileOption.isInsertRedirect()) {
+ fileEntry = new RedirectFileEntry(fileOption.hasChangedName() ? fileOption.getChangedName() : filename, fileOption.getMimeType(), fileOption.getCustomKey());
}
}
return fileEntry;
}
/**
- * Creates container definitions.
- *
- * @param files
- * The list of all files
- * @param containers
- * The list of all containers
- * @param containerFiles
- * Empty map that will be filled with container definitions
- */
- private void createContainers(List<String> files, List<String> containers, Map<String, List<String>> containerFiles) {
- for (String filename : new ArrayList<String>(files)) {
- FileOption fileOption = project.getFileOption(filename);
- String containerName = fileOption.getContainer();
- if (!containerName.equals("")) {
- if (!containers.contains(containerName)) {
- containers.add(containerName);
- containerFiles.put(containerName, new ArrayList<String>());
- /* hmm. looks like a hack to me. */
- files.add("/container/:" + containerName);
- }
- containerFiles.get(containerName).add(filename);
- files.remove(filename);
- }
- }
- }
-
- /**
* 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.
}
}
String indexFile = project.getIndexFile();
- boolean hasIndexFile = (indexFile != null);
- if (hasIndexFile && !project.getFileOption(indexFile).getContainer().equals("")) {
- checkReport.addIssue("warning.container-index", false);
- }
+ 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 = false;
+ boolean insert = fileOptionEntries.isEmpty();
for (Entry<String, FileOption> fileOptionEntry : fileOptionEntries) {
String fileName = fileOptionEntry.getKey();
FileOption fileOption = fileOptionEntry.getValue();
*/
public void run() {
fireProjectInsertStarted();
- List<String> files = fileScanner.getFiles();
+ List<ScannedFile> files = fileScanner.getFiles();
/* create connection to node */
synchronized (lockObject) {
Client client = new Client(connection);
- /* create containers */
- final List<String> containers = new ArrayList<String>();
- final Map<String, List<String>> containerFiles = new HashMap<String, List<String>>();
- createContainers(files, containers, containerFiles);
-
/* collect files */
int edition = project.getEdition();
String dirURI = "USK@" + project.getInsertURI() + "/" + project.getPath() + "/" + edition + "/";
}
putDir.setVerbosity(Verbosity.ALL);
putDir.setMaxRetries(-1);
- putDir.setEarlyEncode(false);
- for (String filename : files) {
- FileEntry fileEntry = createFileEntry(filename, edition, containerFiles);
+ 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);
/* start request */
try {
- client.execute(putDir);
+ client.execute(putDir, progressListener);
+ fireProjectUploadFinished();
} catch (IOException ioe1) {
fireProjectInsertFinished(false, ioe1);
return;
/* parse progress and success messages */
String finalURI = null;
- boolean firstMessage = true;
boolean success = false;
boolean finished = false;
boolean disconnected = false;
while (!finished && !cancelled) {
Message message = client.readMessage();
finished = (message == null) || (disconnected = client.isDisconnected());
- if (firstMessage) {
- fireProjectUploadFinished();
- firstMessage = false;
- }
logger.log(Level.FINE, "Received message: " + message);
if (!finished) {
@SuppressWarnings("null")
boolean finalized = Boolean.parseBoolean(message.get("FinalizedTotal"));
fireProjectInsertProgress(succeeded, failed, fatal, total, finalized);
}
- success = "PutSuccessful".equals(messageName);
- finished = success || "PutFailed".equals(messageName) || messageName.endsWith("Error");
+ success |= "PutSuccessful".equals(messageName);
+ finished = (success && (finalURI != null)) || "PutFailed".equals(messageName) || messageName.endsWith("Error");
}
}
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));
}
/*
- * jSite-remote - UpdateChecker.java -
- * Copyright © 2008 David Roden
+ * 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
private static int counter = 0;
/** The edition for the update check URL. */
- private static final int UPDATE_EDITION = 11;
+ private static final int UPDATE_EDITION = 17;
/** The URL for update checks. */
private static final String UPDATE_KEY = "USK@e3myoFyp5avg6WYN16ImHri6J7Nj8980Fm~aQe4EX1U,QvbWT0ImE0TwLODTl7EoJx2NBnwDxTbLTE6zkB-eGPs,AQACAAE";
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];
/*
- * jSite-remote - UpdateListener.java -
- * Copyright © 2008 David Roden
+ * 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
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
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
*/
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>();
private final Project project;
/** The list of found files. */
- private List<String> files;
+ private List<ScannedFile> files;
/** Wether there was an error. */
private boolean error = false;
* @see FileScannerListener#fileScannerFinished(FileScanner)
*/
public void run() {
- files = new ArrayList<String>();
+ files = new ArrayList<ScannedFile>();
error = false;
try {
scanFiles(new File(project.getLocalPath()), files);
*
* @return The list of found files
*/
- public List<String> getFiles() {
+ public List<ScannedFile> getFiles() {
return files;
}
* @throws IOException
* if an I/O error occurs
*/
- private void scanFiles(File rootDir, List<String> fileList) throws IOException {
+ private void scanFiles(File rootDir, List<ScannedFile> fileList) throws IOException {
File[] files = rootDir.listFiles(new FileFilter() {
@SuppressWarnings("synthetic-access")
scanFiles(file, fileList);
continue;
}
- String filename = project.shortenFilename(file);
- filename = filename.replace('\\', '/');
- fileList.add(filename);
+ 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);
+ }
+
}
-}
\ No newline at end of file
+}
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * jSite-0.7 -
- * Copyright (C) 2006 David Roden
+ * 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
*/
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);
+
}
/*
- * jSite-0.7 -
- * Copyright (C) 2006 David Roden
+ * 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
}
/**
+ * 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() {
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());
}
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);
}
nodeNameTextField.setEnabled(enabled);
nodeHostnameTextField.setEnabled(enabled);
nodePortSpinner.setEnabled(enabled);
- deleteNodeAction.setEnabled(enabled);
+ deleteNodeAction.setEnabled(enabled && (nodeListModel.size() > 1));
if (enabled) {
nodeNameTextField.setText(node.getName());
nodeHostnameTextField.setText(node.getHostname());
JSpinner sourceSpinner = (JSpinner) source;
if ("node-port".equals(sourceSpinner.getName())) {
selectedNode.setPort((Integer) sourceSpinner.getValue());
+ fireNodeSelected(selectedNode);
nodeList.repaint();
}
}
/*
- * jSite - PreferencesPage.java -
- * Copyright © 2009 David Roden
+ * 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
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 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;
/** 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.
*
}
/**
+ * 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
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() {
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"));
}
});
}
* @return The preferences panel
*/
private JPanel createPreferencesPanel() {
- JPanel preferencesPanel = new JPanel(new BorderLayout(12, 12));
-
- JPanel tempDirectoryPanel = new JPanel(new GridBagLayout());
- preferencesPanel.add(tempDirectoryPanel, BorderLayout.CENTER);
+ 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>");
- tempDirectoryPanel.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));
+ 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);
- tempDirectoryPanel.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));
+ 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);
- tempDirectoryPanel.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));
+ 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);
defaultTempDirectory.setSelected(true);
}
chooseTempDirectoryAction.setEnabled(tempDirectory != null);
- tempDirectoryPanel.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));
+ 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);
- tempDirectoryPanel.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));
+ 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() {
*/
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"));
}
});
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
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.ActionListener;
import java.awt.event.KeyEvent;
import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
-import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
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.SwingUtilities;
-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 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;
*
* @author David ‘Bombe’ Roden <bombe@freenetproject.org>
*/
-public class ProjectFilesPage extends TWizardPage implements ActionListener, ListSelectionListener, DocumentListener, FileScannerListener, ChangeListener {
+public class ProjectFilesPage extends TWizardPage implements ActionListener, ListSelectionListener, DocumentListener, FileScannerListener {
/** The project. */
private Project project;
/** The “scan files” action. */
private Action scanAction;
- /** The “edit container” action. */
- private Action editContainerAction;
-
- /** The “add container” action. */
- private Action addContainerAction;
-
- /** The “delete container” action. */
- protected Action deleteContainerAction;
-
/** The “ignore hidden files” checkbox. */
private JCheckBox ignoreHiddenFilesCheckBox;
/** The “insert” checkbox. */
private JCheckBox fileOptionsInsertCheckBox;
+ /** The “force insert” checkbox. */
+ private JCheckBox fileOptionsForceInsertCheckBox;
+
/** The “insert redirect” checkbox. */
private JCheckBox fileOptionsInsertRedirectCheckBox;
/** The “mime type” combo box. */
private JComboBox fileOptionsMIMETypeComboBox;
- /** The “mime type” combo box model. */
- private DefaultComboBoxModel containerComboBoxModel;
-
- /** The “container” combo box. */
- private JComboBox fileOptionsContainerComboBox;
-
- /** The “edition replacement range” spinner. */
- private JSpinner replaceEditionRangeSpinner;
-
- /** The “replacement” check box. */
- private JCheckBox replacementCheckBox;
-
/**
* Creates a new project file page.
*
scanAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
scanAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.rescan.tooltip"));
- addContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.add-container")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionAddContainer();
- }
- };
- addContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.add-container.tooltip"));
- addContainerAction.setEnabled(false);
-
- editContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.edit-container")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionEditContainer();
- }
- };
- editContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.edit-container.tooltip"));
- editContainerAction.setEnabled(false);
-
- deleteContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.delete-container")) {
-
- @SuppressWarnings("synthetic-access")
- public void actionPerformed(ActionEvent actionEvent) {
- actionDeleteContainer();
- }
- };
- deleteContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.delete-container.tooltip"));
- deleteContainerAction.setEnabled(false);
-
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"));
- addContainerAction.putValue(Action.NAME, I18n.getMessage("jsite.project-files.action.add-container"));
- addContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.add-container.tooltip"));
- editContainerAction.putValue(Action.NAME, I18n.getMessage("jsite.project-files.action.edit-container"));
- editContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.edit-container.tooltip"));
- deleteContainerAction.putValue(Action.NAME, I18n.getMessage("jsite.project-files.action.delete-container"));
- deleteContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.delete-container.tooltip"));
}
});
}
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);
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, 5, 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, 5, 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, 5, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ 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"));
@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 {
});
- fileOptionsPanel.add(fileOptionsRenameCheckBox, new GridBagConstraints(0, 6, 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, 6, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
+ 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.setEnabled(false);
final TLabel mimeTypeLabel = new TLabel(I18n.getMessage("jsite.project-files.mime-type") + ":", KeyEvent.VK_M, fileOptionsMIMETypeComboBox);
- fileOptionsPanel.add(mimeTypeLabel, new GridBagConstraints(0, 7, 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, 7, 4, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- containerComboBoxModel = new DefaultComboBoxModel();
- fileOptionsContainerComboBox = new JComboBox(containerComboBoxModel);
- fileOptionsContainerComboBox.setToolTipText(I18n.getMessage("jsite.project-files.container.tooltip"));
- fileOptionsContainerComboBox.setName("project-files.container");
- fileOptionsContainerComboBox.addActionListener(this);
- fileOptionsContainerComboBox.setEnabled(false);
- fileOptionsContainerComboBox.setVisible(false);
-
- final TLabel containerLabel = new TLabel(I18n.getMessage("jsite.project-files.container") + ":", KeyEvent.VK_C, fileOptionsContainerComboBox);
- containerLabel.setVisible(false);
- JButton addContainerButton = new JButton(addContainerAction);
- addContainerButton.setVisible(false);
- JButton editContainerButton = new JButton(editContainerAction);
- editContainerButton.setVisible(false);
- JButton deleteContainerButton = new JButton(deleteContainerAction);
- deleteContainerButton.setVisible(false);
- fileOptionsPanel.add(containerLabel, 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(fileOptionsContainerComboBox, new GridBagConstraints(1, 8, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- fileOptionsPanel.add(addContainerButton, new GridBagConstraints(2, 8, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- fileOptionsPanel.add(editContainerButton, new GridBagConstraints(3, 8, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
- fileOptionsPanel.add(deleteContainerButton, new GridBagConstraints(4, 8, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
-
- JPanel fileOptionsReplacementPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 6, 6));
- fileOptionsReplacementPanel.setBorder(new EmptyBorder(-6, -6, -6, -6));
-
- replacementCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.replacement"));
- replacementCheckBox.setName("project-files.replace-edition");
- replacementCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.replacement.tooltip"));
- replacementCheckBox.addActionListener(this);
- replacementCheckBox.setEnabled(false);
- replacementCheckBox.setVisible(false);
- fileOptionsReplacementPanel.add(replacementCheckBox);
-
- replaceEditionRangeSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
- replaceEditionRangeSpinner.setName("project-files.replace-edition-range");
- replaceEditionRangeSpinner.setToolTipText(I18n.getMessage("jsite.project-files.replacement.edition-range.tooltip"));
- replaceEditionRangeSpinner.addChangeListener(this);
- replaceEditionRangeSpinner.setEnabled(false);
- replaceEditionRangeSpinner.setVisible(false);
- final JLabel editionRangeLabel = new JLabel(I18n.getMessage("jsite.project-files.replacement.edition-range"));
- editionRangeLabel.setVisible(false);
- fileOptionsReplacementPanel.add(editionRangeLabel);
- fileOptionsReplacementPanel.add(replaceEditionRangeSpinner);
-
- fileOptionsPanel.add(fileOptionsReplacementPanel, new GridBagConstraints(0, 9, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0));
+ 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() {
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"));
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") + ":");
- fileOptionsContainerComboBox.setToolTipText(I18n.getMessage("jsite.project-files.container.tooltip"));
- containerLabel.setText(I18n.getMessage("jsite.project-files.container") + ":");
- replacementCheckBox.setText(I18n.getMessage("jsite.project-files.replacement"));
- replacementCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.replacement.tooltip"));
- replaceEditionRangeSpinner.setToolTipText(I18n.getMessage("jsite.project-files.replacement.edition-range.tooltip"));
- editionRangeLabel.setText(I18n.getMessage("jsite.project-files.replacement.edition-range"));
}
});
});
}
- /**
- * Returns a list of all project files.
- *
- * @return All project files
- */
- private List<String> getProjectFiles() {
- List<String> files = new ArrayList<String>();
- for (int index = 0, size = projectFileList.getModel().getSize(); index < size; index++) {
- files.add((String) projectFileList.getModel().getElementAt(index));
- }
- return files;
- }
-
- /**
- * Updates the container combo box model.
- */
- private void rebuildContainerComboBox() {
- /* scan files for containers */
- List<String> files = getProjectFiles();
- List<String> containers = new ArrayList<String>(); // ComboBoxModel
- // sucks. No
- // contains()!
- containers.add("");
- for (String filename : files) {
- String container = project.getFileOption(filename).getContainer();
- if (!containers.contains(container)) {
- containers.add(container);
- }
- }
- Collections.sort(containers);
- containerComboBoxModel.removeAllElements();
- for (String container : containers) {
- containerComboBoxModel.addElement(container);
- }
- }
-
//
// ACTIONS
//
}
/**
- * Adds a container.
- */
- private void actionAddContainer() {
- String containerName = JOptionPane.showInputDialog(wizard, I18n.getMessage("jsite.project-files.action.add-container.message") + ":", null, JOptionPane.INFORMATION_MESSAGE);
- if (containerName == null) {
- return;
- }
- containerName = containerName.trim();
- String filename = (String) projectFileList.getSelectedValue();
- FileOption fileOption = project.getFileOption(filename);
- fileOption.setContainer(containerName);
- rebuildContainerComboBox();
- fileOptionsContainerComboBox.setSelectedItem(containerName);
- }
-
- /**
- * Edits the container.
- */
- private void actionEditContainer() {
- String selectedFilename = (String) projectFileList.getSelectedValue();
- FileOption fileOption = project.getFileOption(selectedFilename);
- String oldContainerName = fileOption.getContainer();
- String containerName = JOptionPane.showInputDialog(wizard, I18n.getMessage("jsite.project-files.action.edit-container.message") + ":", oldContainerName);
- if (containerName == null) {
- return;
- }
- if (containerName.equals("")) {
- fileOption.setContainer("");
- fileOptionsContainerComboBox.setSelectedItem("");
- return;
- }
- List<String> files = getProjectFiles();
- for (String filename : files) {
- fileOption = project.getFileOption(filename);
- if (fileOption.getContainer().equals(oldContainerName)) {
- fileOption.setContainer(containerName);
- }
- }
- rebuildContainerComboBox();
- fileOptionsContainerComboBox.setSelectedItem(containerName);
- }
-
- /**
- * Deletes the container.
- */
- private void actionDeleteContainer() {
- if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.action.delete-container.message"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
- String containerName = (String) fileOptionsContainerComboBox.getSelectedItem();
- List<String> files = getProjectFiles();
- for (String filename : files) {
- FileOption fileOption = project.getFileOption(filename);
- if (fileOption.getContainer().equals(containerName)) {
- fileOption.setContainer("");
- }
- }
- fileOptionsContainerComboBox.setSelectedItem("");
- }
- }
-
- /**
* {@inheritDoc}
* <p>
* Updates the file list.
public void fileScannerFinished(FileScanner fileScanner) {
final boolean error = fileScanner.isError();
if (!error) {
- final List<String> files = fileScanner.getFiles();
+ final List<ScannedFile> files = fileScanner.getFiles();
SwingUtilities.invokeLater(new Runnable() {
@SuppressWarnings("synthetic-access")
public void run() {
- projectFileList.setListData(files.toArray(new String[files.size()]));
+ projectFileList.setListData(files.toArray());
projectFileList.clearSelection();
- rebuildContainerComboBox();
}
});
Set<String> entriesToRemove = new HashSet<String>();
Iterator<String> filenames = new HashSet<String>(project.getFileOptions().keySet()).iterator();
while (filenames.hasNext()) {
String filename = filenames.next();
- if (!files.contains(filename)) {
+ boolean found = false;
+ for (ScannedFile scannedFile : files) {
+ if (scannedFile.getFilename().equals(filename)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
entriesToRemove.add(filename);
}
}
* no file is selected
*/
private FileOption getSelectedFile() {
- String filename = (String) projectFileList.getSelectedValue();
- if (filename == null) {
+ ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
+ if (scannedFile == null) {
return null;
}
- return project.getFileOption(filename);
+ return project.getFileOption(scannedFile.getFilename());
}
//
actionScan();
return;
}
- String filename = (String) projectFileList.getSelectedValue();
- if (filename == null) {
+ 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()) {
- project.setIndexFile(filename);
+ 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 {
- project.setIndexFile(null);
+ if (filename.equals(project.getIndexFile())) {
+ project.setIndexFile(null);
+ }
}
} else if ("insert".equals(checkBox.getName())) {
boolean isInsert = checkBox.isSelected();
fileOption.setInsert(isInsert);
- if (!isInsert) {
- fileOptionsContainerComboBox.setSelectedItem("");
- }
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);
boolean isRenamed = checkBox.isSelected();
fileOptionsRenameTextField.setEnabled(isRenamed);
fileOption.setChangedName(isRenamed ? fileOptionsRenameTextField.getText() : "");
- } else if ("project-files.replace-edition".equals(checkBox.getName())) {
- boolean replaceEdition = checkBox.isSelected();
- fileOption.setReplaceEdition(replaceEdition);
- replaceEditionRangeSpinner.setEnabled(replaceEdition);
}
} else if (source instanceof JComboBox) {
JComboBox comboBox = (JComboBox) source;
if ("project-files.mime-type".equals(comboBox.getName())) {
fileOption.setMimeType((String) comboBox.getSelectedItem());
- } else if ("project-files.container".equals(comboBox.getName())) {
- String containerName = (String) comboBox.getSelectedItem();
- fileOption.setContainer(containerName);
- boolean enabled = !"".equals(containerName);
- editContainerAction.setEnabled(enabled);
- deleteContainerAction.setEnabled(enabled);
- if (enabled) {
- fileOptionsInsertCheckBox.setSelected(true);
- }
}
}
}
/**
* {@inheritDoc}
*/
+ @SuppressWarnings("null")
public void valueChanged(ListSelectionEvent e) {
- String filename = (String) projectFileList.getSelectedValue();
- boolean enabled = filename != null;
- boolean insert = fileOptionsInsertCheckBox.isSelected();
+ 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);
- fileOptionsContainerComboBox.setEnabled(enabled);
- addContainerAction.setEnabled(enabled);
- editContainerAction.setEnabled(enabled);
- deleteContainerAction.setEnabled(enabled);
- replacementCheckBox.setEnabled(enabled && insert);
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());
fileOptionsRenameTextField.setEnabled(fileOption.hasChangedName());
fileOptionsRenameTextField.setText(fileOption.getChangedName());
fileOptionsMIMETypeComboBox.getModel().setSelectedItem(fileOption.getMimeType());
- fileOptionsContainerComboBox.setSelectedItem(fileOption.getContainer());
- replacementCheckBox.setSelected(fileOption.getReplaceEdition());
- replaceEditionRangeSpinner.setValue(fileOption.getEditionRange());
- replaceEditionRangeSpinner.setEnabled(fileOption.getReplaceEdition());
} else {
defaultFileCheckBox.setSelected(false);
fileOptionsInsertCheckBox.setSelected(true);
+ fileOptionsForceInsertCheckBox.setEnabled(false);
+ fileOptionsForceInsertCheckBox.setSelected(false);
fileOptionsInsertRedirectCheckBox.setEnabled(false);
fileOptionsInsertRedirectCheckBox.setSelected(false);
fileOptionsCustomKeyTextField.setEnabled(false);
fileOptionsRenameTextField.setEnabled(false);
fileOptionsRenameTextField.setText("");
fileOptionsMIMETypeComboBox.getModel().setSelectedItem(DefaultMIMETypes.DEFAULT_MIME_TYPE);
- fileOptionsContainerComboBox.setSelectedItem("");
- replacementCheckBox.setSelected(false);
- replaceEditionRangeSpinner.setValue(0);
}
}
* The document event to process
*/
private void processDocumentUpdate(DocumentEvent documentEvent) {
- String filename = (String) projectFileList.getSelectedValue();
- if (filename == null) {
+ ScannedFile scannedFile = (ScannedFile) projectFileList.getSelectedValue();
+ if (scannedFile == null) {
return;
}
- FileOption fileOption = project.getFileOption(filename);
+ FileOption fileOption = project.getFileOption(scannedFile.getFilename());
Document document = documentEvent.getDocument();
try {
String text = document.getText(0, document.getLength());
processDocumentUpdate(documentEvent);
}
- //
- // INTERFACE ChangeListener
- //
-
- /**
- * {@inheritDoc}
- */
- public void stateChanged(ChangeEvent changeEvent) {
- String filename = (String) projectFileList.getSelectedValue();
- if (filename == null) {
- return;
- }
- FileOption fileOption = project.getFileOption(filename);
- Object source = changeEvent.getSource();
- if (source instanceof JSpinner) {
- JSpinner spinner = (JSpinner) source;
- fileOption.setEditionRange((Integer) spinner.getValue());
- }
- }
-
}
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
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;
progressBar.setValue(0);
progressBar.setString(I18n.getMessage("jsite.insert.starting"));
progressBar.setFont(progressBar.getFont().deriveFont(Font.PLAIN));
- projectInserter.start();
+ 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);
+ }
+ });
+ }
+ });
}
/**
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
//
*/
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);
+ }
+ });
}
/**
@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;
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
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();
}
}
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * jSite-remote - I18nContainer.java Copyright © 2007 David Roden
+ * 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
#
-# jSite - a tool for uploading websites into Freenet
-# Copyright (C) 2006 David Roden
+# 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
# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
# otherwise the placeholder will not be replaced!
-jsite.main.already-running=<html><b>jSite is already running</b><br><br>A lock file has been found that suggests that another<br>instance of jSite is already running. Running multiple instances<br>of jSite is guaranteed to break your configuration.</html>
-jsite.main.already-running.override=Start anyway
-
jsite.general.ok=OK
jsite.general.cancel=Cancel
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.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-2010 David Roden<br>Released under the GNU General Public License</html>
+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.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.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!</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.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.action.add-container=Add
-jsite.project-files.action.add-container.tooltip=Adds a new container to the project and this file to it
-jsite.project-files.action.add-container.message=Enter the name of the new container
-jsite.project-files.action.edit-container=Edit
-jsite.project-files.action.edit-container.tooltip=Changes the name of the container
-jsite.project-files.action.edit-container.message=Enter the new name of the container
-jsite.project-files.action.delete-container=Delete
-jsite.project-files.action.delete-container.tooltip=Deletes this container
-jsite.project-files.action.delete-container.message=Do you really want to delete this container?
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.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.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.replacement=Replacements
-jsite.project-files.replacement.tooltip=Activates replacements in file
-jsite.project-files.replacement.edition-range=Range
-jsite.project-files.replacement.edition-range.tooltip=Also replace $[EDITION+1], $[EDITION+2]\u2026
jsite.project-files.scan-error=<html><b>Error scanning files</b><br><br>Either the directory of the project does not exist<br>or some files/directories in it are not accessible.<br>Please go back and select the correct directory.</html>
jsite.project-files.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.key-dialog.label.actions=<html><b>Actions</b></html>
jsite.warning.empty-index=<html><b>No default file</b><br><br>You did not specify a default file for this project.<br>While it is possible to insert a project without a default<br>file you should specify one to ease browsing.</html>
-jsite.warning.container-index=<html><b>Default file in container</b><br><br>Your default file was placed in a container!<br>This might make other people shun your page.</html>
jsite.warning.index-not-html=<html><b>Default file is not HTML</b><br><br>Your default file does not have the MIME type "text/html"!<br>Loading your Freesite in a browser may give unexpected results.</html>
jsite.error.no-node-selected=<html><b>No node selected</b><br><br>Please select a node from the menu!</html>
#
-# jSite - a tool for uploading websites into Freenet
-# Copyright (C) 2006 David Roden
+# 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
# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
# otherwise the placeholder will not be replaced!
-jsite.main.already-running=<html><b>jSite l\u00e4uft bereits!</b><br><br>Es wurde festgestellt, dass jSite bereits l\u00e4uft. Das kann<br>zu Besch\u00e4digungen an der Konfiguration f\u00fchren.</html>
-jsite.main.already-running.override=Trotzdem starten
-
jsite.general.ok=OK
jsite.general.cancel=Abbrechen
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.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-2010 David Roden<br>Ver\u00f6ffentlicht unter der GNU General Public License</html>
+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.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.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!</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.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.action.add-container=Hinzuf\u00fcgen
-jsite.project-files.action.add-container.tooltip=Erzeugt einen neuen Container und f\u00fcgt diese Datei hinzu
-jsite.project-files.action.add-container.message=Bitte geben Sie den Namen des neuen Containers an
-jsite.project-files.action.edit-container=\u00c4ndern
-jsite.project-files.action.edit-container.tooltip=\u00c4ndert den Namen des Containers
-jsite.project-files.action.edit-container.message=Bitte geben Sie den neuen Namen des Containers an
-jsite.project-files.action.delete-container=L\u00f6schen
-jsite.project-files.action.delete-container.tooltip=L\u00f6scht diesen Container
-jsite.project-files.action.delete-container.message=Wollen Sie diesen Container wirklich l\u00f6schen?
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.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.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.replacement=Ersetzungen
-jsite.project-files.replacement.tooltip=Aktiviert Ersetzungen in Datei
-jsite.project-files.replacement.edition-range=Reichweite
-jsite.project-files.replacement.edition-range.tooltip=Ersetzt auch $[EDITION+1], $[EDITION+2], usw.
jsite.project-files.scan-error=<html><b>Fehler beim Einlesen der Dateien</b><br><br>Entweder existiert das Projektverzeichnis nicht,<br>oder einige Dateien und/oder Verzeichnisse sind nicht lesbar!<br>Bitte gehen Sie zur\u00fcck und beheben Sie den Fehler!</html>
jsite.project-files.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.key-dialog.label.actions=<html><b>Aktionen</b></html>
jsite.warning.empty-index=<html><b>Keine Index-Datei gew\u00e4hlt</b><br><br>Sie haben keine Index-Datei f\u00fcr das Projekt angegeben.<br>Obwohl es m\u00f6glich ist, das zu machen, sollten Sie doch<br>eine Index-Datei angeben, um das Browsen zu erleichtern.</html>
-jsite.warning.container-index=<html><b>Index-Datei in Container</b><br><br>Ihre Index-Datei befindet sich in einem Container! Das kann<br>dazu f\u00fchren, dass Ihre Freesite von anderen Leuten gemieden wird.</html>
jsite.warning.index-not-html=<html><b>Index-Datei ist kein HTML</b><br><br>Ihre Index-Datei hat nicht den MIME-Typ "text/html"!<br>Das kann beim Besuch Ihrer Freesite zu<br>unerwarteten Ergebnissen f\u00fchren.</html>
jsite.error.no-node-selected=<html><b>Kein Node ausgew\u00e4hlt</b><br><br>Bitte w\u00e4hlen Sie einen Node aus dem Men\u00fc!</html>
#
-# jSite - a tool for uploading websites into Freenet
-# Copyright (C) 2006 David Roden
+# 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
# lines single quotes (ASCII 39) needs to be escaped by entering them twice,
# otherwise the placeholder will not be replaced!
-jsite.main.already-running=<html><b>jSite est d\u00e9ja lanc\u00e9!</b><br><br>Ne faites pas tourner plusieurs instances<br> sous peine de perdre vos fichiers de configuration !</html>
-jsite.main.already-running.override=D\u00e9marrer
-
jsite.general.ok=OK
jsite.general.cancel=Annuler
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.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-2010 David Roden<br>Released under the GNU General Public License</html>
+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.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.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.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.action.add-container=Ajouter
-jsite.project-files.action.add-container.tooltip=Ajouter un nouveau container au projet
-jsite.project-files.action.add-container.message=Entrez le nom du container
-jsite.project-files.action.edit-container=Editer
-jsite.project-files.action.edit-container.tooltip=Changer le nom du container
-jsite.project-files.action.edit-container.message=Entrez le nouveau nom du container
-jsite.project-files.action.delete-container=Supprimer
-jsite.project-files.action.delete-container.tooltip=Supprimer ce container.
-jsite.project-files.action.delete-container.message=Voulez vous r\u00e9ellement supprimer ce container?
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.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.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.replacement=Remplacer
-jsite.project-files.replacement.tooltip=Activer les remplacements
-jsite.project-files.replacement.edition-range=Plage
-jsite.project-files.replacement.edition-range.tooltip=Remplacer de $[EDITION+1] \u00e0 $[EDITION+2]
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.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.container-index=<html><b>Fichier principal du container</b><br><br>Votre fichier par d\u00e9faut \u00e0 \u00e9t\u00e9 plac\u00e9 dans un container!<br>Ceci peut avoir pour effet de cacher cette page aux utilisateurs.</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 -
- * Copyright (C) 2006 David Roden
+ * 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
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.
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>");
return;
}
- Configuration configuration = new Configuration();
- if (!configuration.createLockFile()) {
- outputWriter.println("Lock file found!");
- 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();
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);
}
}
+ 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);
}
/**
return false;
}
projectInserter.setProject(currentProject);
- projectInserter.start();
+ projectInserter.start(new ProgressListener() {
+
+ public void onProgress(long copied, long length) {
+ System.out.print("Uploaded: " + copied + " / " + length + " bytes...\r");
+ }
+ });
synchronized (lockObject) {
while (!finished) {
try {
* {@inheritDoc}
*/
public void projectUploadFinished(Project project) {
- outputWriter.println("Project \"" + project.getName() + "\" has ben uploaded, starting insert...");
+ outputWriter.println("Project \"" + project.getName() + "\" has been uploaded, starting insert...");
}
/**
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
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;
*/
public class Configuration {
- /** The name of the file the configuration is stored to. */
- private String filename;
-
- /** The name of the lock file. */
- private String lockFilename;
-
/** The root node of the configuration. */
private SimpleXML rootNode;
- /**
- * Creates a new configuration with the default name of the configuration
- * file.
- */
- public Configuration() {
- this(System.getProperty("user.home") + "/.jSite/config7");
- }
+ /** The configuration locator. */
+ private final ConfigurationLocator configurationLocator;
+
+ /** Where the configuration resides. */
+ private ConfigurationLocation configurationLocation;
/**
* Creates a new configuration that is read from the given file.
*
- * @param filename
- * The name of the configuration file
+ * @param configurationLocator
+ * The configuration locator
+ * @param configurationLocation
+ * The configuration directory
*/
- public Configuration(String filename) {
- this(filename, filename + ".lock");
+ public Configuration(ConfigurationLocator configurationLocator, ConfigurationLocation configurationLocation) {
+ this.configurationLocator = configurationLocator;
+ this.configurationLocation = configurationLocation;
+ readConfiguration(configurationLocator.getFile(configurationLocation));
}
- /**
- * Creates a new configuration that is read from the given file and uses the
- * given lock file.
- *
- * @param filename
- * The name of the configuration file
- * @param lockFilename
- * The name of the lock file
- */
- public Configuration(String filename, String lockFilename) {
- this.filename = filename;
- this.lockFilename = lockFilename;
- readConfiguration();
- }
+ //
+ // ACCESSORS
+ //
/**
- * Creates the directory of the configuration file.
+ * Returns the configuration locator.
*
- * @return <code>true</code> if the directory exists, or if it could be
- * created, <code>false</code> otherwise
+ * @return The configuration locator
*/
- private boolean createConfigDirectory() {
- File configDirectory = new File(filename).getAbsoluteFile().getParentFile();
- return (configDirectory.exists() && configDirectory.isDirectory()) || configDirectory.mkdirs();
+ public ConfigurationLocator getConfigurationLocator() {
+ return configurationLocator;
}
/**
- * Creates the lock file.
+ * Returns the location the configuration will be written to when calling
+ * {@link #save()}.
*
- * @return <code>true</code> if the lock file did not already exist and
- * could be created, <code>false</code> otherwise
+ * @return The location the configuration will be written to
*/
- public boolean createLockFile() {
- if (!createConfigDirectory()) {
- return false;
- }
- File lockFile = new File(lockFilename);
- try {
- boolean fileLocked = lockFile.createNewFile();
- if (fileLocked) {
- lockFile.deleteOnExit();
- }
- return fileLocked;
- } catch (IOException e) {
- /* ignore. */
- }
- return false;
+ public ConfigurationLocation getConfigurationDirectory() {
+ return configurationLocation;
}
/**
- * Tells the VM to remove the lock file on program exit.
+ * Sets the location the configuration will be written to when calling
+ * {@link #save()}.
+ *
+ * @param configurationLocation
+ * The location to write the configuration to
*/
- public void removeLockfileOnExit() {
- new File(lockFilename).deleteOnExit();
+ public void setConfigurationLocation(ConfigurationLocation configurationLocation) {
+ this.configurationLocation = configurationLocation;
}
/**
* Reads the configuration from the file.
+ *
+ * @param filename
+ * The name of the file to read the configuration from
*/
- private void readConfiguration() {
- File configurationFile = new File(filename);
- if (configurationFile.exists()) {
- ByteArrayOutputStream fileByteOutputStream = null;
- FileInputStream fileInputStream = null;
- try {
- fileByteOutputStream = new ByteArrayOutputStream();
- fileInputStream = new FileInputStream(configurationFile);
- StreamCopier.copy(fileInputStream, fileByteOutputStream, configurationFile.length());
- fileByteOutputStream.close();
- byte[] fileBytes = fileByteOutputStream.toByteArray();
- rootNode = SimpleXML.fromDocument(XML.transformToDocument(fileBytes));
- return;
- } catch (FileNotFoundException e) {
- /* ignore. */
- } catch (IOException e) {
- /* ignore. */
- } finally {
- Closer.close(fileInputStream);
- Closer.close(fileByteOutputStream);
+ private void readConfiguration(String filename) {
+ Logger.getLogger(Configuration.class.getName()).log(Level.CONFIG, "Reading configuration from: " + filename);
+ if (filename != null) {
+ File configurationFile = new File(filename);
+ if (configurationFile.exists()) {
+ ByteArrayOutputStream fileByteOutputStream = null;
+ FileInputStream fileInputStream = null;
+ try {
+ fileByteOutputStream = new ByteArrayOutputStream();
+ fileInputStream = new FileInputStream(configurationFile);
+ StreamCopier.copy(fileInputStream, fileByteOutputStream, configurationFile.length());
+ fileByteOutputStream.close();
+ byte[] fileBytes = fileByteOutputStream.toByteArray();
+ rootNode = SimpleXML.fromDocument(XML.transformToDocument(fileBytes));
+ return;
+ } catch (FileNotFoundException e) {
+ /* ignore. */
+ } catch (IOException e) {
+ /* ignore. */
+ } finally {
+ Closer.close(fileInputStream);
+ Closer.close(fileByteOutputStream);
+ }
}
}
rootNode = new SimpleXML("configuration");
* <code>false</code> otherwise
*/
public boolean save() {
- File configurationFile = new File(filename);
+ Logger.getLogger(Configuration.class.getName()).log(Level.CONFIG, "Trying to save configuration to: " + configurationLocation);
+ File configurationFile = new File(configurationLocator.getFile(configurationLocation));
if (!configurationFile.exists()) {
File configurationFilePath = configurationFile.getAbsoluteFile().getParentFile();
if (!configurationFilePath.exists() && !configurationFilePath.mkdirs()) {
Project project = new Project();
projects.add(project);
project.setDescription(projectNode.getNode("description").getValue(""));
- project.setIndexFile(projectNode.getNode("index-file").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(""));
} else {
project.setIgnoreHiddenFiles(true);
}
- SimpleXML fileOptionsNode = projectNode.getNode("file-options");
+
+ /* 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) {
fileOption.setChangedName(fileOptionNode.getNode("changed-name").getValue());
}
fileOption.setMimeType(fileOptionNode.getNode("mime-type").getValue(""));
- fileOption.setContainer(fileOptionNode.getNode("container").getValue());
- if (fileOptionNode.getNode("replace-edition") != null) {
- fileOption.setReplaceEdition(Boolean.parseBoolean(fileOptionNode.getNode("replace-edition").getValue()));
- fileOption.setEditionRange(Integer.parseInt(fileOptionNode.getNode("edition-range").getValue()));
- }
fileOptions.put(filename, fileOption);
}
}
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()) {
fileOptionNode.append("custom-key", fileOption.getCustomKey());
fileOptionNode.append("changed-name", fileOption.getChangedName());
fileOptionNode.append("mime-type", fileOption.getMimeType());
- fileOptionNode.append("container", fileOption.getContainer());
- fileOptionNode.append("replace-edition", String.valueOf(fileOption.getReplaceEdition()));
- fileOptionNode.append("edition-range", String.valueOf(fileOption.getEditionRange()));
}
}
}
}
}
+ /**
+ * 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;
+ }
+
+}
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006-2009 David Roden
+ * 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
package de.todesbaum.jsite.main;
+import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
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 de.todesbaum.jsite.application.Node;
import de.todesbaum.jsite.application.Project;
import de.todesbaum.jsite.application.ProjectInserter;
-import de.todesbaum.jsite.application.UpdateChecker;
-import de.todesbaum.jsite.application.UpdateListener;
import de.todesbaum.jsite.application.ProjectInserter.CheckReport;
import de.todesbaum.jsite.application.ProjectInserter.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.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;
private static final Logger logger = Logger.getLogger(Main.class.getName());
/** The version. */
- private static final Version VERSION = new Version(0, 9, 2);
+ private static final Version VERSION = new Version(0, 10);
/** The configuration. */
private Configuration configuration;
/** 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.
*/
* The name of the configuration file
*/
private Main(String configFilename) {
+ /* collect all possible configuration file locations. */
+ ConfigurationLocator configurationLocator = new ConfigurationLocator();
if (configFilename != null) {
- configuration = new Configuration(configFilename);
- } else {
- configuration = new Configuration();
+ 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());
- if (!configuration.createLockFile()) {
- int option = JOptionPane.showOptionDialog(null, I18n.getMessage("jsite.main.already-running"), "", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[] { I18n.getMessage("jsite.main.already-running.override"), I18n.getMessage("jsite.wizard.quit") }, I18n.getMessage("jsite.wizard.quit"));
- if (option != 0) {
- throw new IllegalStateException("Lockfile override not active, refusing start.");
- }
- configuration.removeLockfileOnExit();
- }
wizard = new TWizard();
createActions();
wizard.setJMenuBar(createMenuBar());
}
/**
+ * 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,
* 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);
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);
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());
}
}
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"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
- if (saveConfiguration()) {
- System.exit(0);
+ 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);
/**
* {@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) {
/*
- * jSite - a tool for uploading websites into Freenet
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
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.
}
/**
+ * 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.
*
* 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.add(command.getIdentifier());
}
- connection.execute(command);
+ connection.execute(command, progressListener);
}
/**
/*
- * jSite-remote - ClientGet.java -
- * Copyright © 2008 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
* @author David Roden <droden@gmail.com>
* @version $Id$
*/
-public class ClientPutComplexDir extends ClientPutDir {
+public class ClientPutComplexDir extends ClientPutDir<ClientPutComplexDir> {
/** The file entries of this directory. */
private List<FileEntry> fileEntries = new ArrayList<FileEntry>();
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/**
* 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>
- * @version $Id$
*/
-public class ClientPutDir extends ClientPut {
+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.
*
}
/**
+ * 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
super.write(writer);
if (defaultName != null)
writer.write("DefaultName=" + defaultName + LINEFEED);
+ if (manifestPutter != null) {
+ writer.write("ManifestPutter=" + manifestPutter.getName() + LINEFEED);
+ }
}
}
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
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;
/**
* Disconnects from the node.
*/
public void disconnect() {
- if (nodeWriter != null) {
- try {
- nodeWriter.close();
- } catch (IOException ioe1) {
- }
- nodeWriter = null;
- }
- if (nodeOutputStream != null) {
- try {
- nodeOutputStream.close();
- } catch (IOException ioe1) {
- }
- nodeOutputStream = null;
- }
- if (nodeInputStream != null) {
- try {
- nodeInputStream.close();
- } catch (IOException ioe1) {
- }
- nodeInputStream = null;
- }
- if (nodeSocket != null) {
- try {
- nodeSocket.close();
- } catch (IOException ioe1) {
- }
- nodeSocket = null;
- }
+ 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();
}
* 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");
}
InputStream payloadInputStream = null;
try {
payloadInputStream = command.getPayload();
- StreamCopier.copy(payloadInputStream, nodeOutputStream, command.getPayloadLength());
+ StreamCopier.copy(payloadInputStream, nodeOutputStream, command.getPayloadLength(), progressListener);
} finally {
Closer.close(payloadInputStream);
}
* Main loop of the reader. Lines are read and converted into
* {@link Message} objects.
*/
+ @SuppressWarnings("synthetic-access")
public void run() {
LineInputStream nodeReader = null;
try {
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
import java.util.Map.Entry;
+import java.util.Set;
/**
* Contains replies sent by the Freenet node. A message always has a name, and
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
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;
+ }
+
}
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * jSite-remote - ReturnType.java -
- * Copyright © 2008 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
+ * 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
/*
- * todesbaum-lib - Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
+++ /dev/null
-/*
- * todesbaum-lib -
- * Copyright (C) 2006 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.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-
-
-/**
- * @author David Roden <droden@gmail.com>
- * @version $Id$
- */
-public class ReplacingOutputStream extends FilterOutputStream {
-
- private Map<String, String> replacements = new HashMap<String, String>();
- private StringBuffer ringBuffer = new StringBuffer();
-
- /**
- * @param out
- */
- public ReplacingOutputStream(OutputStream out) {
- super(out);
- }
-
- public void addReplacement(String token, String value) {
- replacements.put(token, value);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(int b) throws IOException {
- ringBuffer.append((char) b);
- Iterator<Entry<String, String>> entries = replacements.entrySet().iterator();
- boolean found = false;
- Entry<String, String> entry = null;
- while (!found && entries.hasNext()) {
- entry = entries.next();
- if (entry.getKey().startsWith(ringBuffer.toString())) {
- found = true;
- }
- }
- if (!found) {
- String buffer = ringBuffer.toString();
- for (int index = 0, size = buffer.length(); index < size; index++) {
- super.write(buffer.charAt(index));
- }
- ringBuffer.setLength(0);
- } else {
- if (entry.getKey().equals(ringBuffer.toString())) {
- String buffer = entry.getValue();
- for (int index = 0, size = buffer.length(); index < size; index++) {
- super.write(buffer.charAt(index));
- }
- ringBuffer.setLength(0);
- }
- }
- }
-
-}
/*
+ * 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
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}.
}
/**
+ * 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>.
*
/**
* 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
* 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) {
}
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);
+ }
+ }
+
+}
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
- * todesbaum-lib -
- * Copyright (C) 2006 David Roden
+ * 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
/*
+ * 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
/*
+ * 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