version 0.4.9.3:
[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.IOException;
25 import java.text.MessageFormat;
26 import java.util.HashMap;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.Map.Entry;
31
32 import javax.swing.AbstractAction;
33 import javax.swing.Action;
34 import javax.swing.ButtonGroup;
35 import javax.swing.Icon;
36 import javax.swing.JList;
37 import javax.swing.JMenu;
38 import javax.swing.JMenuBar;
39 import javax.swing.JOptionPane;
40 import javax.swing.JPanel;
41 import javax.swing.JRadioButtonMenuItem;
42 import javax.swing.event.ListSelectionEvent;
43 import javax.swing.event.ListSelectionListener;
44
45 import de.todesbaum.jsite.application.FileOption;
46 import de.todesbaum.jsite.application.Freenet7Interface;
47 import de.todesbaum.jsite.application.Node;
48 import de.todesbaum.jsite.application.Project;
49 import de.todesbaum.jsite.gui.NodeManagerListener;
50 import de.todesbaum.jsite.gui.NodeManagerPage;
51 import de.todesbaum.jsite.gui.ProjectFilesPage;
52 import de.todesbaum.jsite.gui.ProjectInsertPage;
53 import de.todesbaum.jsite.gui.ProjectPage;
54 import de.todesbaum.jsite.i18n.I18n;
55 import de.todesbaum.jsite.i18n.I18nContainer;
56 import de.todesbaum.util.image.IconLoader;
57 import de.todesbaum.util.swing.TWizard;
58 import de.todesbaum.util.swing.TWizardPage;
59 import de.todesbaum.util.swing.WizardListener;
60
61 /**
62  * @author <a href="mailto:droden@gmail.com">David Roden </a>
63  * @version $Id$
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 };
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())) {
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                         }
324                         if (!project.getFileOption(project.getIndexFile()).getContainer().equals("")) {
325                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.container-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
326                                         return;
327                                 }
328                         }
329                         if (!project.getFileOption(project.getIndexFile()).getMimeType().equals("text/html")) {
330                                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.index-not-html"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
331                                         return;
332                                 }
333                         }
334                         Map<String, FileOption> fileOptions = project.getFileOptions();
335                         Set<Entry<String, FileOption>> fileOptionEntries = fileOptions.entrySet();
336                         for (Entry<String, FileOption> fileOptionEntry: fileOptionEntries) {
337                                 FileOption fileOption = fileOptionEntry.getValue();
338                                 if (!fileOption.isInsert() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) {
339                                         JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.project-files.no-custom-key"), fileOptionEntry.getKey()), null, JOptionPane.ERROR_MESSAGE);
340                                         return;
341                                 }
342                         }
343                         boolean nodeRunning = false;
344                         try {
345                                 nodeRunning = freenetInterface.isNodePresent();
346                         } catch (IOException e) {
347                         }
348                         if (!nodeRunning) {
349                                 JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-running"), null, JOptionPane.ERROR_MESSAGE);
350                                 return;
351                         }
352                         configuration.save();
353                         showPage(PageType.PAGE_INSERT_PROJECT);
354                         ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).startInsert();
355                         nodeMenu.setEnabled(false);
356                 } else if ("page.project.insert".equals(pageName)) {
357                         showPage(PageType.PAGE_PROJECTS);
358                         nodeMenu.setEnabled(true);
359                 }
360         }
361
362         /**
363          * {@inheritDoc}
364          */
365         public void wizardPreviousPressed(TWizard wizard) {
366                 String pageName = wizard.getPage().getName();
367                 if ("page.project".equals(pageName)) {
368                         showPage(PageType.PAGE_NODE_MANAGER);
369                 } else if ("page.project.files".equals(pageName)) {
370                         showPage(PageType.PAGE_PROJECTS);
371                 } else if ("page.project.insert".equals(pageName)) {
372                         showPage(PageType.PAGE_PROJECT_FILES);
373                 }
374         }
375
376         /**
377          * {@inheritDoc}
378          */
379         public void wizardQuitPressed(TWizard wizard) {
380                 if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
381                         if (saveConfiguration()) {
382                                 System.exit(0);
383                         }
384                         if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.config-not-saved"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
385                                 System.exit(0);
386                         }
387                 }
388         }
389
390         //
391         // INTERFACE NodeManagerListener
392         //
393
394         /**
395          * {@inheritDoc}
396          */
397         public void nodesUpdated(Node[] nodes) {
398                 nodeMenu.removeAll();
399                 ButtonGroup nodeButtonGroup = new ButtonGroup();
400                 Node newSelectedNode = null;
401                 for (Node node: nodes) {
402                         JRadioButtonMenuItem nodeMenuItem = new JRadioButtonMenuItem(node.getName());
403                         nodeMenuItem.putClientProperty("Node", node);
404                         nodeMenuItem.addActionListener(this);
405                         nodeButtonGroup.add(nodeMenuItem);
406                         if (node.equals(selectedNode)) {
407                                 newSelectedNode = node;
408                                 nodeMenuItem.setSelected(true);
409                         }
410                         nodeMenu.add(nodeMenuItem);
411                 }
412                 nodeMenu.addSeparator();
413                 nodeMenu.add(manageNodeAction);
414                 selectedNode = newSelectedNode;
415                 freenetInterface.setNode(selectedNode);
416         }
417
418         /**
419          * {@inheritDoc}
420          */
421         public void actionPerformed(ActionEvent e) {
422                 Object source = e.getSource();
423                 if (source instanceof JRadioButtonMenuItem) {
424                         JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) source;
425                         Node node = (Node) menuItem.getClientProperty("Node");
426                         selectedNode = node;
427                         freenetInterface.setNode(selectedNode);
428                 }
429         }
430
431         //
432         // MAIN METHOD
433         //
434         public static void main(String[] args) {
435                 String configFilename = null;
436                 boolean nextIsConfigFilename = false;
437                 for (String argument: args) {
438                         if (nextIsConfigFilename) {
439                                 configFilename = argument;
440                                 nextIsConfigFilename = false;
441                         }
442                         if ("--help".equals(argument)) {
443                                 printHelp();
444                                 return;
445                         } else if ("--debug".equals(argument)) {
446                                 debug = true;
447                         } else if ("--config-file".equals(argument)) {
448                                 nextIsConfigFilename = true;
449                         }
450                 }
451                 if (nextIsConfigFilename) {
452                         System.out.println("--config-file needs parameter!");
453                         return;
454                 }
455                 new Main(configFilename);
456         }
457
458         private static void printHelp() {
459                 System.out.println("--help\tshows this cruft");
460                 System.out.println("--debug\tenables some debug output");
461                 System.out.println("--config-file <file>\tuse specified configuration file");
462         }
463         
464 }