1
22 package org.crosswire.bibledesktop.desktop;
23
24 import java.awt.BorderLayout;
25 import java.awt.Component;
26 import java.awt.Container;
27 import java.awt.event.ActionEvent;
28 import java.awt.event.WindowAdapter;
29 import java.awt.event.WindowEvent;
30 import java.beans.PropertyChangeEvent;
31 import java.beans.PropertyChangeListener;
32 import java.beans.PropertyChangeSupport;
33 import java.io.IOException;
34 import java.io.ObjectInputStream;
35 import java.net.MalformedURLException;
36 import java.net.URI;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.Map;
40 import java.util.ResourceBundle;
41 import java.util.Set;
42
43 import javax.swing.BorderFactory;
44 import javax.swing.ButtonGroup;
45 import javax.swing.ImageIcon;
46 import javax.swing.JCheckBoxMenuItem;
47 import javax.swing.JComponent;
48 import javax.swing.JFrame;
49 import javax.swing.JMenu;
50 import javax.swing.JMenuBar;
51 import javax.swing.JOptionPane;
52 import javax.swing.JPanel;
53 import javax.swing.JPopupMenu;
54 import javax.swing.JRadioButtonMenuItem;
55 import javax.swing.JSplitPane;
56 import javax.swing.SwingUtilities;
57 import javax.swing.WindowConstants;
58 import javax.swing.event.SwingPropertyChangeSupport;
59
60 import org.crosswire.bibledesktop.BDMsg;
61 import org.crosswire.bibledesktop.book.BibleViewPane;
62 import org.crosswire.bibledesktop.book.DisplaySelectEvent;
63 import org.crosswire.bibledesktop.book.DisplaySelectListener;
64 import org.crosswire.bibledesktop.book.DisplaySelectPane;
65 import org.crosswire.bibledesktop.book.MultiBookPane;
66 import org.crosswire.bibledesktop.display.BookDataDisplay;
67 import org.crosswire.bibledesktop.display.URIEvent;
68 import org.crosswire.bibledesktop.display.URIEventListener;
69 import org.crosswire.bibledesktop.display.basic.SplitBookDataDisplay;
70 import org.crosswire.bibledesktop.util.ConfigurableSwingConverter;
71 import org.crosswire.common.config.ChoiceFactory;
72 import org.crosswire.common.config.Config;
73 import org.crosswire.common.history.History;
74 import org.crosswire.common.progress.JobManager;
75 import org.crosswire.common.progress.Progress;
76 import org.crosswire.common.swing.ActionFactory;
77 import org.crosswire.common.swing.CWAction;
78 import org.crosswire.common.swing.CWOptionPane;
79 import org.crosswire.common.swing.CatchingThreadGroup;
80 import org.crosswire.common.swing.ExceptionPane;
81 import org.crosswire.common.swing.FixedSplitPane;
82 import org.crosswire.common.swing.GuiUtil;
83 import org.crosswire.common.swing.LookAndFeelUtil;
84 import org.crosswire.common.swing.desktop.LayoutPersistence;
85 import org.crosswire.common.swing.desktop.LayoutType;
86 import org.crosswire.common.swing.desktop.TDIViewLayout;
87 import org.crosswire.common.swing.desktop.ToolBar;
88 import org.crosswire.common.swing.desktop.ViewGenerator;
89 import org.crosswire.common.swing.desktop.ViewManager;
90 import org.crosswire.common.swing.desktop.event.ViewEvent;
91 import org.crosswire.common.swing.desktop.event.ViewEventListener;
92 import org.crosswire.common.util.CWClassLoader;
93 import org.crosswire.common.util.CWProject;
94 import org.crosswire.common.util.FileUtil;
95 import org.crosswire.common.util.Logger;
96 import org.crosswire.common.util.OSType;
97 import org.crosswire.common.util.Reporter;
98 import org.crosswire.common.util.ResourceUtil;
99 import org.crosswire.common.util.Translations;
100 import org.crosswire.common.xml.Converter;
101 import org.crosswire.common.xml.XMLUtil;
102 import org.crosswire.jsword.book.Book;
103 import org.crosswire.jsword.book.BookFilters;
104 import org.crosswire.jsword.book.Books;
105 import org.crosswire.jsword.book.BooksEvent;
106 import org.crosswire.jsword.book.BooksListener;
107 import org.crosswire.jsword.book.Defaults;
108 import org.crosswire.jsword.passage.Key;
109 import org.crosswire.jsword.passage.NoSuchKeyException;
110 import org.crosswire.jsword.util.ConverterFactory;
111 import org.jdom.Document;
112 import org.jdom.JDOMException;
113
114
123 public class Desktop extends JFrame implements URIEventListener, ViewEventListener, DisplaySelectListener, ViewGenerator {
124 private static final CWProject PROJECT = CWProject.instance();
129
130 static {
131 CWProject.setHome("jsword.home", ".jsword", "JSword");
132 }
133
134
140 public static void main(String[] args) {
141 try {
142 ThreadGroup group = new CatchingThreadGroup("BibleDesktopUIGroup");
143 Thread t = new DesktopThread(group);
144 t.start();
145 } catch (Exception ex) {
146 ex.printStackTrace(System.err);
149 ExceptionPane.showExceptionDialog(null, ex);
150 }
151 }
152
153
156 public Desktop() {
157 setName("Desktop");
159
160 Translations.instance().setLocale();
162
163 URI predictURI = PROJECT.getWritableURI(SPLASH_PROPS, FileUtil.EXTENSION_PROPERTIES);
164 Progress startJob = JobManager.createJob("Startup");
165 startJob.beginJob(BDMsg.gettext("Startup"), predictURI);
167
168 generateConfig();
173
174 JOptionPane.setRootFrame(this);
176
177 Reporter.grabAWTExecptions(true);
179
180 desktopActions = new DesktopActions(this);
182 actions = desktopActions.getActions();
183
184 startJob.setSectionName(BDMsg.gettext("Generating Components"));
187 buildActionMap();
188 createComponents();
189
190 debug();
192
193 startJob.setSectionName(BDMsg.gettext("General configuration"));
197 createLayout();
198
199 BooksListener cbl = new BooksListener() {
201 public void bookAdded(BooksEvent ev) {
202 generateConfig();
203 }
204
205 public void bookRemoved(BooksEvent ev) {
206 generateConfig();
207 }
208 };
209 Books.installed().addBooksListener(cbl);
210
211 GuiUtil.applyDefaultOrientation(this);
214
215 startJob.done();
216 }
217
218
221 private void debug() {
222
225 }
228
229
232 private void createComponents() {
233 barStatus = new StatusBar();
234 reference = new MultiBookPane();
235 sptBooks = new FixedSplitPane(false);
236
237 changeSupport = new SwingPropertyChangeSupport(this);
238 views = new ViewManager(this);
239 views.setActionFactory(getViewActions(views));
240 views.addViewEventListener(this);
241 history = new History();
242 }
243
244 private ActionFactory getViewActions(ViewManager viewMgr) {
245 ActionFactory viewActions = new ActionFactory(viewMgr);
246
247 CWAction cwAction = viewActions.addAction(ViewManager.TAB_MODE, BDMsg.gettext("Tabbed Mode"));
249 cwAction.setTooltip(BDMsg.gettext("View passages using tabs"));
251
252 cwAction = viewActions.addAction(ViewManager.WINDOW_MODE, BDMsg.gettext("Sub-Window Mode"));
254 cwAction.setTooltip(BDMsg.gettext("View passages using sub-windows"));
256
257 cwAction = viewActions.addAction(ViewManager.NEW_TAB, BDMsg.gettext("New Bible View"));
259 cwAction.setTooltip(BDMsg.gettext("Open a new Bible View"));
261 cwAction.setSmallIcon("toolbarButtonGraphics/general/New16.gif");
262 cwAction.setLargeIcon("toolbarButtonGraphics/general/New24.gif");
263 cwAction.setAccelerator("N,ctrl");
264
265 cwAction = viewActions.addAction(ViewManager.CLOSE_VIEW, BDMsg.gettext("Close the Current View"));
267 cwAction.setAccelerator("0x73,ctrl");
268
269 cwAction = viewActions.addAction(ViewManager.CLEAR_VIEW, BDMsg.gettext("Clear the Current View"));
271 cwAction.setTooltip(BDMsg.gettext("Clear the current view's passages"));
272
273 cwAction = viewActions.addAction(ViewManager.CLOSE_ALL_VIEWS, BDMsg.gettext("Close All Views"));
275 cwAction.setTooltip(BDMsg.gettext("Close all passages"));
276
277 cwAction = viewActions.addAction(ViewManager.CLOSE_OTHER_VIEWS, BDMsg.gettext("Close Other Views"));
279 cwAction.setTooltip(BDMsg.gettext("Close all the other passages."));
281 return viewActions;
282 }
283
284
287 private void createLayout() {
288 addWindowListener(new WindowAdapter() {
289
292 @Override
293 public void windowClosed(WindowEvent ev) {
294 actions.findAction("Exit").actionPerformed(new ActionEvent(this, 0, EMPTY_STRING));
295 }
296 });
297
298 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
299
300 TDIViewLayout tdi = (TDIViewLayout) LayoutType.TDI.getLayout();
301 tdi.addPopup(createPopupMenu());
302
303 reference.addURIEventListener(this);
304
305 sptBooks.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
306 sptBooks.setRightComponent(reference);
307 sptBooks.setLeftComponent(views.getDesktop());
308 sptBooks.setResizeWeight(0.8D);
309 sptBooks.setOpaque(true);
310 sptBooks.setBorder(null);
311
312 Container contentPane = getContentPane();
315 contentPane.setLayout(new BorderLayout());
316 ToolBar toolbar = createToolBar();
317 contentPane.add(toolbar, BorderLayout.NORTH);
318
319 mainPanel = new JPanel(new BorderLayout());
320 mainPanel.setBorder(BorderFactory.createEmptyBorder(1, 5, 1, 5));
321 mainPanel.add(sptBooks, BorderLayout.CENTER);
322
323 corePanel = new JPanel(new BorderLayout());
325 corePanel.add(mainPanel, BorderLayout.CENTER);
326 corePanel.add(barStatus, BorderLayout.SOUTH);
327 contentPane.add(corePanel, BorderLayout.CENTER);
328 setJMenuBar(createMenuBar(toolbar));
329
330 setIconImage(ICON_APP.getImage());
331 setEnabled(true);
332 setTitle(BDMsg.getApplicationTitle());
333 }
334
335 private JMenuBar createMenuBar(ToolBar toolbar) {
336 JMenuBar barMenu = new JMenuBar();
337 barMenu.add(createFileMenu());
338 barMenu.add(createEditMenu());
339 barMenu.add(createViewMenu(toolbar));
340 barMenu.add(createNavigateMenu());
341 barMenu.add(createToolsMenu());
342 barMenu.add(createHelpMenu());
343 return barMenu;
344 }
345
346 private void buildActionMap() {
347 CWAction cwAction = actions.addAction("File", BDMsg.gettext("File"));
350
351 cwAction = actions.addAction("Open", BDMsg.gettext("Open"));
353 cwAction.setTooltip(BDMsg.gettext("Open a saved passage."));
355 cwAction.setSmallIcon("toolbarButtonGraphics/general/Open16.gif");
356 cwAction.setLargeIcon("toolbarButtonGraphics/general/Open24.gif");
357 cwAction.setAccelerator("O,ctrl");
358
359 cwAction = actions.addAction("Save", BDMsg.gettext("Save"));
361 cwAction.setTooltip(BDMsg.gettext("Save the current passage."));
363 cwAction.setSmallIcon("toolbarButtonGraphics/general/Save16.gif");
364 cwAction.setLargeIcon("toolbarButtonGraphics/general/Save24.gif");
365 cwAction.setAccelerator("S,ctrl");
366
367 cwAction = actions.addAction("SaveAs", BDMsg.gettext("Save As"));
369 cwAction.setTooltip(BDMsg.gettext("Save the current passage under a different name."));
371 cwAction.setSmallIcon("toolbarButtonGraphics/general/SaveAs16.gif");
372 cwAction.setLargeIcon("toolbarButtonGraphics/general/SaveAs24.gif");
373 cwAction.setAccelerator("A,ctrl,shift");
374
375 cwAction = actions.addAction("SaveAll", BDMsg.gettext("Save All"));
377 cwAction.setTooltip(BDMsg.gettext("Save all passages."));
379 cwAction.setSmallIcon("toolbarButtonGraphics/general/SaveAll16.gif");
380 cwAction.setLargeIcon("toolbarButtonGraphics/general/SaveAll24.gif");
381 cwAction.setAccelerator("S,ctrl,shift");
382
383 cwAction = actions.addAction("Exit", BDMsg.gettext("Exit"));
385 cwAction.setTooltip(BDMsg.gettext("Exit the Desktop application."));
387 cwAction.setAccelerator("0x73,alt");
388
389 cwAction = actions.addAction("Edit", BDMsg.gettext("Edit"));
392
393
401 cwAction = actions.addAction("Copy", BDMsg.gettext("Copy"));
403 cwAction.setTooltip(BDMsg.gettext("Copy the selection."));
405 cwAction.setSmallIcon("toolbarButtonGraphics/general/Copy16.gif");
406 cwAction.setLargeIcon("toolbarButtonGraphics/general/Copy24.gif");
407 cwAction.setAccelerator("C,ctrl");
408
409
417 cwAction = actions.addAction("Navigate", BDMsg.gettext("Navigate"));
420
421 cwAction = actions.addAction("Back", BDMsg.gettext("Back"));
423 cwAction.setTooltip(BDMsg.gettext("Go back to previous passage."));
425 cwAction.setSmallIcon("toolbarButtonGraphics/navigation/Back16.gif");
426 cwAction.setLargeIcon("toolbarButtonGraphics/navigation/Back24.gif");
427
428 cwAction = actions.addAction("Forward", BDMsg.gettext("Forward"));
430 cwAction.setTooltip(BDMsg.gettext("Go forward to next passage."));
432 cwAction.setSmallIcon("toolbarButtonGraphics/navigation/Forward16.gif");
433 cwAction.setLargeIcon("toolbarButtonGraphics/navigation/Forward24.gif");
434
435 cwAction = actions.addAction("Verse", BDMsg.gettext("Verse Numbers"));
438 cwAction.setTooltip(BDMsg.gettext("Set the style for verse numbers"));
440 cwAction = actions.addAction(XSLTProperty.VERSE_NUMBERS.getName(), BDMsg.gettext("Show Verse Numbers"));
442 cwAction = actions.addAction(XSLTProperty.CV.getName(), BDMsg.gettext("Show Chapter and Verse Numbers"));
444 cwAction = actions.addAction(XSLTProperty.BCV.getName(), BDMsg.gettext("Show Book, Chapter and Verse Numbers"));
446 cwAction = actions.addAction(XSLTProperty.NO_VERSE_NUMBERS.getName(), BDMsg.gettext("Hide Verse Numbers"));
448
449 cwAction = actions.addAction("View", BDMsg.gettext("View"));
452 cwAction = actions.addAction(XSLTProperty.TINY_VERSE_NUMBERS.getName(), BDMsg.gettext("Use Small Verse Numbers"));
454
455 cwAction = actions.addAction(XSLTProperty.START_VERSE_ON_NEWLINE.getName(), BDMsg.gettext("Start Verses on Separate Lines"));
457 cwAction.setTooltip(BDMsg.gettext("Start each verses on a new line"));
459
460 cwAction = actions.addAction("CompareToggle", BDMsg.gettext("Show Differences"));
462 cwAction.setTooltip(BDMsg.gettext("Toggle display of differences between different Bibles"));
464
465 cwAction = actions.addAction(XSLTProperty.HEADINGS.getName(), BDMsg.gettext("Show Headings"));
467 cwAction = actions.addAction(XSLTProperty.NOTES.getName(), BDMsg.gettext("Show Study Notes"));
469 cwAction = actions.addAction(XSLTProperty.XREF.getName(), BDMsg.gettext("Use Cross Reference Linkings"));
471 cwAction = actions.addAction(XSLTProperty.STRONGS_NUMBERS.getName(), BDMsg.gettext("Show Strong's Numbers"));
473 cwAction = actions.addAction(XSLTProperty.MORPH.getName(), BDMsg.gettext("Show Word Morphology"));
475
476 cwAction = actions.addAction("ToolTipToggle", BDMsg.gettext("Show Tool Tips"));
478 cwAction.setTooltip(BDMsg.gettext("Toggle display of tool tips"));
481 cwAction.setAccelerator("T,ctrl");
482
483 cwAction = actions.addAction("StatusToggle", BDMsg.gettext("Show the Status Area"));
485 cwAction.setTooltip(BDMsg.gettext("Toggle display of the status area"));
487
488 cwAction = actions.addAction("SidebarToggle", BDMsg.gettext("Show the Passage Sidebar"));
490 cwAction.setTooltip(BDMsg.gettext("Toggle display of the Passage Sidebar"));
492 cwAction.setAccelerator("B,ctrl");
493
494 cwAction = actions.addAction("ViewSource", BDMsg.gettext("View Source"));
496 cwAction.setTooltip(BDMsg.gettext("View the HTML and OSIS source to the current window"));
498 cwAction.setAccelerator("U,ctrl");
499
500 cwAction = actions.addAction("Tools", BDMsg.gettext("Tools"));
503
504 cwAction = actions.addAction("Books", BDMsg.gettext("Books"));
506 cwAction.setTooltip(BDMsg.gettext("Display/Install Books"));
508 cwAction.setSmallIcon("toolbarButtonGraphics/general/Import16.gif");
509 cwAction.setLargeIcon("toolbarButtonGraphics/general/Import24.gif");
510
511 cwAction = actions.addAction("Options", BDMsg.gettext("Options"));
515 cwAction.setTooltip(BDMsg.gettext("Alter system settings."));
517 cwAction.setSmallIcon("toolbarButtonGraphics/general/Properties16.gif");
518 cwAction.setLargeIcon("toolbarButtonGraphics/general/Properties24.gif");
519
520 cwAction = actions.addAction("Help", BDMsg.gettext("Help"));
523
524 cwAction = actions.addAction("Contents", BDMsg.gettext("Contents"));
526 cwAction.setTooltip(BDMsg.gettext("Help file contents."));
528 cwAction.setSmallIcon("toolbarButtonGraphics/general/Help16.gif");
529 cwAction.setLargeIcon("toolbarButtonGraphics/general/Help24.gif");
530 cwAction.setAccelerator("0x70");
531
532 cwAction = actions.addAction("About", BDMsg.gettext("About"));
536 cwAction.setTooltip(BDMsg.gettext("Information about Bible Desktop"));
538 cwAction.setSmallIcon("toolbarButtonGraphics/general/About16.gif");
539 cwAction.setLargeIcon("toolbarButtonGraphics/general/About24.gif");
540 }
541
542
547 private JMenu createFileMenu() {
548 JMenu menu = new JMenu(actions.findAction("File"));
549 menu.setToolTipText(null);
550
551 menu.add(views.getContextAction(ViewManager.NEW_TAB)).addMouseListener(barStatus);
552 menu.add(views.getContextAction(ViewManager.CLOSE_VIEW)).addMouseListener(barStatus);
553 menu.add(views.getContextAction(ViewManager.CLEAR_VIEW)).addMouseListener(barStatus);
554 menu.add(views.getContextAction(ViewManager.CLOSE_OTHER_VIEWS)).addMouseListener(barStatus);
555 menu.add(views.getContextAction(ViewManager.CLOSE_ALL_VIEWS)).addMouseListener(barStatus);
556
557 menu.addSeparator();
558 menu.add(actions.findAction("Open")).addMouseListener(barStatus);
559 menu.add(actions.findAction("Save")).addMouseListener(barStatus);
560 menu.add(actions.findAction("SaveAs")).addMouseListener(barStatus);
561 menu.add(actions.findAction("SaveAll")).addMouseListener(barStatus);
562
563 if (!desktopActions.isOSXRegistered()) {
565 menu.addSeparator();
566 menu.add(actions.findAction("Exit")).addMouseListener(barStatus);
567 }
568
569 return menu;
570 }
571
572 private JMenu createEditMenu() {
573 JMenu menu = new JMenu(actions.findAction("Edit"));
574 menu.setToolTipText(null);
575 menu.add(actions.findAction("Copy")).addMouseListener(barStatus);
577
579 return menu;
580 }
581
582 private JMenu createNavigateMenu() {
583 JMenu menu = new JMenu(actions.findAction("Navigate"));
584 menu.setToolTipText(null);
585
586 menu.add(actions.findAction("Back")).addMouseListener(barStatus);
587 menu.add(actions.findAction("Forward")).addMouseListener(barStatus);
588
589 return menu;
590 }
591
592 private JRadioButtonMenuItem createRadioButton(ButtonGroup group, XSLTProperty prop) {
593 JRadioButtonMenuItem radio = new JRadioButtonMenuItem(actions.findAction(prop.getName()));
594 group.add(radio);
595 radio.setSelected(prop.getDefaultState());
596 return radio;
597 }
598
599 private JCheckBoxMenuItem createCheckbox(XSLTProperty prop) {
600 JCheckBoxMenuItem toggle = new JCheckBoxMenuItem(actions.findAction(prop.getName()));
601 toggle.setSelected(prop.getDefaultState());
602 return toggle;
603 }
604
605 private JMenu createVerseMenu() {
606 JMenu menu = new JMenu(actions.findAction("Verse"));
607 ButtonGroup group = new ButtonGroup();
608 menu.add(createRadioButton(group, XSLTProperty.VERSE_NUMBERS)).addMouseListener(barStatus);
609 menu.add(createRadioButton(group, XSLTProperty.CV)).addMouseListener(barStatus);
610 menu.add(createRadioButton(group, XSLTProperty.BCV)).addMouseListener(barStatus);
611 menu.add(createRadioButton(group, XSLTProperty.NO_VERSE_NUMBERS)).addMouseListener(barStatus);
612 return menu;
613 }
614
615
620 private JMenu createViewMenu(ToolBar toolbar) {
621 JMenu menu = new JMenu(actions.findAction("View"));
622 menu.add(createCheckbox(XSLTProperty.TINY_VERSE_NUMBERS)).addMouseListener(barStatus);
623 menu.add(createCheckbox(XSLTProperty.START_VERSE_ON_NEWLINE)).addMouseListener(barStatus);
624 menu.add(createVerseMenu());
625
626 menu.addSeparator();
627
628 menu.add(new JCheckBoxMenuItem(actions.findAction("CompareToggle"))).addMouseListener(barStatus);
629 menu.add(createCheckbox(XSLTProperty.HEADINGS)).addMouseListener(barStatus);
630 menu.add(createCheckbox(XSLTProperty.NOTES)).addMouseListener(barStatus);
631 menu.add(createCheckbox(XSLTProperty.XREF)).addMouseListener(barStatus);
632 menu.add(createCheckbox(XSLTProperty.STRONGS_NUMBERS)).addMouseListener(barStatus);
633 menu.add(createCheckbox(XSLTProperty.MORPH)).addMouseListener(barStatus);
634
635 menu.addSeparator();
636
637 menu.add(views.getTdiView()).addMouseListener(barStatus);
638 menu.add(views.getMdiView()).addMouseListener(barStatus);
639
640 menu.addSeparator();
641
642 menu.add(toolbar.getShowToggle()).addMouseListener(barStatus);
643 menu.add(toolbar.getTextToggle()).addMouseListener(barStatus);
644 menu.add(toolbar.getIconSizeToggle()).addMouseListener(barStatus);
645
646 JCheckBoxMenuItem toggle = new JCheckBoxMenuItem(actions.findAction("ToolTipToggle"));
647 toggle.setSelected(true);
648 menu.add(toggle).addMouseListener(barStatus);
649
650 toggle = new JCheckBoxMenuItem(actions.findAction("StatusToggle"));
651 toggle.setSelected(true);
652 menu.add(toggle).addMouseListener(barStatus);
653
654 sidebarToggle = new JCheckBoxMenuItem(actions.findAction("SidebarToggle"));
655 sidebarToggle.setSelected(isSidebarShowing());
656 menu.add(sidebarToggle).addMouseListener(barStatus);
657
658 if (viewSourceShowing) {
659 menu.addSeparator();
660
661 menu.add(actions.findAction("ViewSource")).addMouseListener(barStatus);
662 menu.setToolTipText(null);
663 }
664
665 return menu;
666 }
667
668 private JMenu createToolsMenu() {
669 JMenu menu = new JMenu(actions.findAction("Tools"));
670 menu.setToolTipText(null);
671
672 menu.add(actions.findAction("Books")).addMouseListener(barStatus);
673
674 if (!desktopActions.isOSXRegistered()) {
676 menu.add(actions.findAction("Options")).addMouseListener(barStatus);
677 }
678
679 return menu;
680 }
681
682 private JMenu createHelpMenu() {
683 JMenu menu = new JMenu(actions.findAction("Help"));
684 menu.setToolTipText(null);
685 menu.add(actions.findAction("Contents")).addMouseListener(barStatus);
686
687 if (!desktopActions.isOSXRegistered()) {
689 menu.addSeparator();
690 menu.add(actions.findAction("About")).addMouseListener(barStatus);
691 }
692
693 return menu;
694 }
695
696 private JPopupMenu createPopupMenu() {
697 JPopupMenu menu = new JPopupMenu();
698 menu.add(views.getContextAction(ViewManager.NEW_TAB)).addMouseListener(barStatus);
699 menu.add(views.getContextAction(ViewManager.CLOSE_VIEW)).addMouseListener(barStatus);
700 menu.add(views.getContextAction(ViewManager.CLEAR_VIEW)).addMouseListener(barStatus);
701 menu.add(views.getContextAction(ViewManager.CLOSE_OTHER_VIEWS)).addMouseListener(barStatus);
702 menu.add(views.getContextAction(ViewManager.CLOSE_ALL_VIEWS)).addMouseListener(barStatus);
703
704 menu.addSeparator();
705
706 menu.add(actions.findAction("Open")).addMouseListener(barStatus);
707 menu.add(actions.findAction("Save")).addMouseListener(barStatus);
708 menu.add(actions.findAction("SaveAs")).addMouseListener(barStatus);
709 menu.add(actions.findAction("SaveAll")).addMouseListener(barStatus);
710
711 return menu;
712 }
713
714 private ToolBar createToolBar() {
715 ToolBar menu = new ToolBar(this);
716
717 menu.add(views.getContextAction(ViewManager.NEW_TAB)).addMouseListener(barStatus);
718 menu.add(actions.findAction("Open")).addMouseListener(barStatus);
719 menu.add(actions.findAction("Save")).addMouseListener(barStatus);
720 menu.addSeparator();
721 menu.add(actions.findAction("Copy")).addMouseListener(barStatus);
723 menu.addSeparator();
725 menu.add(actions.findAction("Back")).addMouseListener(barStatus);
726 menu.add(actions.findAction("Forward")).addMouseListener(barStatus);
727 menu.addSeparator();
728 menu.add(actions.findAction("Contents")).addMouseListener(barStatus);
729
730 if (!desktopActions.isOSXRegistered()) {
732 menu.add(actions.findAction("About")).addMouseListener(barStatus);
733 }
734
735 menu.setRollover(true);
736
737 return menu;
738 }
739
740
743 public void establishPreferredSize() {
744 Container contentPane = getContentPane();
745 if (contentPane instanceof JComponent) {
746 ((JComponent) contentPane).setPreferredSize(contentPane.getSize());
747 }
749 }
750
751
754 public ViewManager getViews() {
755 return views;
756 }
757
758 public Component createView() {
759 boolean show = sidebarToggle == null ? isSidebarShowing() : sidebarToggle.isSelected();
760 BibleViewPane view = new BibleViewPane(show);
761 BookDataDisplay display = view.getPassagePane().getBookDataDisplay();
762 display.addURIEventListener(this);
763 display.addURIEventListener(barStatus);
764 display.setCompareBooks(compareShowing);
765 changeSupport.addPropertyChangeListener(BookDataDisplay.COMPARE_BOOKS, display);
766 DisplaySelectPane dsp = view.getSelectPane();
767 dsp.addCommandListener(this);
768 return view;
769 }
770
771
774 public void viewRemoved(ViewEvent event) {
775 BibleViewPane view = (BibleViewPane) event.getSource();
776 BookDataDisplay display = view.getPassagePane().getBookDataDisplay();
777 display.removeURIEventListener(this);
778 display.removeURIEventListener(barStatus);
779 changeSupport.removePropertyChangeListener(BookDataDisplay.COMPARE_BOOKS, display);
780 DisplaySelectPane dsp = view.getSelectPane();
781 dsp.removeCommandListener(this);
782 }
783
784
787 public void bookChosen(DisplaySelectEvent ev) {
788 }
790
791
794 public void passageSelected(DisplaySelectEvent ev) {
795 Key key = ev.getKey();
796 if (key != null && !key.isEmpty()) {
797 history.add(key.getName());
799 }
800 }
801
802 public void selectHistory(int i) {
803 Object obj = history.go(i);
804 if (obj != null) {
805 activateURI(new URIEvent(this, Desktop.BIBLE_PROTOCOL, (String) obj));
806 }
807 }
808
809
812 public void activateURI(URIEvent ev) {
813 barStatus.activateURI(ev);
814 String protocol = ev.getScheme();
815 String data = ev.getURI();
816
817 try {
818 if (protocol.equals(BIBLE_PROTOCOL)) {
819 BibleViewPane clearView = null;
821 for (Component comp : views) {
822 BibleViewPane view = (BibleViewPane) comp;
823 if (view.isClear()) {
824 clearView = view;
825 continue;
826 }
827 Book book = view.getSelectPane().getFirstBook();
828 if (book != null) {
829 Key key = book.getKey(data);
830 String dataPassage = key.getName();
831 if (view.getTitle().equals(dataPassage)) {
832 views.select(view);
834 return;
835 }
836 }
837 }
838
839 if (isBibleViewReused()) {
842 BibleViewPane view = (BibleViewPane) views.getSelected();
843 if (view != null) {
844 clearView = view;
845 }
846 }
847
848 if (clearView != null) {
850 Book book = clearView.getSelectPane().getFirstBook();
851 if (book != null) {
852 Key key = book.getKey(data);
853 clearView.setKey(book.createEmptyKeyList());
855 clearView.setKey(key);
856 views.select(clearView);
857 }
858 return;
859 }
860
861 BibleViewPane view = (BibleViewPane) views.addView();
864
865 Book book = view.getSelectPane().getFirstBook();
866 if (book != null) {
867 Key key = book.getKey(data);
868 view.setKey(key);
869 }
870 } else if (protocol.equals(COMMENTARY_PROTOCOL)) {
871 Book book = Defaults.getCommentary();
872 if (book != null && Books.installed().getBook(book.getName()) != null) {
873 reference.selectBook(book);
874 Book[] books = reference.getBooks();
875 Key key = books[0].getKey(data);
876 reference.setKey(key);
877 }
878 } else if (protocol.equals(GREEK_DEF_PROTOCOL)) {
879 jump(Defaults.getGreekDefinitions(), data);
880 } else if (protocol.equals(HEBREW_DEF_PROTOCOL)) {
881 jump(Defaults.getHebrewDefinitions(), data);
882 } else if (protocol.equals(GREEK_MORPH_PROTOCOL)) {
883 jump(Defaults.getGreekParse(), data);
884 } else if (protocol.equals(HEBREW_MORPH_PROTOCOL)) {
885 jump(Defaults.getHebrewParse(), data);
886 } else if (protocol.equals(DICTIONARY_PROTOCOL)) {
887 jump(Defaults.getDictionary(), data);
888 } else {
889 Reporter.informUser(this, new MalformedURLException(BDMsg.gettext("Unknown protocol {0}", protocol)));
891 }
892 } catch (NoSuchKeyException ex) {
893 Reporter.informUser(this, ex);
894 }
895 }
896
897
905 private void jump(Book book, String data) {
906 if (book != null && Books.installed().getBook(book.getName()) != null) {
908 reference.selectBook(book);
909 reference.setWord(data);
910 }
911 }
912
913
916 public void enterURI(URIEvent ev) {
917 }
919
920
923 public void leaveURI(URIEvent ev) {
924 }
926
927
933 public void showStatusBar(boolean show) {
934 if (show) {
935 corePanel.add(barStatus, BorderLayout.SOUTH);
936 } else {
937 corePanel.remove(barStatus);
938 }
939 validate();
940 }
941
942
948 public void setCloseEnabled(boolean enabled) {
949 views.getContextAction(ViewManager.CLEAR_VIEW).setEnabled(enabled);
950 views.getContextAction(ViewManager.CLOSE_OTHER_VIEWS).setEnabled(enabled);
951 }
952
953
956 public final void generateConfig() {
957 fillChoiceFactory();
959
960 config = new Config(BDMsg.gettext("Desktop Options"));
962 try {
963 Document xmlconfig = XMLUtil.getDocument(CONFIG_KEY);
964
965 Locale defaultLocale = Locale.getDefault();
966 ResourceBundle configResources = ResourceBundle.getBundle(CONFIG_KEY, defaultLocale, CWClassLoader.instance(Desktop.class));
967
968 config.add(xmlconfig, configResources);
969
970 try {
971 config.setProperties(ResourceUtil.getProperties(DESKTOP_KEY));
972 } catch (IOException ex) {
973 ex.printStackTrace(System.err);
974 ExceptionPane.showExceptionDialog(null, ex);
975 }
976
977 config.localToApplication();
978 config.addPropertyChangeListener(new PropertyChangeListener() {
979
982 public void propertyChange(PropertyChangeEvent evt) {
983 if ("BibleDisplay.ConfigurableFont".equals(evt.getPropertyName()))
986 {
987 BibleViewPane view = (BibleViewPane) getViews().getSelected();
988 SplitBookDataDisplay da = view.getPassagePane();
989 da.getBookDataDisplay().refresh();
990
991 reference.refresh();
992 }
993
994 if ("BibleDisplay.MaxPickers".equals(evt.getPropertyName()))
995 {
996 BibleViewPane view = (BibleViewPane) getViews().getSelected();
997 DisplaySelectPane selector = view.getSelectPane();
998 selector.getBiblePicker().enableButtons();
999 }
1000 }
1001 });
1002 } catch (IOException e) {
1003 e.printStackTrace(System.err);
1006 ExceptionPane.showExceptionDialog(null, e);
1007 } catch (JDOMException e) {
1008 e.printStackTrace(System.err);
1010 ExceptionPane.showExceptionDialog(null, e);
1011 }
1012
1013 }
1014
1015 public void checkForBooks() {
1016 List<Book> bibles = Books.installed().getBooks(BookFilters.getBibles());
1019 if (bibles.isEmpty()) {
1020 String title = BDMsg.gettext("Install Bibles?");
1022 StringBuilder msg = new StringBuilder(200);
1023 msg.append(BDMsg.gettext("You have no Bibles installed. Do you wish to install some now?"));
1026 msg.append("\n");
1027 msg.append("(This is also available from Books in the Tools menu)");
1029 int reply = CWOptionPane.showConfirmDialog(this, msg, title, JOptionPane.OK_CANCEL_OPTION,
1030 JOptionPane.QUESTION_MESSAGE);
1031 if (reply == JOptionPane.OK_OPTION) {
1032 desktopActions.doBooks();
1033 }
1034 }
1035 }
1036
1037
1041 public static void setSidebarShowing(boolean show) {
1042 sidebarShowing = show;
1043 }
1044
1045
1048 public static boolean isSidebarShowing() {
1049 return sidebarShowing;
1050 }
1051
1052
1056 public static void setViewSourceShowing(boolean show) {
1057 viewSourceShowing = show;
1058 }
1059
1060
1063 public static boolean isViewSourceShowing() {
1064 return viewSourceShowing;
1065 }
1066
1067
1071 public void setCompareShowing(boolean show) {
1072 boolean old = compareShowing;
1073 compareShowing = show;
1074 changeSupport.firePropertyChange(BookDataDisplay.COMPARE_BOOKS, old, compareShowing);
1075 }
1076
1077
1080 public boolean isCompareShowing() {
1081 return compareShowing;
1082 }
1083
1084
1088 public static void setBibleViewReused(boolean reuse) {
1089 reuseBibleView = reuse;
1090 }
1091
1092
1095 public static boolean isBibleViewReused() {
1096 return reuseBibleView;
1097 }
1098
1099
1103 public static void setCSSOverride(String override) {
1104 XSLTProperty.CSS.setState(override);
1105 }
1106
1107
1110 public static String getCSSOverride() {
1111 return XSLTProperty.CSS.getStringState();
1112 }
1113
1114
1118 final void fillChoiceFactory() {
1119 refreshBooks();
1121
1122 Translations.instance().register();
1123
1124 Map<String, Class<Converter>> converters = ConverterFactory.getKnownConverters();
1126 Set<String> keys = converters.keySet();
1127 String[] names = keys.toArray(new String[keys.size()]);
1128 ChoiceFactory.getDataMap().put(CONV_KEY, names);
1129
1130 ConfigurableSwingConverter cstyle = new ConfigurableSwingConverter();
1132 String[] cstyles = cstyle.getStyles();
1133 ChoiceFactory.getDataMap().put(CSWING_KEY, cstyles);
1134 }
1135
1136
1139 protected final void refreshBooks() {
1140 Defaults.refreshBooks();
1143
1144 boolean hasDictionaries = Defaults.getDictionary() != null;
1146 boolean hasCommentaries = Defaults.getCommentary() != null;
1147 boolean newRefBooks = hasDictionaries || hasCommentaries;
1148 if (newRefBooks != hasRefBooks) {
1149 if (reference != null) {
1151 if (!newRefBooks) {
1152 sptBooks.setDividerLocation(8000);
1153 } else {
1154 int norm = (int) (sptBooks.getMaximumDividerLocation() * 0.8);
1155 sptBooks.setDividerLocation(norm);
1156 }
1157 }
1160
1161 hasRefBooks = newRefBooks;
1162 }
1163 }
1164
1165
1168 public Config getConfig() {
1169 return config;
1170 }
1171
1172
1179 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
1180 config = null;
1181 history = null;
1182 desktopActions = new DesktopActions(this);
1183 actions = new ActionFactory(desktopActions);
1184 buildActionMap();
1185 views = new ViewManager(this);
1186 views.addViewEventListener(this);
1187 is.defaultReadObject();
1188 }
1189
1190
1193 private static final class DesktopThread extends Thread {
1194 DesktopThread(ThreadGroup group) {
1195 super(group, "BibleDesktopUIThread");
1196 }
1197
1198
1201 @Override
1202 public void run() {
1203 Translations.instance().setLocale();
1205
1206 if (OSType.MAC.equals(OSType.getOSType())) {
1208 System.setProperty("apple.laf.useScreenMenuBar", "true");
1209 System.setProperty("com.apple.mrj.application.apple.menu.about.name", BDMsg.getApplicationTitle());
1210 System.setProperty("com.apple.mrj.application.live-resize", "true");
1211 }
1212
1213 ExceptionPane.setHelpDeskListener(true);
1214 LookAndFeelUtil.initialize();
1215
1216 Splash splash = new Splash();
1217 Desktop desktop = new Desktop();
1218
1219 LayoutPersistence layoutPersistence = LayoutPersistence.instance();
1222 if (layoutPersistence.isLayoutPersisted(desktop)) {
1223 layoutPersistence.restoreLayout(desktop);
1224 } else {
1225 GuiUtil.defaultDesktopSize(desktop);
1226 GuiUtil.centerOnScreen(desktop);
1227 }
1228
1229 SwingUtilities.invokeLater(new DesktopRunner(desktop, splash));
1232 }
1233 }
1234
1235
1238 private static class DesktopRunner implements Runnable {
1239
1243 public DesktopRunner(Desktop aDesktop, Splash aSplash) {
1244 desktop = aDesktop;
1245 splash = aSplash;
1246 }
1247
1248
1251 public void run() {
1252 splash.close();
1253 desktop.setVisible(true);
1254 desktop.establishPreferredSize();
1255 desktop.pack();
1256 desktop.checkForBooks();
1257 }
1258
1259 private Desktop desktop;
1260 private Splash splash;
1261 }
1262
1263 private boolean hasRefBooks;
1264
1265 private static final String SPLASH_PROPS = "splash";
1267
1268 public static final String BIBLE_PROTOCOL = "bible";
1270 public static final String DICTIONARY_PROTOCOL = "dict";
1271 public static final String GREEK_DEF_PROTOCOL = "gdef";
1272 public static final String HEBREW_DEF_PROTOCOL = "hdef";
1273 public static final String GREEK_MORPH_PROTOCOL = "gmorph";
1274 public static final String HEBREW_MORPH_PROTOCOL = "hmorph";
1275 public static final String COMMENTARY_PROTOCOL = "comment";
1276
1277 private static final String EMPTY_STRING = "";
1279
1280 private static final String CONFIG_KEY = "config";
1282 private static final String DESKTOP_KEY = "desktop";
1283 private static final String CONV_KEY = "converters";
1284 private static final String CSWING_KEY = "cswing-styles";
1285
1286
1289 private transient Config config;
1290
1291
1294 private static boolean sidebarShowing;
1295
1296
1299 private static boolean viewSourceShowing;
1300
1301
1304 private boolean compareShowing;
1305
1306
1309 private static boolean reuseBibleView = true;
1310
1311
1314 protected static final Logger log = Logger.getLogger(Desktop.class);
1315
1316
1319 private transient volatile ActionFactory actions;
1320
1323 protected transient DesktopActions desktopActions;
1324
1325
1328 private static final ImageIcon ICON_APP = GuiUtil.getIcon("images/BibleDesktop16.png");
1329
1330 private transient ViewManager views;
1331 private JPanel corePanel;
1332 private JCheckBoxMenuItem sidebarToggle;
1333 private StatusBar barStatus;
1334 protected MultiBookPane reference;
1335 private JSplitPane sptBooks;
1336 private JPanel mainPanel;
1337 private transient History history;
1338 private PropertyChangeSupport changeSupport;
1339
1340
1343 private static final long serialVersionUID = 3977014029116191800L;
1344}
1345