remove subversion $Id$ tags
[jSite.git] / src / de / todesbaum / jsite / main / Main.java
1 /*
2  * jSite - a tool for uploading websites into Freenet
3  * Copyright (C) 2006 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.HashMap;
28 import java.util.Locale;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.Map.Entry;
32
33 import javax.swing.AbstractAction;
34 import javax.swing.Action;
35 import javax.swing.ButtonGroup;
36 import javax.swing.Icon;
37 import javax.swing.JList;
38 import javax.swing.JMenu;
39 import javax.swing.JMenuBar;
40 import javax.swing.JOptionPane;
41 import javax.swing.JPanel;
42 import javax.swing.JRadioButtonMenuItem;
43 import javax.swing.event.ListSelectionEvent;
44 import javax.swing.event.ListSelectionListener;
45
46 import de.todesbaum.jsite.application.FileOption;
47 import de.todesbaum.jsite.application.Freenet7Interface;
48 import de.todesbaum.jsite.application.Node;
49 import de.todesbaum.jsite.application.Project;
50 import de.todesbaum.jsite.gui.NodeManagerListener;
51 import de.todesbaum.jsite.gui.NodeManagerPage;
52 import de.todesbaum.jsite.gui.ProjectFilesPage;
53 import de.todesbaum.jsite.gui.ProjectInsertPage;
54 import de.todesbaum.jsite.gui.ProjectPage;
55 import de.todesbaum.jsite.i18n.I18n;
56 import de.todesbaum.jsite.i18n.I18nContainer;
57 import de.todesbaum.util.image.IconLoader;
58 import de.todesbaum.util.swing.TWizard;
59 import de.todesbaum.util.swing.TWizardPage;
60 import de.todesbaum.util.swing.WizardListener;
61
62 /**
63  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
64  */
65 public class Main implements ActionListener, ListSelectionListener, WizardListener, NodeManagerListener {
66
67         private static boolean debug = false;
68         private Configuration configuration;
69         private Freenet7Interface freenetInterface = new Freenet7Interface();
70         protected Icon jSiteIcon;
71
72         private static enum PageType {
73                 PAGE_NODE_MANAGER, PAGE_PROJECTS, PAGE_PROJECT_FILES, PAGE_INSERT_PROJECT
74         }
75
76         private static final Locale[] SUPPORTED_LOCALES = new Locale[] { Locale.ENGLISH, Locale.GERMAN, Locale.FRENCH, Locale.ITALIAN, new Locale("pl") };
77         protected Map<Locale, Action> languageActions = new HashMap<Locale, Action>();
78         protected Action manageNodeAction;
79         protected Action aboutAction;
80         protected TWizard wizard;
81         protected JMenu nodeMenu;
82         private Node selectedNode;
83         private final Map<PageType, TWizardPage> pages = new HashMap<PageType, TWizardPage>();
84
85         private Main() {
86                 this(null);
87         }
88
89         private Main(String configFilename) {
90                 if (configFilename != null) {
91                         configuration = new Configuration(configFilename);
92                 } else {
93                         configuration = new Configuration();
94                 }
95                 Locale.setDefault(configuration.getLocale());
96                 I18n.setLocale(configuration.getLocale());
97                 if (!configuration.createLockFile()) {
98                         JOptionPane.showMessageDialog(null, I18n.getMessage("jsite.main.already-running"), null, JOptionPane.ERROR_MESSAGE);
99                         return;
100                 }
101                 wizard = new TWizard();
102                 createActions();
103                 wizard.setJMenuBar(createMenuBar());
104                 wizard.setQuitName(I18n.getMessage("jsite.wizard.quit"));
105                 wizard.setPreviousEnabled(false);
106                 wizard.setNextEnabled(true);
107                 wizard.addWizardListener(this);
108                 jSiteIcon = IconLoader.loadIcon("/jsite-icon.png");
109                 wizard.setIcon(jSiteIcon);
110
111                 initPages();
112                 showPage(PageType.PAGE_PROJECTS);
113         }
114
115         private void createActions() {
116                 for (final Locale locale: SUPPORTED_LOCALES) {
117                         languageActions.put(locale, new AbstractAction(I18n.getMessage("jsite.menu.language." + locale.getLanguage()), IconLoader.loadIcon("/flag-" + locale.getLanguage() + ".png")) {
118
119                                 public void actionPerformed(ActionEvent actionEvent) {
120                                         switchLanguage(locale);
121                                 }
122                         });
123                 }
124                 manageNodeAction = new AbstractAction(I18n.getMessage("jsite.menu.nodes.manage-nodes")) {
125                         public void actionPerformed(ActionEvent actionEvent) {
126                                 showPage(PageType.PAGE_NODE_MANAGER);
127                                 wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous"));
128                                 wizard.setNextName(I18n.getMessage("jsite.wizard.next"));
129                         }
130                 };
131                 aboutAction = new AbstractAction(I18n.getMessage("jsite.menu.help.about")) {
132
133                         public void actionPerformed(ActionEvent e) {
134                                 JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.about.message"), Version.getVersion()), null, JOptionPane.INFORMATION_MESSAGE, jSiteIcon);
135                         }
136                 };
137
138                 I18nContainer.getInstance().registerRunnable(new Runnable() {
139                         public void run() {
140                                 manageNodeAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.nodes.manage-nodes"));
141                                 aboutAction.putValue(Action.NAME, I18n.getMessage("jsite.menu.help.about"));
142                         }
143                 });
144         }
145
146         private JMenuBar createMenuBar() {
147                 JMenuBar menuBar = new JMenuBar();
148                 final JMenu languageMenu = new JMenu(I18n.getMessage("jsite.menu.languages"));
149                 menuBar.add(languageMenu);
150                 ButtonGroup languageButtonGroup = new ButtonGroup();
151                 for (Locale locale: SUPPORTED_LOCALES) {
152                         Action languageAction = languageActions.get(locale);
153                         JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(languageActions.get(locale));
154                         if (locale.equals(Locale.getDefault())) {
155                                 menuItem.setSelected(true);
156                         }
157                         languageAction.putValue("menuItem", menuItem);
158                         languageButtonGroup.add(menuItem);
159                         languageMenu.add(menuItem);
160                 }
161                 nodeMenu = new JMenu(I18n.getMessage("jsite.menu.nodes"));
162                 menuBar.add(nodeMenu);
163                 selectedNode = configuration.getSelectedNode();
164                 nodesUpdated(configuration.getNodes());
165
166                 /* evil hack to right-align the help menu */
167                 JPanel panel = new JPanel();
168                 panel.setOpaque(false);
169                 menuBar.add(panel);
170
171                 final JMenu helpMenu = new JMenu(I18n.getMessage("jsite.menu.help"));
172                 menuBar.add(helpMenu);
173                 helpMenu.add(aboutAction);
174
175                 I18nContainer.getInstance().registerRunnable(new Runnable() {
176                         public void run() {
177                                 languageMenu.setText(I18n.getMessage("jsite.menu.languages"));
178                                 nodeMenu.setText(I18n.getMessage("jsite.menu.nodes"));
179                                 helpMenu.setText(I18n.getMessage("jsite.menu.help"));
180                                 for (Map.Entry<Locale, Action> languageActionEntry: languageActions.entrySet()) {
181                                         languageActionEntry.getValue().putValue(Action.NAME, I18n.getMessage("jsite.menu.language." + languageActionEntry.getKey().getLanguage()));
182                                 }
183                         }
184                 });
185
186                 return menuBar;
187         }
188
189         private void initPages() {
190                 NodeManagerPage nodeManagerPage = new NodeManagerPage(wizard);
191                 nodeManagerPage.setName("page.node-manager");
192                 nodeManagerPage.addNodeManagerListener(this);
193                 nodeManagerPage.setNodes(configuration.getNodes());
194                 pages.put(PageType.PAGE_NODE_MANAGER, nodeManagerPage);
195
196                 ProjectPage projectPage = new ProjectPage(wizard);
197                 projectPage.setName("page.project");
198                 projectPage.setProjects(configuration.getProjects());
199                 projectPage.setFreenetInterface(freenetInterface);
200                 projectPage.addListSelectionListener(this);
201                 pages.put(PageType.PAGE_PROJECTS, projectPage);
202
203                 ProjectFilesPage projectFilesPage = new ProjectFilesPage(wizard);
204                 projectFilesPage.setName("page.project.files");
205                 pages.put(PageType.PAGE_PROJECT_FILES, projectFilesPage);
206
207                 ProjectInsertPage projectInsertPage = new ProjectInsertPage(wizard);
208                 projectInsertPage.setDebug(debug);
209                 projectInsertPage.setName("page.project.insert");
210                 projectInsertPage.setFreenetInterface(freenetInterface);
211                 pages.put(PageType.PAGE_INSERT_PROJECT, projectInsertPage);
212         }
213
214         protected void showPage(PageType pageType) {
215                 wizard.setPreviousEnabled(pageType.ordinal() > 0);
216                 wizard.setNextEnabled(pageType.ordinal() < (pages.size() - 1));
217                 wizard.setPage(pages.get(pageType));
218                 wizard.setTitle(pages.get(pageType).getHeading() + " - jSite");
219         }
220
221         private boolean saveConfiguration() {
222                 NodeManagerPage nodeManagerPage = (NodeManagerPage) pages.get(PageType.PAGE_NODE_MANAGER);
223                 configuration.setNodes(nodeManagerPage.getNodes());
224                 if (selectedNode != null) {
225                         configuration.setSelectedNode(selectedNode);
226                 }
227
228                 ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
229                 configuration.setProjects(projectPage.getProjects());
230
231                 return configuration.save();
232         }
233
234         private Locale findSupportedLocale(Locale forLocale) {
235                 for (Locale locale: SUPPORTED_LOCALES) {
236                         if (locale.equals(forLocale)) {
237                                 return locale;
238                         }
239                 }
240                 for (Locale locale: SUPPORTED_LOCALES) {
241                         if (locale.getCountry().equals(forLocale.getCountry()) && locale.getLanguage().equals(forLocale.getLanguage())) {
242                                 return locale;
243                         }
244                 }
245                 for (Locale locale: SUPPORTED_LOCALES) {
246                         if (locale.getLanguage().equals(forLocale.getLanguage())) {
247                                 return locale;
248                         }
249                 }
250                 return SUPPORTED_LOCALES[0];
251         }
252
253         //
254         // ACTIONS
255         //
256
257         protected void switchLanguage(Locale locale) {
258                 Locale supportedLocale = findSupportedLocale(locale);
259                 Action languageAction = languageActions.get(supportedLocale);
260                 JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) languageAction.getValue("menuItem");
261                 menuItem.setSelected(true);
262                 I18n.setLocale(supportedLocale);
263                 for (Runnable i18nRunnable: I18nContainer.getInstance()) {
264                         try {
265                                 i18nRunnable.run();
266                         } catch (Throwable t) {
267                                 /* we probably shouldn't swallow this. */
268                         }
269                 }
270                 wizard.setPage(wizard.getPage());
271                 configuration.setLocale(supportedLocale);
272         }
273
274         //
275         // INTERFACE ListSelectionListener
276         //
277
278         /**
279          * {@inheritDoc}
280          */
281         public void valueChanged(ListSelectionEvent e) {
282                 JList list = (JList) e.getSource();
283                 int selectedRow = list.getSelectedIndex();
284                 wizard.setNextEnabled(selectedRow > -1);
285         }
286
287         //
288         // INTERFACE WizardListener
289         //
290
291         /**
292          * {@inheritDoc}
293          */
294         public void wizardNextPressed(TWizard wizard) {
295                 String pageName = wizard.getPage().getName();
296                 if ("page.node-manager".equals(pageName)) {
297                         showPage(PageType.PAGE_PROJECTS);
298                 } else if ("page.project".equals(pageName)) {
299                         ProjectPage projectPage = (ProjectPage) wizard.getPage();
300                         Project project = projectPage.getSelectedProject();
301                         if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) {
302                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-local-path"), null, JOptionPane.ERROR_MESSAGE);
303                                 return;
304                         }
305                         if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) {
306                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-path"), null, JOptionPane.ERROR_MESSAGE);
307                                 return;
308                         }
309                         ((ProjectFilesPage) pages.get(PageType.PAGE_PROJECT_FILES)).setProject(project);
310                         ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).setProject(project);
311                         showPage(PageType.PAGE_PROJECT_FILES);
312                 } else if ("page.project.files".equals(pageName)) {
313                         ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS);
314                         Project project = projectPage.getSelectedProject();
315                         if (selectedNode == null) {
316                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE);
317                                 return;
318                         }
319                         if (project.getIndexFile() == null) {
320                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.empty-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
321                                         return;
322                                 }
323                         } else {
324                                 File indexFile = new File(project.getLocalPath(), project.getIndexFile());
325                                 if (!indexFile.exists()) {
326                                         JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.index-missing"), null, JOptionPane.ERROR_MESSAGE);
327                                         return;
328                                 }
329                         }
330                         String indexFile = project.getIndexFile();
331                         boolean hasIndexFile = (indexFile != null);
332                         if (hasIndexFile && !project.getFileOption(indexFile).getContainer().equals("")) {
333                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.container-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
334                                         return;
335                                 }
336                         }
337                         if (hasIndexFile && !project.getFileOption(indexFile).getMimeType().equals("text/html")) {
338                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.index-not-html"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
339                                         return;
340                                 }
341                         }
342                         Map<String, FileOption> fileOptions = project.getFileOptions();
343                         Set<Entry<String, FileOption>> fileOptionEntries = fileOptions.entrySet();
344                         for (Entry<String, FileOption> fileOptionEntry: fileOptionEntries) {
345                                 FileOption fileOption = fileOptionEntry.getValue();
346                                 if (!fileOption.isInsert() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) {
347                                         JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.project-files.no-custom-key"), fileOptionEntry.getKey()), null, JOptionPane.ERROR_MESSAGE);
348                                         return;
349                                 }
350                         }
351                         boolean nodeRunning = false;
352                         try {
353                                 nodeRunning = freenetInterface.isNodePresent();
354                         } catch (IOException e) {
355                         }
356                         if (!nodeRunning) {
357                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
358                                 return;
359                         }
360                         configuration.save();
361                         showPage(PageType.PAGE_INSERT_PROJECT);
362                         ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).startInsert();
363                         nodeMenu.setEnabled(false);
364                 } else if ("page.project.insert".equals(pageName)) {
365                         showPage(PageType.PAGE_PROJECTS);
366                         nodeMenu.setEnabled(true);
367                 }
368         }
369
370         /**
371          * {@inheritDoc}
372          */
373         public void wizardPreviousPressed(TWizard wizard) {
374                 String pageName = wizard.getPage().getName();
375                 if ("page.project".equals(pageName)) {
376                         showPage(PageType.PAGE_NODE_MANAGER);
377                 } else if ("page.project.files".equals(pageName)) {
378                         showPage(PageType.PAGE_PROJECTS);
379                 } else if ("page.project.insert".equals(pageName)) {
380                         showPage(PageType.PAGE_PROJECT_FILES);
381                 }
382         }
383
384         /**
385          * {@inheritDoc}
386          */
387         public void wizardQuitPressed(TWizard wizard) {
388                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
389                         if (saveConfiguration()) {
390                                 System.exit(0);
391                         }
392                         if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.config-not-saved"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
393                                 System.exit(0);
394                         }
395                 }
396         }
397
398         //
399         // INTERFACE NodeManagerListener
400         //
401
402         /**
403          * {@inheritDoc}
404          */
405         public void nodesUpdated(Node[] nodes) {
406                 nodeMenu.removeAll();
407                 ButtonGroup nodeButtonGroup = new ButtonGroup();
408                 Node newSelectedNode = null;
409                 for (Node node: nodes) {
410                         JRadioButtonMenuItem nodeMenuItem = new JRadioButtonMenuItem(node.getName());
411                         nodeMenuItem.putClientProperty("Node", node);
412                         nodeMenuItem.addActionListener(this);
413                         nodeButtonGroup.add(nodeMenuItem);
414                         if (node.equals(selectedNode)) {
415                                 newSelectedNode = node;
416                                 nodeMenuItem.setSelected(true);
417                         }
418                         nodeMenu.add(nodeMenuItem);
419                 }
420                 nodeMenu.addSeparator();
421                 nodeMenu.add(manageNodeAction);
422                 selectedNode = newSelectedNode;
423                 freenetInterface.setNode(selectedNode);
424         }
425
426         /**
427          * {@inheritDoc}
428          */
429         public void actionPerformed(ActionEvent e) {
430                 Object source = e.getSource();
431                 if (source instanceof JRadioButtonMenuItem) {
432                         JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) source;
433                         Node node = (Node) menuItem.getClientProperty("Node");
434                         selectedNode = node;
435                         freenetInterface.setNode(selectedNode);
436                 }
437         }
438
439         //
440         // MAIN METHOD
441         //
442         public static void main(String[] args) {
443                 String configFilename = null;
444                 boolean nextIsConfigFilename = false;
445                 for (String argument: args) {
446                         if (nextIsConfigFilename) {
447                                 configFilename = argument;
448                                 nextIsConfigFilename = false;
449                         }
450                         if ("--help".equals(argument)) {
451                                 printHelp();
452                                 return;
453                         } else if ("--debug".equals(argument)) {
454                                 debug = true;
455                         } else if ("--config-file".equals(argument)) {
456                                 nextIsConfigFilename = true;
457                         }
458                 }
459                 if (nextIsConfigFilename) {
460                         System.out.println("--config-file needs parameter!");
461                         return;
462                 }
463                 new Main(configFilename);
464         }
465
466         private static void printHelp() {
467                 System.out.println("--help\tshows this cruft");
468                 System.out.println("--debug\tenables some debug output");
469                 System.out.println("--config-file <file>\tuse specified configuration file");
470         }
471
472 }