Add missing @Override annotations.
[jSite.git] / src / de / todesbaum / jsite / gui / ProjectPage.java
1 /*
2  * jSite - ProjectPage.java - Copyright © 2006–2012 David Roden
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 package de.todesbaum.jsite.gui;
20
21 import java.awt.BorderLayout;
22 import java.awt.Dimension;
23 import java.awt.FlowLayout;
24 import java.awt.GridBagConstraints;
25 import java.awt.GridBagLayout;
26 import java.awt.Insets;
27 import java.awt.Toolkit;
28 import java.awt.datatransfer.Clipboard;
29 import java.awt.datatransfer.ClipboardOwner;
30 import java.awt.datatransfer.StringSelection;
31 import java.awt.datatransfer.Transferable;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.KeyEvent;
34 import java.io.IOException;
35 import java.text.MessageFormat;
36
37 import javax.swing.AbstractAction;
38 import javax.swing.Action;
39 import javax.swing.JButton;
40 import javax.swing.JComponent;
41 import javax.swing.JFileChooser;
42 import javax.swing.JLabel;
43 import javax.swing.JList;
44 import javax.swing.JOptionPane;
45 import javax.swing.JPanel;
46 import javax.swing.JScrollPane;
47 import javax.swing.JTextField;
48 import javax.swing.ListSelectionModel;
49 import javax.swing.border.EmptyBorder;
50 import javax.swing.event.DocumentEvent;
51 import javax.swing.event.DocumentListener;
52 import javax.swing.event.ListSelectionEvent;
53 import javax.swing.event.ListSelectionListener;
54 import javax.swing.text.AbstractDocument;
55 import javax.swing.text.AttributeSet;
56 import javax.swing.text.BadLocationException;
57 import javax.swing.text.Document;
58 import javax.swing.text.DocumentFilter;
59
60 import de.todesbaum.jsite.application.Freenet7Interface;
61 import de.todesbaum.jsite.application.KeyDialog;
62 import de.todesbaum.jsite.application.Project;
63 import de.todesbaum.jsite.i18n.I18n;
64 import de.todesbaum.jsite.i18n.I18nContainer;
65 import de.todesbaum.util.swing.SortedListModel;
66 import de.todesbaum.util.swing.TLabel;
67 import de.todesbaum.util.swing.TWizard;
68 import de.todesbaum.util.swing.TWizardPage;
69
70 /**
71  * Wizard page that lets the user manage his projects and start inserts.
72  *
73  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
74  */
75 public class ProjectPage extends TWizardPage implements ListSelectionListener, DocumentListener, ClipboardOwner {
76
77         /** The freenet interface. */
78         private Freenet7Interface freenetInterface;
79
80         /** The “browse” action. */
81         private Action projectLocalPathBrowseAction;
82
83         /** The “add project” action. */
84         private Action projectAddAction;
85
86         /** The “delete project” action. */
87         private Action projectDeleteAction;
88
89         /** The “clone project” action. */
90         private Action projectCloneAction;
91
92         /** The “manage keys” action. */
93         private Action projectManageKeysAction;
94
95         /** The “copy URI” action. */
96         private Action projectCopyURIAction;
97
98         /** The “reset edition” action. */
99         private Action projectResetEditionAction;
100
101         /** The file chooser. */
102         private JFileChooser pathChooser;
103
104         /** The project list model. */
105         private SortedListModel<Project> projectListModel;
106
107         /** The project list scroll pane. */
108         private JScrollPane projectScrollPane;
109
110         /** The project list. */
111         private JList projectList;
112
113         /** The project name textfield. */
114         private JTextField projectNameTextField;
115
116         /** The project description textfield. */
117         private JTextField projectDescriptionTextField;
118
119         /** The local path textfield. */
120         private JTextField projectLocalPathTextField;
121
122         /** The textfield for the complete URI. */
123         private JTextField projectCompleteUriTextField;
124
125         /** The project path textfield. */
126         private JTextField projectPathTextField;
127
128         /** Whether the “copy URI to clipboard” action was used. */
129         private boolean uriCopied;
130
131         /**
132          * Creates a new project page.
133          *
134          * @param wizard
135          *            The wizard this page belongs to
136          */
137         public ProjectPage(final TWizard wizard) {
138                 super(wizard);
139                 setLayout(new BorderLayout(12, 12));
140                 dialogInit();
141                 setHeading(I18n.getMessage("jsite.project.heading"));
142                 setDescription(I18n.getMessage("jsite.project.description"));
143
144                 I18nContainer.getInstance().registerRunnable(new Runnable() {
145
146                         @Override
147                         public void run() {
148                                 setHeading(I18n.getMessage("jsite.project.heading"));
149                                 setDescription(I18n.getMessage("jsite.project.description"));
150                         }
151                 });
152         }
153
154         /**
155          * Initializes the page.
156          */
157         private void dialogInit() {
158                 createActions();
159
160                 pathChooser = new JFileChooser();
161                 projectListModel = new SortedListModel<Project>();
162                 projectList = new JList(projectListModel);
163                 projectList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
164                 projectList.addListSelectionListener(this);
165
166                 add(projectScrollPane = new JScrollPane(projectList), BorderLayout.LINE_START);
167                 projectScrollPane.setPreferredSize(new Dimension(150, projectList.getPreferredSize().height));
168                 add(createInformationPanel(), BorderLayout.CENTER);
169         }
170
171         /**
172          * {@inheritDoc}
173          */
174         @Override
175         public void pageAdded(TWizard wizard) {
176                 super.pageAdded(wizard);
177                 projectList.clearSelection();
178                 this.wizard.setPreviousName(I18n.getMessage("jsite.menu.nodes.manage-nodes"));
179                 this.wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
180                 this.wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
181                 this.wizard.setNextEnabled(false);
182         }
183
184         /**
185          * Adds the given listener to the list of listeners.
186          *
187          * @param listener
188          *            The listener to add
189          */
190         public void addListSelectionListener(ListSelectionListener listener) {
191                 projectList.addListSelectionListener(listener);
192         }
193
194         /**
195          * Removes the given listener from the list of listeners.
196          *
197          * @param listener
198          *            The listener to remove
199          */
200         public void removeListSelectionListener(ListSelectionListener listener) {
201                 projectList.removeListSelectionListener(listener);
202         }
203
204         /**
205          * Creates all actions.
206          */
207         private void createActions() {
208                 projectLocalPathBrowseAction = new AbstractAction(I18n.getMessage("jsite.project.action.browse")) {
209
210                         @Override
211                         @SuppressWarnings("synthetic-access")
212                         public void actionPerformed(ActionEvent actionEvent) {
213                                 actionLocalPathBrowse();
214                         }
215                 };
216                 projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip"));
217                 projectLocalPathBrowseAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_B);
218                 projectLocalPathBrowseAction.setEnabled(false);
219
220                 projectAddAction = new AbstractAction(I18n.getMessage("jsite.project.action.add-project")) {
221
222                         @Override
223                         @SuppressWarnings("synthetic-access")
224                         public void actionPerformed(ActionEvent actionEvent) {
225                                 actionAdd();
226                         }
227                 };
228                 projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip"));
229                 projectAddAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
230
231                 projectDeleteAction = new AbstractAction(I18n.getMessage("jsite.project.action.delete-project")) {
232
233                         @Override
234                         @SuppressWarnings("synthetic-access")
235                         public void actionPerformed(ActionEvent actionEvent) {
236                                 actionDelete();
237                         }
238                 };
239                 projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip"));
240                 projectDeleteAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
241                 projectDeleteAction.setEnabled(false);
242
243                 projectCloneAction = new AbstractAction(I18n.getMessage("jsite.project.action.clone-project")) {
244
245                         @Override
246                         @SuppressWarnings("synthetic-access")
247                         public void actionPerformed(ActionEvent actionEvent) {
248                                 actionClone();
249                         }
250                 };
251                 projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip"));
252                 projectCloneAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_L);
253                 projectCloneAction.setEnabled(false);
254
255                 projectCopyURIAction = new AbstractAction(I18n.getMessage("jsite.project.action.copy-uri")) {
256
257                         @Override
258                         @SuppressWarnings("synthetic-access")
259                         public void actionPerformed(ActionEvent actionEvent) {
260                                 actionCopyURI();
261                         }
262                 };
263                 projectCopyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
264                 projectCopyURIAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_U);
265                 projectCopyURIAction.setEnabled(false);
266
267                 projectManageKeysAction = new AbstractAction(I18n.getMessage("jsite.project.action.manage-keys")) {
268
269                         @Override
270                         @SuppressWarnings("synthetic-access")
271                         public void actionPerformed(ActionEvent actionEvent) {
272                                 actionManageKeys();
273                         }
274                 };
275                 projectManageKeysAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.manage-keys.tooltip"));
276                 projectManageKeysAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_M);
277                 projectManageKeysAction.setEnabled(false);
278
279                 projectResetEditionAction = new AbstractAction(I18n.getMessage("jsite.project.action.reset-edition")) {
280
281                         @Override
282                         @SuppressWarnings("synthetic-access")
283                         public void actionPerformed(ActionEvent actionEvent) {
284                                 actionResetEdition();
285                         }
286                 };
287                 projectResetEditionAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.reset-edition.tooltip"));
288                 projectResetEditionAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_R);
289                 projectResetEditionAction.setEnabled(false);
290
291                 I18nContainer.getInstance().registerRunnable(new Runnable() {
292
293                         @Override
294                         @SuppressWarnings("synthetic-access")
295                         public void run() {
296                                 projectLocalPathBrowseAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.browse"));
297                                 projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip"));
298                                 projectAddAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.add-project"));
299                                 projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip"));
300                                 projectDeleteAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.delete-project"));
301                                 projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip"));
302                                 projectCloneAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.clone-project"));
303                                 projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip"));
304                                 projectCopyURIAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.copy-uri"));
305                                 projectCopyURIAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.copy-uri.tooltip"));
306                                 projectManageKeysAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.manage-keys"));
307                                 projectManageKeysAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.manage-keys.tooltip"));
308                                 projectResetEditionAction.putValue(Action.NAME, I18n.getMessage("jsite.project.action.reset-edition"));
309                                 projectResetEditionAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.reset-edition.tooltip"));
310                                 pathChooser.setApproveButtonText(I18n.getMessage("jsite.project.action.browse.choose"));
311                         }
312                 });
313         }
314
315         /**
316          * Creates the information panel.
317          *
318          * @return The information panel
319          */
320         private JComponent createInformationPanel() {
321                 JPanel informationPanel = new JPanel(new BorderLayout(12, 12));
322
323                 JPanel informationTable = new JPanel(new GridBagLayout());
324
325                 JPanel functionButtons = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12));
326                 functionButtons.setBorder(new EmptyBorder(-12, -12, -12, -12));
327                 functionButtons.add(new JButton(projectAddAction));
328                 functionButtons.add(new JButton(projectDeleteAction));
329                 functionButtons.add(new JButton(projectCloneAction));
330                 functionButtons.add(new JButton(projectManageKeysAction));
331
332                 informationPanel.add(functionButtons, BorderLayout.PAGE_START);
333                 informationPanel.add(informationTable, BorderLayout.CENTER);
334
335                 final JLabel projectInformationLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.information") + "</b></html>");
336                 informationTable.add(projectInformationLabel, new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
337
338                 projectNameTextField = new JTextField();
339                 projectNameTextField.getDocument().putProperty("name", "project.name");
340                 projectNameTextField.getDocument().addDocumentListener(this);
341                 projectNameTextField.setEnabled(false);
342
343                 final TLabel projectNameLabel = new TLabel(I18n.getMessage("jsite.project.project.name") + ":", KeyEvent.VK_N, projectNameTextField);
344                 informationTable.add(projectNameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
345                 informationTable.add(projectNameTextField, new GridBagConstraints(1, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
346
347                 projectDescriptionTextField = new JTextField();
348                 projectDescriptionTextField.getDocument().putProperty("name", "project.description");
349                 projectDescriptionTextField.getDocument().addDocumentListener(this);
350                 projectDescriptionTextField.setEnabled(false);
351
352                 final TLabel projectDescriptionLabel = new TLabel(I18n.getMessage("jsite.project.project.description") + ":", KeyEvent.VK_D, projectDescriptionTextField);
353                 informationTable.add(projectDescriptionLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
354                 informationTable.add(projectDescriptionTextField, new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
355
356                 projectLocalPathTextField = new JTextField();
357                 projectLocalPathTextField.getDocument().putProperty("name", "project.localpath");
358                 projectLocalPathTextField.getDocument().addDocumentListener(this);
359                 projectLocalPathTextField.setEnabled(false);
360
361                 final TLabel projectLocalPathLabel = new TLabel(I18n.getMessage("jsite.project.project.local-path") + ":", KeyEvent.VK_L, projectLocalPathTextField);
362                 informationTable.add(projectLocalPathLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
363                 informationTable.add(projectLocalPathTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
364                 informationTable.add(new JButton(projectLocalPathBrowseAction), new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
365
366                 final JLabel projectAddressLabel = new JLabel("<html><b>" + I18n.getMessage("jsite.project.project.address") + "</b></html>");
367                 informationTable.add(projectAddressLabel, new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0));
368
369                 projectPathTextField = new JTextField();
370                 projectPathTextField.getDocument().putProperty("name", "project.path");
371                 projectPathTextField.getDocument().addDocumentListener(this);
372                 ((AbstractDocument) projectPathTextField.getDocument()).setDocumentFilter(new DocumentFilter() {
373
374                         /**
375                          * {@inheritDoc}
376                          */
377                         @Override
378                         @SuppressWarnings("synthetic-access")
379                         public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
380                                 super.insertString(fb, offset, string.replaceAll("/", ""), attr);
381                                 updateCompleteURI();
382                         }
383
384                         /**
385                          * {@inheritDoc}
386                          */
387                         @Override
388                         @SuppressWarnings("synthetic-access")
389                         public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
390                                 super.replace(fb, offset, length, text.replaceAll("/", ""), attrs);
391                                 updateCompleteURI();
392                         }
393
394                         /**
395                          * {@inheritDoc}
396                          */
397                         @Override
398                         @SuppressWarnings("synthetic-access")
399                         public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
400                                 super.remove(fb, offset, length);
401                                 updateCompleteURI();
402                         }
403                 });
404                 projectPathTextField.setEnabled(false);
405
406                 final TLabel projectPathLabel = new TLabel(I18n.getMessage("jsite.project.project.path") + ":", KeyEvent.VK_P, projectPathTextField);
407                 informationTable.add(projectPathLabel, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
408                 informationTable.add(projectPathTextField, new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
409
410                 projectCompleteUriTextField = new JTextField();
411                 projectCompleteUriTextField.setEditable(false);
412                 final TLabel projectUriLabel = new TLabel(I18n.getMessage("jsite.project.project.uri") + ":", KeyEvent.VK_U, projectCompleteUriTextField);
413                 informationTable.add(projectUriLabel, new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0));
414                 informationTable.add(projectCompleteUriTextField, new GridBagConstraints(1, 6, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
415                 informationTable.add(new JButton(projectCopyURIAction), new GridBagConstraints(2, 6, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0));
416
417                 I18nContainer.getInstance().registerRunnable(new Runnable() {
418
419                         @Override
420                         public void run() {
421                                 projectInformationLabel.setText("<html><b>" + I18n.getMessage("jsite.project.project.information") + "</b></html>");
422                                 projectNameLabel.setText(I18n.getMessage("jsite.project.project.name") + ":");
423                                 projectDescriptionLabel.setText(I18n.getMessage("jsite.project.project.description") + ":");
424                                 projectLocalPathLabel.setText(I18n.getMessage("jsite.project.project.local-path") + ":");
425                                 projectAddressLabel.setText("<html><b>" + I18n.getMessage("jsite.project.project.address") + "</b></html>");
426                                 projectPathLabel.setText(I18n.getMessage("jsite.project.project.path") + ":");
427                                 projectUriLabel.setText(I18n.getMessage("jsite.project.project.uri") + ":");
428                         }
429                 });
430
431                 return informationPanel;
432         }
433
434         /**
435          * Sets the project list.
436          *
437          * @param projects
438          *            The list of projects
439          */
440         public void setProjects(Project[] projects) {
441                 projectListModel.clear();
442                 for (Project project : projects) {
443                         projectListModel.add(project);
444                 }
445         }
446
447         /**
448          * Returns the list of projects.
449          *
450          * @return The list of projects
451          */
452         public Project[] getProjects() {
453                 return projectListModel.toArray(new Project[projectListModel.size()]);
454         }
455
456         /**
457          * Sets the freenet interface to use.
458          *
459          * @param freenetInterface
460          *            The freenetInterface to use
461          */
462         public void setFreenetInterface(Freenet7Interface freenetInterface) {
463                 this.freenetInterface = freenetInterface;
464         }
465
466         /**
467          * Returns the currently selected project.
468          *
469          * @return The currently selected project
470          */
471         public Project getSelectedProject() {
472                 return (Project) projectList.getSelectedValue();
473         }
474
475         /**
476          * Returns whether the “copy URI to clipboard” button was used.
477          *
478          * @return {@code true} if the “copy URI to clipboard” button was used,
479          *         {@code false} otherwise
480          */
481         public boolean wasUriCopied() {
482                 return uriCopied;
483         }
484
485         /**
486          * Updates the currently selected project with changed information from a
487          * textfield.
488          *
489          * @param documentEvent
490          *            The document event to process
491          */
492         private void setTextField(DocumentEvent documentEvent) {
493                 Document document = documentEvent.getDocument();
494                 String propertyName = (String) document.getProperty("name");
495                 Project project = (Project) projectList.getSelectedValue();
496                 if (project == null) {
497                         return;
498                 }
499                 try {
500                         String text = document.getText(0, document.getLength()).trim();
501                         if ("project.name".equals(propertyName)) {
502                                 project.setName(text);
503                                 projectList.repaint();
504                         } else if ("project.description".equals(propertyName)) {
505                                 project.setDescription(text);
506                         } else if ("project.localpath".equals(propertyName)) {
507                                 project.setLocalPath(text);
508                         } else if ("project.privatekey".equals(propertyName)) {
509                                 project.setInsertURI(text);
510                         } else if ("project.publickey".equals(propertyName)) {
511                                 project.setRequestURI(text);
512                         } else if ("project.path".equals(propertyName)) {
513                                 project.setPath(text);
514                         }
515                 } catch (BadLocationException e) {
516                         /* ignore. */
517                 }
518         }
519
520         //
521         // ACTIONS
522         //
523
524         /**
525          * Lets the user choose a local path for a project.
526          */
527         private void actionLocalPathBrowse() {
528                 Project project = (Project) projectList.getSelectedValue();
529                 if (project == null) {
530                         return;
531                 }
532                 pathChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
533                 if (pathChooser.showDialog(this, I18n.getMessage("jsite.project.action.browse.choose")) == JFileChooser.APPROVE_OPTION) {
534                         projectLocalPathTextField.setText(pathChooser.getSelectedFile().getPath());
535                 }
536         }
537
538         /**
539          * Adds a new project.
540          */
541         private void actionAdd() {
542                 String[] keyPair = null;
543                 if (!freenetInterface.hasNode()) {
544                         JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
545                         return;
546                 }
547                 try {
548                         keyPair = freenetInterface.generateKeyPair();
549                 } catch (IOException ioe1) {
550                         JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE);
551                         return;
552                 }
553                 Project newProject = new Project();
554                 newProject.setName(I18n.getMessage("jsite.project.new-project.name"));
555                 newProject.setInsertURI(keyPair[0]);
556                 newProject.setRequestURI(keyPair[1]);
557                 newProject.setEdition(-1);
558                 newProject.setPath("");
559                 projectListModel.add(newProject);
560                 projectScrollPane.revalidate();
561                 projectScrollPane.repaint();
562                 projectList.setSelectedIndex(projectListModel.indexOf(newProject));
563         }
564
565         /**
566          * Deletes the currently selected project.
567          */
568         private void actionDelete() {
569                 int selectedIndex = projectList.getSelectedIndex();
570                 if (selectedIndex > -1) {
571                         if (JOptionPane.showConfirmDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.action.delete-project.confirm"), ((Project) projectList.getSelectedValue()).getName()), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
572                                 projectListModel.remove(selectedIndex);
573                                 projectList.clearSelection();
574                                 if (projectListModel.getSize() != 0) {
575                                         projectList.setSelectedIndex(Math.min(selectedIndex, projectListModel.getSize() - 1));
576                                 }
577                         }
578                 }
579         }
580
581         /**
582          * Clones the currently selected project.
583          */
584         private void actionClone() {
585                 int selectedIndex = projectList.getSelectedIndex();
586                 if (selectedIndex > -1) {
587                         Project newProject = new Project((Project) projectList.getSelectedValue());
588                         newProject.setName(MessageFormat.format(I18n.getMessage("jsite.project.action.clone-project.copy"), newProject.getName()));
589                         projectListModel.add(newProject);
590                         projectList.setSelectedIndex(projectListModel.indexOf(newProject));
591                 }
592         }
593
594         /**
595          * Copies the request URI of the currently selected project to the
596          * clipboard.
597          */
598         private void actionCopyURI() {
599                 int selectedIndex = projectList.getSelectedIndex();
600                 if (selectedIndex > -1) {
601                         Project selectedProject = (Project) projectList.getSelectedValue();
602                         Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
603                         clipboard.setContents(new StringSelection(selectedProject.getFinalRequestURI(0)), this);
604                         uriCopied = true;
605                 }
606         }
607
608         /**
609          * Opens a {@link KeyDialog} and lets the user manipulate the keys of the
610          * project.
611          */
612         private void actionManageKeys() {
613                 int selectedIndex = projectList.getSelectedIndex();
614                 if (selectedIndex > -1) {
615                         Project selectedProject = (Project) projectList.getSelectedValue();
616                         KeyDialog keyDialog = new KeyDialog(freenetInterface, wizard);
617                         keyDialog.setPrivateKey(selectedProject.getInsertURI());
618                         keyDialog.setPublicKey(selectedProject.getRequestURI());
619                         keyDialog.setVisible(true);
620                         if (!keyDialog.wasCancelled()) {
621                                 String originalPublicKey = selectedProject.getRequestURI();
622                                 String originalPrivateKey = selectedProject.getInsertURI();
623                                 selectedProject.setInsertURI(keyDialog.getPrivateKey());
624                                 selectedProject.setRequestURI(keyDialog.getPublicKey());
625                                 if (!originalPublicKey.equals(selectedProject.getRequestURI()) || !originalPrivateKey.equals(selectedProject.getInsertURI())) {
626                                         selectedProject.setEdition(-1);
627                                 }
628                                 updateCompleteURI();
629                         }
630                 }
631         }
632
633         /**
634          * Resets the edition of the currently selected project.
635          */
636         private void actionResetEdition() {
637                 if (JOptionPane.showConfirmDialog(this, I18n.getMessage("jsite.project.warning.reset-edition"), null, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
638                         return;
639                 }
640                 int selectedIndex = projectList.getSelectedIndex();
641                 if (selectedIndex > -1) {
642                         Project selectedProject = (Project) projectList.getSelectedValue();
643                         selectedProject.setEdition(-1);
644                         updateCompleteURI();
645                 }
646         }
647
648         /**
649          * Updates the complete URI text field.
650          */
651         private void updateCompleteURI() {
652                 int selectedIndex = projectList.getSelectedIndex();
653                 if (selectedIndex > -1) {
654                         Project selectedProject = (Project) projectList.getSelectedValue();
655                         projectCompleteUriTextField.setText(selectedProject.getFinalRequestURI(0));
656                 }
657         }
658
659         //
660         // INTERFACE ListSelectionListener
661         //
662
663         /**
664          * {@inheritDoc}
665          */
666         @Override
667         public void valueChanged(ListSelectionEvent listSelectionEvent) {
668                 int selectedRow = projectList.getSelectedIndex();
669                 Project selectedProject = (Project) projectList.getSelectedValue();
670                 projectNameTextField.setEnabled(selectedRow > -1);
671                 projectDescriptionTextField.setEnabled(selectedRow > -1);
672                 projectLocalPathTextField.setEnabled(selectedRow > -1);
673                 projectPathTextField.setEnabled(selectedRow > -1);
674                 projectLocalPathBrowseAction.setEnabled(selectedRow > -1);
675                 projectDeleteAction.setEnabled(selectedRow > -1);
676                 projectCloneAction.setEnabled(selectedRow > -1);
677                 projectCopyURIAction.setEnabled(selectedRow > -1);
678                 projectManageKeysAction.setEnabled(selectedRow > -1);
679                 projectResetEditionAction.setEnabled(selectedRow > -1);
680                 if (selectedRow > -1) {
681                         projectNameTextField.setText(selectedProject.getName());
682                         projectDescriptionTextField.setText(selectedProject.getDescription());
683                         projectLocalPathTextField.setText(selectedProject.getLocalPath());
684                         projectPathTextField.setText(selectedProject.getPath());
685                         projectCompleteUriTextField.setText("freenet:" + selectedProject.getFinalRequestURI(0));
686                 } else {
687                         projectNameTextField.setText("");
688                         projectDescriptionTextField.setText("");
689                         projectLocalPathTextField.setText("");
690                         projectPathTextField.setText("");
691                         projectCompleteUriTextField.setText("");
692                 }
693         }
694
695         //
696         // INTERFACE ChangeListener
697         //
698
699         //
700         // INTERFACE DocumentListener
701         //
702
703         /**
704          * {@inheritDoc}
705          */
706         @Override
707         public void insertUpdate(DocumentEvent documentEvent) {
708                 setTextField(documentEvent);
709         }
710
711         /**
712          * {@inheritDoc}
713          */
714         @Override
715         public void removeUpdate(DocumentEvent documentEvent) {
716                 setTextField(documentEvent);
717         }
718
719         /**
720          * {@inheritDoc}
721          */
722         @Override
723         public void changedUpdate(DocumentEvent documentEvent) {
724                 setTextField(documentEvent);
725         }
726
727         //
728         // INTERFACE ClipboardOwner
729         //
730
731         /**
732          * {@inheritDoc}
733          */
734         @Override
735         public void lostOwnership(Clipboard clipboard, Transferable contents) {
736                 /* ignore. */
737         }
738
739 }