001 package jigcell.compare.ui;
002
003 import java.awt.BorderLayout;
004 import java.awt.Component;
005 import java.awt.Container;
006 import java.awt.Cursor;
007 import java.awt.Dimension;
008 import java.awt.EventQueue;
009 import java.awt.Frame;
010 import java.awt.Toolkit;
011 import java.awt.Window;
012 import java.awt.event.ActionEvent;
013 import java.awt.event.ActionListener;
014 import java.awt.event.ComponentEvent;
015 import java.awt.event.ComponentListener;
016 import java.awt.event.MouseEvent;
017 import java.awt.event.MouseListener;
018 import java.awt.event.WindowEvent;
019 import java.awt.event.WindowListener;
020 import java.awt.event.WindowStateListener;
021 import java.beans.PropertyChangeEvent;
022 import java.lang.reflect.Field;
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.HashSet;
026 import java.util.Iterator;
027 import java.util.List;
028 import java.util.Map;
029 import javax.swing.BorderFactory;
030 import javax.swing.ImageIcon;
031 import javax.swing.JButton;
032 import javax.swing.JComponent;
033 import javax.swing.JDialog;
034 import javax.swing.JFrame;
035 import javax.swing.JLabel;
036 import javax.swing.JMenu;
037 import javax.swing.JMenuBar;
038 import javax.swing.JPanel;
039 import javax.swing.JScrollPane;
040 import javax.swing.JTabbedPane;
041 import javax.swing.JToolBar;
042 import javax.swing.JWindow;
043 import javax.swing.LookAndFeel;
044 import javax.swing.SwingUtilities;
045 import javax.swing.Timer;
046 import javax.swing.UIManager;
047 import javax.swing.event.ChangeEvent;
048 import javax.swing.event.ChangeListener;
049 import jigcell.compare.IConfigEditor;
050 import jigcell.compare.ITab;
051 import jigcell.compare.impl.Compare;
052 import jigcell.compare.impl.Config;
053 import jigcell.compare.impl.ProxyBuilder;
054
055 /**
056 * The Comparator frontend.
057 *
058 * <p>
059 * This code is licensed under the DARPA BioCOMP Open Source License. See LICENSE for more details.
060 * </p>
061 *
062 * @author Nicholas Allen
063 */
064
065 public class CompareFrontEnd extends Compare implements ChangeListener, ComponentListener, ITab, WindowListener, WindowStateListener {
066
067 /**
068 * Property key for look and feel class
069 */
070
071 public final static String CONFIG_LOOKFEEL = "CompareFrontEnd.lookAndFeel";
072
073 /**
074 * Property key for tab config names
075 */
076
077 public final static String CONFIG_TABCONFIG = "CompareFrontEnd.tabs";
078
079 /**
080 * Property key for window coordinates
081 */
082
083 public final static String CONFIG_WINDOWCOORDINATES = "CompareFrontEnd.windowCoordinates";
084
085 /**
086 * Property key for window maximized state
087 */
088
089 public final static String CONFIG_WINDOWMAXIMIZED = "CompareFrontEnd.windowMaximized";
090
091 /**
092 * Initial dimensions of the Comparator window
093 */
094
095 protected final static Dimension DIMENSION_WINDOW = new Dimension (880, 660);
096
097 /**
098 * Number of screen buffers to request
099 */
100
101 protected final static int COUNT_FRAMEBUFFER = 2;
102
103 /**
104 * Default menu bar name
105 */
106
107 protected final static String MENUBAR_DEFAULT = "default";
108
109 /**
110 * Method signature of tabs
111 */
112
113 private final static Class SIGNATURE_TAB [] = new Class [] {Compare.class, String.class};
114
115 /**
116 * Provides interface help for the view
117 */
118
119 protected InterfaceBuilder manager;
120
121 /**
122 * Main interface
123 */
124
125 protected JTabbedPane pane;
126
127 /**
128 * Toolbar
129 */
130
131 protected JToolBar toolbar;
132
133 /**
134 * Menu builder
135 */
136
137 protected MenuBuilder menuManager;
138
139 /**
140 * Component of the tab to add to pane
141 */
142
143 private Component tabComponent;
144
145 /**
146 * Currently selected tab in the display frame
147 */
148
149 private ITab selectedTab;
150
151 /**
152 * Tab to add to pane
153 */
154
155 private ITab tabImplementation;
156
157 /**
158 * Current tab accessory
159 */
160
161 private ITabAccessory currentTabAccessory;
162
163 /**
164 * Default tab accessory
165 */
166
167 private ITabAccessory defaultTabAccessory;
168
169 /**
170 * Display frame for frontend shell
171 */
172
173 private JFrame displayFrame;
174
175 /**
176 * Splash screen while loading
177 */
178
179 private SplashScreen splash;
180
181 /**
182 * Information about a Comparator tab.
183 */
184
185 protected static class FrontEndTabInfo extends TabInfo {
186
187 /**
188 * Configures the tab
189 */
190
191 private final IConfigEditor config;
192
193 /**
194 * Tab toolbar tools
195 */
196
197 private final JButton tools [];
198
199 /**
200 * About the tab
201 */
202
203 private final JDialog about;
204
205 /**
206 * Tab menus
207 */
208
209 private final JMenu menus [];
210
211 /**
212 * Tab accessory
213 */
214
215 private ITabAccessory accessory;
216
217 /**
218 * Creates a new tab description.
219 *
220 * @param tab Tab
221 * @param menus Tab menus
222 * @param tools Tab toolbar tools
223 * @param about About dialog for the tab
224 * @param config Configure dialog the tab
225 */
226
227 public FrontEndTabInfo (ITab tab, JMenu menus [], JButton tools [], JDialog about, IConfigEditor config) {
228 super (tab);
229 this.menus = menus;
230 this.tools = tools;
231 this.about = about;
232 this.config = config;
233 }
234
235 /**
236 * About the tab.
237 */
238
239 public JDialog getAbout () {
240 return about;
241 }
242
243 /**
244 * The tab accessory.
245 */
246
247 public ITabAccessory getAccessory () {
248 return accessory;
249 }
250
251 /**
252 * Configures the tab.
253 */
254
255 public IConfigEditor getConfigEditor () {
256 return config;
257 }
258
259 /**
260 * The tab menus.
261 */
262
263 public JMenu [] getMenus () {
264 return menus;
265 }
266
267 /**
268 * The tab toolbar tools.
269 */
270
271 public JButton [] getTools () {
272 return tools;
273 }
274
275 /**
276 * Sets the tab accessory. If the accessory is null, the default accessory will be used.
277 *
278 * @param accessory Tab accessory
279 */
280
281 public void setAccessory (ITabAccessory accessory) {
282 this.accessory = accessory;
283 }
284 }
285
286 /**
287 * A splash screen to display while things are loading.
288 */
289
290 protected class SplashScreen extends JWindow implements ActionListener, MouseListener, Runnable {
291
292 /**
293 * Length to display splash screen after loading is done
294 */
295
296 protected final static int TIMER_LENGTH = 1000;
297
298 /**
299 * Lock for controlling the splash screen
300 */
301
302 public final Object SPLASH_LOCK = new Object ();
303
304 /**
305 * Minimum size splash to display
306 */
307
308 protected Dimension SIZE_MINIMUM = new Dimension (400, 300);
309
310 /**
311 * Status display
312 */
313
314 protected JLabel messageLabel;
315
316 /**
317 * Status text to update to
318 */
319
320 protected String message;
321
322 /**
323 * Delay timer
324 */
325
326 protected Timer timer;
327
328 /**
329 * Lock for controlling update manipulation
330 */
331
332 private final Object UPDATE_LOCK = new Object ();
333
334 public SplashScreen (JFrame compare, String message) {
335 super (compare);
336 SplashScreen.this.setCursor (Cursor.getPredefinedCursor (Cursor.WAIT_CURSOR));
337 timer = new Timer (TIMER_LENGTH, this);
338 Container pane = this.getContentPane ();
339 pane.add (new JLabel (UIManager.getIcon ("jigcell.compare.splashScreen")), BorderLayout.CENTER);
340 messageLabel = new JLabel (message);
341 pane.add (messageLabel, BorderLayout.SOUTH);
342 this.getRootPane ().setBorder (BorderFactory.createRaisedBevelBorder ());
343 this.pack ();
344 Dimension size = getSize ();
345 if (size.width < SIZE_MINIMUM.width)
346 size.width = SIZE_MINIMUM.width;
347 if (size.height < SIZE_MINIMUM.height)
348 size.height = SIZE_MINIMUM.height;
349 setSize (size);
350 this.setLocationRelativeTo (null);
351 this.addWindowListener (CompareFrontEnd.this);
352 this.addMouseListener (this);
353 this.setVisible (true);
354 }
355
356 public void actionPerformed (ActionEvent e) {
357 this.setVisible (false);
358 this.dispose ();
359 }
360
361 /**
362 * Destroys the splash screen.
363 */
364
365 public void dispose () {
366 synchronized (SPLASH_LOCK) {
367 this.removeMouseListener (this);
368 if (timer != null) {
369 timer.stop ();
370 timer.removeActionListener (this);
371 timer = null;
372 }
373 super.dispose ();
374 }
375 }
376
377 public void mouseClicked (MouseEvent e) {}
378
379 public void mouseEntered (MouseEvent e) {}
380
381 public void mouseExited (MouseEvent e) {}
382
383 public void mousePressed (MouseEvent e) {
384 this.setVisible (false);
385 this.dispose ();
386 }
387
388 public void mouseReleased (MouseEvent e) {}
389
390 public void run () {
391 messageLabel.setText (message);
392 message = null;
393 }
394
395 /**
396 * Changes the status message displayed on the splash screen.
397 *
398 * @param message Message to display
399 */
400
401 public void updateStatus (String message) {
402 updateStatus (message, false);
403 }
404
405 /**
406 * Changes the status message displayed on the splash screen.
407 *
408 * @param message Message to display
409 * @param done Whether the load has finished
410 */
411
412 public void updateStatus (String message, boolean done) {
413 synchronized (UPDATE_LOCK) {
414 if (done && timer != null)
415 timer.start ();
416 if (EventQueue.isDispatchThread ())
417 messageLabel.setText (message);
418 else
419 try {
420 this.message = message;
421 message (message);
422 EventQueue.invokeAndWait (this);
423 } catch (Exception e) {
424 assertion (getString ("CompareFrontEnd.splashUpdateError"), e);
425 }
426 }
427 }
428 }
429
430 static {
431 new IconLoader (CompareFrontEnd.class);
432 }
433
434 /**
435 * Starts a new graphical Comparator.
436 *
437 * @param args Program arguments
438 */
439
440 public static void main (String args []) {
441 new CompareFrontEnd (args == null || args.length == 0 ? DEFAULT_CONFIG : args [0]);
442 }
443
444 /**
445 * Finds the class for a given look and feel name.
446 *
447 * @param name Name of look and feel
448 */
449
450 protected static Class findLookAndFeelClass (String name) {
451 if (name == null)
452 return null;
453 UIManager.LookAndFeelInfo looks [] = UIManager.getInstalledLookAndFeels ();
454 for (int looksCount = 0, looksLength = looks.length; looksCount < looksLength; looksCount++) {
455 UIManager.LookAndFeelInfo look = looks [looksCount];
456 if (name.equals (look.getName ()))
457 try {
458 return Class.forName (look.getClassName ());
459 } catch (Exception e) {
460 assertion (getString ("CompareFrontEnd.lookFeelCreateError"), e);
461 return null;
462 }
463 }
464 return null;
465 }
466
467 /**
468 * Installs a new look and feel if it has not already been registered.
469 *
470 * @param name Name of new look and feel
471 * @param className Class for new look and feel
472 */
473
474 protected static void installLookAndFeel (String name, String className) {
475 if (name == null || className == null)
476 throw new IllegalArgumentException ();
477 UIManager.LookAndFeelInfo looks [] = UIManager.getInstalledLookAndFeels ();
478 int looksLength = looks.length;
479 for (int looksCount = 0; looksCount < looksLength; looksCount++)
480 if (className.equals (looks [looksCount].getClassName ()))
481 return;
482 UIManager.LookAndFeelInfo newLooks [] = new UIManager.LookAndFeelInfo [looksLength + 1];
483 System.arraycopy (looks, 0, newLooks, 0, looksLength);
484 newLooks [looksLength] = new UIManager.LookAndFeelInfo (name, className);
485 UIManager.setInstalledLookAndFeels (newLooks);
486 }
487
488 /**
489 * Creates a new graphical Comparator.
490 *
491 * @param configFile Name of configuration file
492 */
493
494 public CompareFrontEnd (String configFile) {
495 super (configFile);
496 try {
497 Config config = getConfig ();
498 Config compareConfig = config.getConfig (Config.convertToClassMarker (this));
499 for (Iterator iterator = Config.convertToList (config.findValue (configMarkers, CONFIG_TABCONFIG, false, false, false)).iterator ();
500 iterator.hasNext (); )
501 try {
502 String marker = Config.createInstanceMarker ();
503 Config tabConfig = compareConfig.getConfig ((String) iterator.next ());
504 String name = tabConfig.findValue (null, CONFIG_CLASSNAME, false, false, false);
505 config.setConfig (marker, tabConfig);
506 if (splash != null)
507 synchronized (splash.SPLASH_LOCK) {
508 splash.updateStatus (formatString ("CompareFrontEnd.tabLoad", name));
509 }
510 ITab tab = (ITab) Class.forName (name).getDeclaredConstructor (SIGNATURE_TAB).newInstance (new Object [] {this, marker});
511 tab.readConfiguration (ITab.STATE_ENDINITIALIZE);
512 } catch (Exception e) {
513 shellHandleException (MESSAGE_WARNING, getString ("CompareFrontEnd.tabLoadError"), e);
514 }
515 } catch (Exception e) {
516 assertion (getString ("CompareFrontEnd.tabListError"), e);
517 }
518 if (splash != null)
519 synchronized (splash.SPLASH_LOCK) {
520 splash.updateStatus (getString ("CompareFrontEnd.startupFinished"), true);
521 splash = null;
522 }
523 }
524
525 /**
526 * Adds a tab to the main Comparator display.
527 *
528 * @param component Contents of the tab
529 */
530
531 public TabInfo addTab (ITab component) {
532 return addTab (component, component instanceof Component, null, null);
533 }
534
535 /**
536 * Adds a tab to the main Comparator display.
537 *
538 * @param component Contents of the tab
539 * @param wrapped Whether component should be wrapped in a scrollpane
540 * @param menus Menus to be displayed when tab is active
541 * @param tools Tools to place in toolbar
542 */
543
544 public TabInfo addTab (ITab component, boolean wrapped, JMenu menus [], JButton tools []) {
545 TabInfo info = new FrontEndTabInfo (component, menus, tools, component.createAboutDialog (), component.createConfigEditor ());
546 synchronized (TAB_LOCK) {
547 updateResourceMap (RESOURCE_TABS, component, info);
548 if (!(component instanceof Component))
549 return info;
550 tabImplementation = component;
551 if (wrapped) {
552 JScrollPane pane = new JScrollPane ((Component) component, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
553 JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
554 pane.setBorder (InterfaceBuilder.BORDER_NOTHING);
555 tabComponent = pane;
556 } else
557 tabComponent = (Component) component;
558 if (EventQueue.isDispatchThread ())
559 addTabToView ();
560 else
561 try {
562 EventQueue.invokeAndWait (ProxyBuilder.proxyRunnable (this, "addTabToView"));
563 } catch (Exception e) {
564 assertion (getString ("CompareFrontEnd.tabAddError"), e);
565 }
566 }
567 return info;
568 }
569
570 public void componentHidden (ComponentEvent e) {}
571
572 public void componentMoved (ComponentEvent e) {
573 saveWindowSettings ();
574 }
575
576 public void componentResized (ComponentEvent e) {
577 saveWindowSettings ();
578 }
579
580 public void componentShown (ComponentEvent e) {}
581
582 /**
583 * Starts configuring a Comparator tab.
584 */
585
586 public void configure (ITab tab) {
587 IConfigEditor configEditor = getTabInfo (tab).getConfigEditor ();
588 if (configEditor == null)
589 return;
590 JDialog configDialog = configEditor.createConfigDialog ();
591 configDialog.setLocationRelativeTo (null);
592 if (!configDialog.isVisible ())
593 configDialog.setVisible (true);
594 configDialog.requestFocus ();
595 }
596
597 /**
598 * {@inheritDoc}
599 */
600
601 public JDialog createAboutDialog () {
602 return PanelTab.createAboutDialogForTab (CompareFrontEnd.class, manager);
603 }
604
605 /**
606 * {@inheritDoc}
607 */
608
609 public IConfigEditor createConfigEditor () {
610 IConfigEditor editor = new ConfigEditor (this, this, configMarkers, getConfig ().getConfig (Config.convertToClassMarker (this)));
611 editor.addOption (CONFIG_DATASOURCE, getString ("CompareFrontEnd.optionData"), String [].class);
612 UIManager.LookAndFeelInfo looks [] = UIManager.getInstalledLookAndFeels ();
613 int looksLength = looks.length;
614 String lookNames [] = new String [looksLength];
615 for (int looksCount = 0; looksCount < looksLength; looksCount++)
616 lookNames [looksCount] = looks [looksCount].getName ();
617 lookNames = (String []) new HashSet (Arrays.asList (lookNames)).toArray (new String [0]);
618 Arrays.sort (lookNames);
619 editor.addOption (CONFIG_LOOKFEEL, getString ("CompareFrontEnd.optionLook"), lookNames, true, Class.class);
620 return editor;
621 }
622
623 /**
624 * The frontend shell display frame. Returns null if this is a headless Comparator.
625 */
626
627 public JFrame getDisplayFrame () {
628 return displayFrame;
629 }
630
631 /**
632 * {@inheritDoc}
633 */
634
635 public String getName () {
636 return getString ("CompareFrontEnd.tabName");
637 }
638
639 /**
640 * The accessory component for a tab.
641 */
642
643 public ITabAccessory getTabAccessory (ITab tab) {
644 ITabAccessory accessory = getTabInfo (tab).getAccessory ();
645 return accessory == null ? defaultTabAccessory : accessory;
646 }
647
648 /**
649 * The currently selected tab in the display frame.
650 */
651
652 public ITab getSelectedTab () {
653 return selectedTab;
654 }
655
656 protected void propertyChange (PropertyChangeEvent e) {
657 if (PROPERTY_CONFIG_EDIT.equals (e.getPropertyName ()))
658 readConfiguration (STATE_RUNNING);
659 super.propertyChange (e);
660 }
661
662 /**
663 * {@inheritDoc}
664 */
665
666 public void readConfiguration (String state) {
667 updateLookAndFeel (state);
668 }
669
670 /**
671 * Selects one of the tabs for the display frame.
672 *
673 * @param tab Underlying tab component
674 */
675
676 public void selectTab (ITab tab) {
677 if (selectedTab == tab)
678 return;
679 for (Iterator iterator = getTabMap ().keySet ().iterator (); iterator.hasNext (); ) {
680 Object component = iterator.next ();
681 if (component == tab || component instanceof JScrollPane && ((JScrollPane) component).getViewport ().getView () == tab) {
682 pane.setSelectedComponent ((Component) component);
683 return;
684 }
685 }
686 }
687
688 /**
689 * Sets the accessory component displayed for a tab. If the accessory is null, the default accessory will be displayed.
690 *
691 * @param tab Comparator tab
692 * @param accessory Accessory
693 */
694
695 public void setTabAccessory (ITab tab, ITabAccessory accessory) {
696 FrontEndTabInfo info = getTabInfo (tab);
697 info.setAccessory (accessory);
698 if (tab == getSelectedTab ())
699 updateViewAccessory (info);
700 displayFrame.validate ();
701 displayFrame.repaint ();
702 }
703
704 /**
705 * Handle an exception in a Comparator component.
706 *
707 * @param type Exception type
708 * @param message Display message
709 * @param t Throwable
710 */
711
712 public void shellHandleException (String type, Object message, Throwable t) {
713 manager.showErrorDialog (type, message, t);
714 assertion (message instanceof String ? (String) message : null, t);
715 }
716
717 /**
718 * Handle an informational message in a Comparator component.
719 *
720 * @param type Message type
721 * @param message Display message
722 */
723
724 public void shellHandleMessage (String type, Object message) {
725 manager.showMessageDialog (type, message);
726 if (message instanceof String)
727 message ((String) message);
728 }
729
730 public void stateChanged (ChangeEvent e) {
731 if (e.getSource () != pane)
732 return;
733 Map tabMap = getTabMap ();
734 Component component = pane.getSelectedComponent ();
735 FrontEndTabInfo info = (FrontEndTabInfo) tabMap.get (component);
736 if (info == null && component instanceof JScrollPane)
737 info = (FrontEndTabInfo) tabMap.get (((JScrollPane) component).getViewport ().getView ());
738 selectedTab = info.getTab ();
739 updateViewTools (info);
740 updateViewMenus (info);
741 updateViewAccessory (info);
742 displayFrame.validate ();
743 displayFrame.repaint ();
744 }
745
746 public void windowActivated (WindowEvent e) {}
747
748 public void windowClosed (WindowEvent e) {
749 if (e.getWindow () instanceof SplashScreen)
750 displayFrame.setVisible (true);
751 }
752
753 public void windowClosing (WindowEvent e) {
754 if (e.getWindow () == displayFrame)
755 exit (0);
756 }
757
758 public void windowDeactivated (WindowEvent e) {}
759
760 public void windowDeiconified (WindowEvent e) {}
761
762 public void windowIconified (WindowEvent e) {}
763
764 public void windowOpened (WindowEvent e) {
765 if (e.getWindow () == displayFrame) {
766 try {
767 Thread.currentThread ().setContextClassLoader (Compare.class.getClassLoader ());
768 } catch (Exception _e) {
769 assertion (getString ("Compare.startupLoaderError"), _e);
770 }
771 if (splash != null)
772 synchronized (splash.SPLASH_LOCK) {
773 Window children [] = displayFrame.getOwnedWindows ();
774 for (int i = 0, l = children.length; i < l; i++) {
775 Window child = children [i];
776 if (child != null && child instanceof SplashScreen) {
777 child.setVisible (false);
778 child.dispose ();
779 }
780 }
781 }
782 displayFrame.createBufferStrategy (COUNT_FRAMEBUFFER);
783 displayFrame.toFront ();
784 displayFrame.requestFocusInWindow ();
785 }
786 }
787
788 public void windowStateChanged (WindowEvent e) {
789 saveWindowSettings ();
790 }
791
792 protected void saveWindowSettings () {
793 Config config = getConfig ().getConfig (Config.convertToClassMarker (this));
794 int state = displayFrame.getExtendedState ();
795 config.setValue (CONFIG_WINDOWMAXIMIZED, (state & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH);
796 if (state == JFrame.NORMAL)
797 config.setValue (CONFIG_WINDOWCOORDINATES, displayFrame.getBounds ());
798 firePropertyChange (Compare.PROPERTY_CONFIG_EDIT);
799 }
800
801 /**
802 * Displays information about a Comparator tab.
803 */
804
805 protected void about (ITab tab) {
806 JDialog aboutDialog = getTabInfo (tab).getAbout ();
807 if (aboutDialog == null)
808 return;
809 aboutDialog.setLocationRelativeTo (null);
810 if (!aboutDialog.isVisible ())
811 aboutDialog.setVisible (true);
812 aboutDialog.requestFocus ();
813 }
814
815 /**
816 * Inserts a new tab into the interface.
817 */
818
819 protected void addTabToView () {
820 pane.addTab (tabImplementation.getName (), tabComponent);
821 if (pane.getTabCount () == 1)
822 selectTab (tabImplementation);
823 tabImplementation = null;
824 tabComponent = null;
825 }
826
827 /**
828 * Creates the menus that will appear for all tabs.
829 */
830
831 protected JMenu [] createSharedMenus () {
832 return menuManager.createMenus (MENUBAR_DEFAULT);
833 }
834
835 /**
836 * Exits from the Comparator.
837 *
838 * @param status Status code
839 */
840
841 protected void exit (int status) {
842 if (manager.showChoiceDialog (getString ("CompareFrontEnd.exitTitle"), getString ("CompareFrontEnd.exitQuestion"),
843 new String [] {getString ("CompareFrontEnd.exitButtonYes"), getString ("CompareFrontEnd.exitButtonNo")}, 1) != 0)
844 return;
845 displayFrame.setVisible (false);
846 displayFrame.dispose ();
847 super.exit (status);
848 }
849
850 /**
851 * The tab info for a tab.
852 *
853 * @param tab Tab
854 */
855
856 protected FrontEndTabInfo getTabInfo (ITab tab) {
857 for (Iterator iterator = getTabMap ().entrySet ().iterator (); iterator.hasNext (); ) {
858 Map.Entry entry = (Map.Entry) iterator.next ();
859 Object component = entry.getKey ();
860 if (component == tab || component instanceof JScrollPane && ((JScrollPane) component).getViewport ().getView () == tab)
861 return (FrontEndTabInfo) entry.getValue ();
862 }
863 return null;
864 }
865
866 /**
867 * {@inheritDoc}
868 */
869
870 protected void shellStableHook () {
871 super.shellStableHook ();
872 updateLookAndFeel (STATE_INITIALIZE);
873 splash = new SplashScreen (displayFrame, getString ("CompareFrontEnd.splashStartup"));
874 displayFrame = new JFrame (getString ("CompareFrontEnd.title"));
875 displayFrame.setIconImage (((ImageIcon) UIManager.getIcon ("jigcell.compare.programIcon")).getImage ());
876 Config config = getConfig ().getConfig (Config.convertToClassMarker (this));
877 try {
878 displayFrame.setBounds (Config.convertToRectangle (config.findValue (configMarkers, CONFIG_WINDOWCOORDINATES, false, false, false)));
879 } catch (Exception e) {
880 Compare.warning ("Unable to restore window position.", e);
881 displayFrame.setSize (DIMENSION_WINDOW);
882 displayFrame.setLocationRelativeTo (null);
883 }
884 if (Config.convertToBoolean (config.findValue (configMarkers, CONFIG_WINDOWMAXIMIZED, false, false, false), false))
885 displayFrame.setExtendedState (JFrame.MAXIMIZED_BOTH);
886 displayFrame.getToolkit ().setDynamicLayout (true);
887 displayFrame.setDefaultCloseOperation (JFrame.DO_NOTHING_ON_CLOSE);
888 displayFrame.addComponentListener (this);
889 displayFrame.addWindowListener (this);
890 displayFrame.addWindowStateListener (this);
891 manager = new InterfaceBuilder (this, displayFrame);
892 defaultTabAccessory = new MemoryMonitorAccessory ();
893 JPanel contentPane = new JPanel (new BorderLayout ());
894 pane = new JTabbedPane (JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
895 contentPane.add (pane, BorderLayout.CENTER);
896 pane.addChangeListener (this);
897 toolbar = new JToolBar ();
898 contentPane.add (toolbar, BorderLayout.NORTH);
899 toolbar.setRollover (true);
900 displayFrame.setContentPane (contentPane);
901 menuManager = new MenuBuilder (this);
902 synchronized (TAB_LOCK) {
903 updateResourceMap (RESOURCE_TABS, this,
904 new FrontEndTabInfo (this, createSharedMenus (), null, createAboutDialog (), createConfigEditor ()));
905 }
906 }
907
908 /**
909 * {@inheritDoc}
910 */
911
912 protected void shellStartHook () {
913 super.shellStartHook ();
914 try {
915 class FrontEndThreadGroup extends ThreadGroup {
916 public FrontEndThreadGroup () {
917 super ("compare");
918 }
919
920 public void uncaughtException (Thread thread, Throwable t) {
921 shellHandleException (t instanceof AssertionError ? getString ("CompareFrontEnd.assertionError") :
922 getString ("CompareFrontEnd.uncaughtError"), t.getMessage (), t);
923 }
924 }
925
926 Class unsafeClass = Class.forName ("sun.misc.Unsafe");
927 Field unsafeField = unsafeClass.getDeclaredField ("theUnsafe");
928 unsafeField.setAccessible (true);
929 Object unsafe = unsafeField.get (null);
930 Long offset = (Long) unsafeClass.getMethod ("objectFieldOffset", new Class [] {Field.class}).invoke (unsafe,
931 new Object [] {EventQueue.class.getDeclaredField ("threadGroup")});
932 unsafeClass.getMethod ("putObject", new Class [] {Object.class, Long.TYPE, Object.class}).invoke (unsafe,
933 new Object [] {Toolkit.getDefaultToolkit ().getSystemEventQueue (), offset, new FrontEndThreadGroup ()});
934 } catch (Exception e) {
935 assertion (getString ("CompareFrontEnd.startupGroupError"), e);
936 }
937 }
938
939 /**
940 * Modifies the application look and feel to match the current configuration.
941 *
942 * @param state Application state
943 */
944
945 protected void updateLookAndFeel (String state) {
946 String lookFeelName = getConfig ().findValue (configMarkers, CONFIG_LOOKFEEL, false, false, false);
947 if (lookFeelName == null)
948 return;
949 Class lookFeelClass = findLookAndFeelClass (lookFeelName);
950 if (lookFeelClass == null)
951 return;
952 LookAndFeel currentLook = UIManager.getLookAndFeel ();
953 if (currentLook != null && currentLook.getClass () == lookFeelClass)
954 return;
955 try {
956 UIManager.setLookAndFeel ((LookAndFeel) lookFeelClass.newInstance ());
957 } catch (Exception e) {
958 shellHandleException (MESSAGE_WARNING, getString ("CompareFrontEnd.lookFeelLoadError"), e);
959 }
960 if (state != STATE_RUNNING)
961 return;
962 List windows = new ArrayList ();
963 windows.addAll (Arrays.asList (Frame.getFrames ()));
964 while (!windows.isEmpty ()) {
965 Window window = (Window) windows.remove (0);
966 windows.addAll (Arrays.asList (window.getOwnedWindows ()));
967 SwingUtilities.updateComponentTreeUI (window);
968 }
969 updateViewTools (getTabInfo (getSelectedTab ()));
970 }
971
972 /**
973 * Fills in the tab accessory using the provided tab info.
974 *
975 * @param info Tab info
976 */
977
978 protected void updateViewAccessory (FrontEndTabInfo info) {
979 ITab tab = info.getTab ();
980 ITabAccessory accessory = getTabAccessory (tab);
981 Container contentPane = displayFrame.getContentPane ();
982 if (currentTabAccessory != null)
983 try {
984 contentPane.remove (currentTabAccessory.getDisplay ());
985 currentTabAccessory.uninstall ();
986 } finally {
987 currentTabAccessory = null;
988 }
989 if (accessory == null)
990 return;
991 JComponent display = accessory.getDisplay ();
992 SwingUtilities.updateComponentTreeUI (display);
993 contentPane.add (display, BorderLayout.SOUTH);
994 currentTabAccessory = accessory;
995 accessory.install (this, tab);
996 }
997
998 /**
999 * Fills in the menu bar using the provided tab info.
1000 *
1001 * @param info Tab info
1002 */
1003
1004 protected void updateViewMenus (FrontEndTabInfo info) {
1005 JMenuBar menuBar = new JMenuBar ();
1006 JMenu menus [] = getTabInfo (this).getMenus ();
1007 if (menus != null)
1008 for (int i = 0, l = menus.length; i < l; i++)
1009 menuBar.add (menus [i]);
1010 menus = info.getMenus ();
1011 if (menus != null)
1012 for (int i = 0, l = menus.length; i < l; i++)
1013 menuBar.add (menus [i]);
1014 SwingUtilities.updateComponentTreeUI (menuBar);
1015 displayFrame.setJMenuBar (menuBar);
1016 }
1017
1018 /**
1019 * Fills in the toolbar using the provided tab info.
1020 *
1021 * @param info Tab info
1022 */
1023
1024 protected void updateViewTools (FrontEndTabInfo info) {
1025 JButton tools [] = info.getTools ();
1026 toolbar.removeAll ();
1027 if (tools == null)
1028 return;
1029 for (int i = 0, l = tools.length; i < l; i++) {
1030 JButton tool = tools [i];
1031 if (tool == null)
1032 toolbar.addSeparator ();
1033 else {
1034 SwingUtilities.updateComponentTreeUI (tool);
1035 toolbar.add (tool);
1036 }
1037 }
1038 }
1039 }