6773eee285c8665952dedd57d9699a814cc32f10
[jSite.git] / src / de / todesbaum / jsite / main / Main.java
1 /*
2  * jSite - a tool for uploading websites into Freenet
3  * Copyright (C) 2006-2009 David Roden
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 package de.todesbaum.jsite.main;
21
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.io.File;
25 import java.io.IOException;
26 import java.text.MessageFormat;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.Map.Entry;
33 import java.util.logging.ConsoleHandler;
34 import java.util.logging.Handler;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
37
38 import javax.swing.AbstractAction;
39 import javax.swing.Action;
40 import javax.swing.ButtonGroup;
41 import javax.swing.Icon;
42 import javax.swing.JList;
43 import javax.swing.JMenu;
44 import javax.swing.JMenuBar;
45 import javax.swing.JOptionPane;
46 import javax.swing.JPanel;
47 import javax.swing.JRadioButtonMenuItem;
48 import javax.swing.event.ListSelectionEvent;
49 import javax.swing.event.ListSelectionListener;
50
51 import de.todesbaum.jsite.application.FileOption;
52 import de.todesbaum.jsite.application.Freenet7Interface;
53 import de.todesbaum.jsite.application.Node;
54 import de.todesbaum.jsite.application.Project;
55 import de.todesbaum.jsite.application.UpdateChecker;
56 import de.todesbaum.jsite.application.UpdateListener;
57 import de.todesbaum.jsite.gui.NodeManagerListener;
58 import de.todesbaum.jsite.gui.NodeManagerPage;
59 import de.todesbaum.jsite.gui.ProjectFilesPage;
60 import de.todesbaum.jsite.gui.ProjectInsertPage;
61 import de.todesbaum.jsite.gui.ProjectPage;
62 import de.todesbaum.jsite.i18n.I18n;
63 import de.todesbaum.jsite.i18n.I18nContainer;
64 import de.todesbaum.util.image.IconLoader;
65 import de.todesbaum.util.swing.TWizard;
66 import de.todesbaum.util.swing.TWizardPage;
67 import de.todesbaum.util.swing.WizardListener;
68
69 /**
70  * The main class that ties together everything.
71  *
72  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
73  */
74 public class Main implements ActionListener, ListSelectionListener, WizardListener, NodeManagerListener, UpdateListener {
75
76         /** The version. */
77         private static final Version VERSION = new Version(0, 7, 1);
78
79         /** The configuration. */
80         private Configuration configuration;
81
82         /** The freenet interface. */
83         private Freenet7Interface freenetInterface = new Freenet7Interface();
84
85         /** The update checker. */
86         private final UpdateChecker updateChecker;
87
88         /** The jSite icon. */
89         private Icon jSiteIcon;
90
91         /**
92          * Enumeration for all possible pages.
93          *
94          * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
95          */
96         private static enum PageType {
97
98                 /** The node manager page. */
99                 PAGE_NODE_MANAGER,
100
101                 /** The project page. */
102                 PAGE_PROJECTS,
103
104                 /** The project files page. */
105                 PAGE_PROJECT_FILES,
106
107                 /** The project insert page. */
108                 PAGE_INSERT_PROJECT
109
110         }
111
112         /** The supported locales. */
113         private static final Locale[] SUPPORTED_LOCALES = new Locale[] { Locale.ENGLISH, Locale.GERMAN, Locale.FRENCH, Locale.ITALIAN, new Locale("pl") };
114
115         /** The actions that switch the language. */
116         private Map<Locale, Action> languageActions = new HashMap<Locale, Action>();
117
118         /** The “manage nodes” action. */
119         private Action manageNodeAction;
120
121         /** The “preferences” action. */
122         private Action optionsPreferencesAction;
123
124         /** The “check for updates” action. */
125         private Action checkForUpdatesAction;
126
127         /** The “about jSite” action. */
128         private Action aboutAction;
129
130         /** The wizard. */
131         private TWizard wizard;
132
133         /** The node menu. */
134         private JMenu nodeMenu;
135
136         /** The currently selected node. */
137         private Node selectedNode;
138
139         /** Mapping from page type to page. */
140         private final Map<PageType, TWizardPage> pages = new HashMap<PageType, TWizardPage>();
141
142         /**
143          * Creates a new core with the default configuration file.
144          */
145         private Main() {
146                 this(null);
147         }
148
149         /**
150          * Creates a new core with the given configuration from the given file.
151          *
152          * @param configFilename
153          *            The name of the configuration file
154          */
155         private Main(String configFilename) {
156                 if (configFilename != null) {
157                         configuration = new Configuration(configFilename);
158                 } else {
159                         configuration = new Configuration();
160                 }
161                 Locale.setDefault(configuration.getLocale());
162                 I18n.setLocale(configuration.getLocale());
163                 if (!configuration.createLockFile()) {
164                         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"));
165                         if (option != 0) {
166                                 throw new IllegalStateException("Lockfile override not active, refusing start.");
167                         }
168                         configuration.removeLockfileOnExit();
169                 }
170                 wizard = new TWizard();
171                 createActions();
172                 wizard.setJMenuBar(createMenuBar());
173                 wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
174                 wizard.setPreviousEnabled(false);
175                 wizard.setNextEnabled(true);
176                 wizard.addWizardListener(this);
177                 jSiteIcon = IconLoader.loadIcon("/jsite-icon.png");
178                 wizard.setIcon(jSiteIcon);
179
180                 updateChecker = new UpdateChecker(freenetInterface);
181                 updateChecker.addUpdateListener(this);
182                 updateChecker.start();
183
184                 initPages();
185                 showPage(PageType.PAGE_PROJECTS);
186         }
187
188         /**
189          * Creates all actions.
190          */
191         private void createActions() {
192                 for (final Locale locale : SUPPORTED_LOCALES) {
193                         languageActions.put(locale, new AbstractAction(I18n.getMessage("jsite.menu.language." + locale.getLanguage()), IconLoader.loadIcon("/flag-" + locale.getLanguage() + ".png")) {
194
195                                 @SuppressWarnings("synthetic-access")
196                                 public void actionPerformed(ActionEvent actionEvent) {
197                                         switchLanguage(locale);
198                                 }
199                         });
200                 }
201                 manageNodeAction = new AbstractAction(I18n.getMessage("jsite.menu.nodes.manage-nodes")) {
202
203                         @SuppressWarnings("synthetic-access")
204                         public void actionPerformed(ActionEvent actionEvent) {
205                                 showPage(PageType.PAGE_NODE_MANAGER);
206                                 wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
207                                 wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
208                         }
209                 };
210                 optionsPreferencesAction = new AbstractAction(I18n.getMessage("jsite.menu.options.preferences")) {
211
212                         /**
213                          * {@inheritDoc}
214                          */
215                         @Override
216                         @SuppressWarnings("synthetic-access")
217                         public void actionPerformed(ActionEvent actionEvent) {
218                                 optionsPreferences();
219                         }
220                 };
221                 checkForUpdatesAction = new AbstractAction(I18n.getMessage("jsite.menu.help.check-for-updates")) {
222
223                         /**
224                          * {@inheritDoc}
225                          */
226                         @SuppressWarnings("synthetic-access")
227                         public void actionPerformed(ActionEvent actionEvent) {
228                                 showLatestUpdate();
229                         }
230                 };
231                 aboutAction = new AbstractAction(I18n.getMessage("jsite.menu.help.about")) {
232
233                         @SuppressWarnings("synthetic-access")
234                         public void actionPerformed(ActionEvent e) {
235                                 JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.about.message"), getVersion().toString()), null, JOptionPane.INFORMATION_MESSAGE, jSiteIcon);
236                         }
237                 };
238
239                 I18nContainer.getInstance().registerRunnable(new Runnable() {
240
241                         @SuppressWarnings("synthetic-access")
242                         public void run() {
243                                 manageNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.nodes.manage-nodes"));
244                                 optionsPreferencesAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.options.preferences"));
245                                 checkForUpdatesAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.help.check-for-updates"));
246                                 aboutAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.help.about"));
247                         }
248                 });
249         }
250
251         /**
252          * Creates the menu bar.
253          *
254          * @return The menu bar
255          */
256         private JMenuBar createMenuBar() {
257                 JMenuBar menuBar = new JMenuBar();
258                 final JMenu languageMenu = new JMenu(I18n.getMessage("jsite.menu.languages"));
259                 menuBar.add(languageMenu);
260                 ButtonGroup languageButtonGroup = new ButtonGroup();
261                 for (Locale locale : SUPPORTED_LOCALES) {
262                         Action languageAction = languageActions.get(locale);
263                         JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(languageActions.get(locale));
264                         if (locale.equals(Locale.getDefault())) {
265                                 menuItem.setSelected(true);
266                         }
267                         languageAction.putValue("menuItem", menuItem);
268                         languageButtonGroup.add(menuItem);
269                         languageMenu.add(menuItem);
270                 }
271                 nodeMenu = new JMenu(I18n.getMessage("jsite.menu.nodes"));
272                 menuBar.add(nodeMenu);
273                 selectedNode = configuration.getSelectedNode();
274                 nodesUpdated(configuration.getNodes());
275
276                 final JMenu optionsMenu = new JMenu(I18n.getMessage("jsite.menu.options"));
277                 menuBar.add(optionsMenu);
278                 optionsMenu.add(optionsPreferencesAction);
279
280                 /* evil hack to right-align the help menu */
281                 JPanel panel = new JPanel();
282                 panel.setOpaque(false);
283                 menuBar.add(panel);
284
285                 final JMenu helpMenu = new JMenu(I18n.getMessage("jsite.menu.help"));
286                 menuBar.add(helpMenu);
287                 helpMenu.add(checkForUpdatesAction);
288                 helpMenu.add(aboutAction);
289
290                 I18nContainer.getInstance().registerRunnable(new Runnable() {
291
292                         @SuppressWarnings("synthetic-access")
293                         public void run() {
294                                 languageMenu.setText(I18n.getMessage("jsite.menu.languages"));
295                                 nodeMenu.setText(I18n.getMessage("jsite.menu.nodes"));
296                                 optionsMenu.setText(I18n.getMessage("jsite.menu.options"));
297                                 helpMenu.setText(I18n.getMessage("jsite.menu.help"));
298                                 for (Map.Entry<Locale, Action> languageActionEntry : languageActions.entrySet()) {
299                                         languageActionEntry.getValue().putValue(Action.NAME, I18n.getMessage("jsite.menu.language." + languageActionEntry.getKey().getLanguage()));
300                                 }
301                         }
302                 });
303
304                 return menuBar;
305         }
306
307         /**
308          * Initializes all pages.
309          */
310         private void initPages() {
311                 NodeManagerPage nodeManagerPage = new NodeManagerPage(wizard);
312                 nodeManagerPage.setName("page.node-manager");
313                 nodeManagerPage.addNodeManagerListener(this);
314                 nodeManagerPage.setNodes(configuration.getNodes());
315                 pages.put(PageType.PAGE_NODE_MANAGER, nodeManagerPage);
316
317                 ProjectPage projectPage = new ProjectPage(wizard);
318                 projectPage.setName("page.project");
319                 projectPage.setProjects(configuration.getProjects());
320                 projectPage.setFreenetInterface(freenetInterface);
321                 projectPage.addListSelectionListener(this);
322                 pages.put(PageType.PAGE_PROJECTS, projectPage);
323
324                 ProjectFilesPage projectFilesPage = new ProjectFilesPage(wizard);
325                 projectFilesPage.setName("page.project.files");
326                 pages.put(PageType.PAGE_PROJECT_FILES, projectFilesPage);
327
328                 ProjectInsertPage projectInsertPage = new ProjectInsertPage(wizard);
329                 projectInsertPage.setName("page.project.insert");
330                 projectInsertPage.setFreenetInterface(freenetInterface);
331                 pages.put(PageType.PAGE_INSERT_PROJECT, projectInsertPage);
332         }
333
334         /**
335          * Shows the page with the given type.
336          *
337          * @param pageType
338          *            The page type to show
339          */
340         private void showPage(PageType pageType) {
341                 wizard.setPreviousEnabled(pageType.ordinal() > 0);
342                 wizard.setNextEnabled(pageType.ordinal() < (pages.size() - 1));
343                 wizard.setPage(pages.get(pageType));
344                 wizard.setTitle(pages.get(pageType).getHeading() + " - jSite");
345         }
346
347         /**
348          * Saves the configuration.
349          *
350          * @return <code>true</code> if the configuration could be saved,
351          *         <code>false</code> otherwise
352          */
353         private boolean saveConfiguration() {
354                 NodeManagerPage nodeManagerPage = (NodeManagerPage) pages.get(PageType.PAGE_NODE_MANAGER);
355                 configuration.setNodes(nodeManagerPage.getNodes());
356                 if (selectedNode != null) {
357                         configuration.setSelectedNode(selectedNode);
358                 }
359
360                 ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
361                 configuration.setProjects(projectPage.getProjects());
362
363                 return configuration.save();
364         }
365
366         /**
367          * Finds a supported locale for the given locale.
368          *
369          * @param forLocale
370          *            The locale to find a supported locale for
371          * @return The supported locale that was found, or the default locale if no
372          *         supported locale could be found
373          */
374         private Locale findSupportedLocale(Locale forLocale) {
375                 for (Locale locale : SUPPORTED_LOCALES) {
376                         if (locale.equals(forLocale)) {
377                                 return locale;
378                         }
379                 }
380                 for (Locale locale : SUPPORTED_LOCALES) {
381                         if (locale.getCountry().equals(forLocale.getCountry()) && locale.getLanguage().equals(forLocale.getLanguage())) {
382                                 return locale;
383                         }
384                 }
385                 for (Locale locale : SUPPORTED_LOCALES) {
386                         if (locale.getLanguage().equals(forLocale.getLanguage())) {
387                                 return locale;
388                         }
389                 }
390                 return SUPPORTED_LOCALES[0];
391         }
392
393         /**
394          * Returns the version.
395          *
396          * @return The version
397          */
398         public static final Version getVersion() {
399                 return VERSION;
400         }
401
402         //
403         // ACTIONS
404         //
405
406         /**
407          * Switches the language of the interface to the given locale.
408          *
409          * @param locale
410          *            The locale to switch to
411          */
412         private void switchLanguage(Locale locale) {
413                 Locale supportedLocale = findSupportedLocale(locale);
414                 Action languageAction = languageActions.get(supportedLocale);
415                 JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) languageAction.getValue("menuItem");
416                 menuItem.setSelected(true);
417                 I18n.setLocale(supportedLocale);
418                 for (Runnable i18nRunnable : I18nContainer.getInstance()) {
419                         try {
420                                 i18nRunnable.run();
421                         } catch (Throwable t) {
422                                 /* we probably shouldn't swallow this. */
423                         }
424                 }
425                 wizard.setPage(wizard.getPage());
426                 configuration.setLocale(supportedLocale);
427         }
428
429         /**
430          * Shows a dialog with general preferences.
431          */
432         private void optionsPreferences() {
433
434         }
435
436         /**
437          * Shows a dialog box that shows the last version that was found by the
438          * {@link UpdateChecker}.
439          */
440         private void showLatestUpdate() {
441                 Version latestVersion = updateChecker.getLatestVersion();
442                 int versionDifference = latestVersion.compareTo(VERSION);
443                 if (versionDifference > 0) {
444                         JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.newer.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
445                 } else if (versionDifference < 0) {
446                         JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.older.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
447                 } else {
448                         JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.latest-version.okay.message"), VERSION, latestVersion), I18n.getMessage("jsite.update-checker.latest-version.title"), JOptionPane.INFORMATION_MESSAGE);
449                 }
450         }
451
452         //
453         // INTERFACE ListSelectionListener
454         //
455
456         /**
457          * {@inheritDoc}
458          */
459         public void valueChanged(ListSelectionEvent e) {
460                 JList list = (JList) e.getSource();
461                 int selectedRow = list.getSelectedIndex();
462                 wizard.setNextEnabled(selectedRow > -1);
463         }
464
465         //
466         // INTERFACE WizardListener
467         //
468
469         /**
470          * {@inheritDoc}
471          */
472         public void wizardNextPressed(TWizard wizard) {
473                 String pageName = wizard.getPage().getName();
474                 if ("page.node-manager".equals(pageName)) {
475                         showPage(PageType.PAGE_PROJECTS);
476                 } else if ("page.project".equals(pageName)) {
477                         ProjectPage projectPage = (ProjectPage) wizard.getPage();
478                         Project project = projectPage.getSelectedProject();
479                         if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) {
480                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-local-path"), null, JOptionPane.ERROR_MESSAGE);
481                                 return;
482                         }
483                         if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) {
484                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-path"), null, JOptionPane.ERROR_MESSAGE);
485                                 return;
486                         }
487                         ((ProjectFilesPage) pages.get(PageType.PAGE_PROJECT_FILES)).setProject(project);
488                         ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).setProject(project);
489                         showPage(PageType.PAGE_PROJECT_FILES);
490                 } else if ("page.project.files".equals(pageName)) {
491                         ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
492                         Project project = projectPage.getSelectedProject();
493                         if (selectedNode == null) {
494                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
495                                 return;
496                         }
497                         if ((project.getIndexFile() == null) || (project.getIndexFile().length() == 0)) {
498                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.empty-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
499                                         return;
500                                 }
501                         } else {
502                                 File indexFile = new File(project.getLocalPath(), project.getIndexFile());
503                                 if (!indexFile.exists()) {
504                                         JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.index-missing"), null, JOptionPane.ERROR_MESSAGE);
505                                         return;
506                                 }
507                         }
508                         String indexFile = project.getIndexFile();
509                         boolean hasIndexFile = (indexFile != null);
510                         if (hasIndexFile && !project.getFileOption(indexFile).getContainer().equals("")) {
511                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.container-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
512                                         return;
513                                 }
514                         }
515                         if (hasIndexFile && !project.getFileOption(indexFile).getMimeType().equals("text/html")) {
516                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.index-not-html"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
517                                         return;
518                                 }
519                         }
520                         Map<String, FileOption> fileOptions = project.getFileOptions();
521                         Set<Entry<String, FileOption>> fileOptionEntries = fileOptions.entrySet();
522                         for (Entry<String, FileOption> fileOptionEntry : fileOptionEntries) {
523                                 FileOption fileOption = fileOptionEntry.getValue();
524                                 if (!fileOption.isInsert() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) {
525                                         JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.project-files.no-custom-key"), fileOptionEntry.getKey()), null, JOptionPane.ERROR_MESSAGE);
526                                         return;
527                                 }
528                         }
529                         boolean nodeRunning = false;
530                         try {
531                                 nodeRunning = freenetInterface.isNodePresent();
532                         } catch (IOException e) {
533                                 /* ignore. */
534                         }
535                         if (!nodeRunning) {
536                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
537                                 return;
538                         }
539                         configuration.save();
540                         showPage(PageType.PAGE_INSERT_PROJECT);
541                         ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).startInsert();
542                         nodeMenu.setEnabled(false);
543                 } else if ("page.project.insert".equals(pageName)) {
544                         showPage(PageType.PAGE_PROJECTS);
545                         nodeMenu.setEnabled(true);
546                 }
547         }
548
549         /**
550          * {@inheritDoc}
551          */
552         public void wizardPreviousPressed(TWizard wizard) {
553                 String pageName = wizard.getPage().getName();
554                 if ("page.project".equals(pageName)) {
555                         showPage(PageType.PAGE_NODE_MANAGER);
556                 } else if ("page.project.files".equals(pageName)) {
557                         showPage(PageType.PAGE_PROJECTS);
558                 } else if ("page.project.insert".equals(pageName)) {
559                         showPage(PageType.PAGE_PROJECT_FILES);
560                 }
561         }
562
563         /**
564          * {@inheritDoc}
565          */
566         public void wizardQuitPressed(TWizard wizard) {
567                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
568                         if (saveConfiguration()) {
569                                 System.exit(0);
570                         }
571                         if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.config-not-saved"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
572                                 System.exit(0);
573                         }
574                 }
575         }
576
577         //
578         // INTERFACE NodeManagerListener
579         //
580
581         /**
582          * {@inheritDoc}
583          */
584         public void nodesUpdated(Node[] nodes) {
585                 nodeMenu.removeAll();
586                 ButtonGroup nodeButtonGroup = new ButtonGroup();
587                 Node newSelectedNode = null;
588                 for (Node node : nodes) {
589                         JRadioButtonMenuItem nodeMenuItem = new JRadioButtonMenuItem(node.getName());
590                         nodeMenuItem.putClientProperty("Node", node);
591                         nodeMenuItem.addActionListener(this);
592                         nodeButtonGroup.add(nodeMenuItem);
593                         if (node.equals(selectedNode)) {
594                                 newSelectedNode = node;
595                                 nodeMenuItem.setSelected(true);
596                         }
597                         nodeMenu.add(nodeMenuItem);
598                 }
599                 nodeMenu.addSeparator();
600                 nodeMenu.add(manageNodeAction);
601                 selectedNode = newSelectedNode;
602                 freenetInterface.setNode(selectedNode);
603         }
604
605         /**
606          * {@inheritDoc}
607          */
608         public void actionPerformed(ActionEvent e) {
609                 Object source = e.getSource();
610                 if (source instanceof JRadioButtonMenuItem) {
611                         JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) source;
612                         Node node = (Node) menuItem.getClientProperty("Node");
613                         selectedNode = node;
614                         freenetInterface.setNode(selectedNode);
615                 }
616         }
617
618         //
619         // INTERFACE UpdateListener
620         //
621
622         /**
623          * {@inheritDoc}
624          */
625         public void foundUpdateData(Version foundVersion, long versionTimestamp) {
626                 if (foundVersion.compareTo(VERSION) > 0) {
627                         JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.update-checker.found-version.message"), foundVersion.toString(), new Date(versionTimestamp)), I18n.getMessage("jsite.update-checker.found-version.title"), JOptionPane.INFORMATION_MESSAGE);
628                 }
629         }
630
631         //
632         // MAIN METHOD
633         //
634
635         /**
636          * Main method that is called by the VM.
637          *
638          * @param args
639          *            The command-line arguments
640          */
641         public static void main(String[] args) {
642                 /* initialize logger. */
643                 Logger logger = Logger.getLogger("de.todesbaum");
644                 Handler handler = new ConsoleHandler();
645                 logger.addHandler(handler);
646                 String configFilename = null;
647                 boolean nextIsConfigFilename = false;
648                 for (String argument : args) {
649                         if (nextIsConfigFilename) {
650                                 configFilename = argument;
651                                 nextIsConfigFilename = false;
652                         }
653                         if ("--help".equals(argument)) {
654                                 printHelp();
655                                 return;
656                         } else if ("--debug".equals(argument)) {
657                                 logger.setLevel(Level.ALL);
658                                 handler.setLevel(Level.ALL);
659                         } else if ("--config-file".equals(argument)) {
660                                 nextIsConfigFilename = true;
661                         }
662                 }
663                 if (nextIsConfigFilename) {
664                         System.out.println("--config-file needs parameter!");
665                         return;
666                 }
667                 new Main(configFilename);
668         }
669
670         /**
671          * Prints a small syntax help.
672          */
673         private static void printHelp() {
674                 System.out.println("--help\tshows this cruft");
675                 System.out.println("--debug\tenables some debug output");
676                 System.out.println("--config-file <file>\tuse specified configuration file");
677         }
678
679 }