1 /*
2 * Scope: a generic MVC framework.
3 * Copyright (c) 2000-2002, The Scope team
4 * All rights reserved.
5 *
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * Neither the name "Scope" nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 *
36 * $Id: SwingContext.java,v 1.17 2002/09/12 18:23:24 ludovicc Exp $
37 */
38 package org.scopemvc.controller.swing;
39
40
41 import java.awt.BorderLayout;
42 import java.awt.Container;
43 import java.awt.Cursor;
44 import java.awt.Dialog;
45 import java.awt.Frame;
46 import java.awt.Image;
47 import java.awt.Rectangle;
48 import java.awt.Window;
49 import java.awt.event.WindowAdapter;
50 import java.awt.event.WindowEvent;
51 import java.util.Iterator;
52 import java.util.LinkedList;
53 import java.util.Timer;
54 import java.util.TimerTask;
55 import javax.swing.JComponent;
56 import javax.swing.JDialog;
57 import javax.swing.JFrame;
58 import javax.swing.JMenu;
59 import javax.swing.JMenuBar;
60 import javax.swing.JMenuItem;
61 import javax.swing.JOptionPane;
62 import javax.swing.JRootPane;
63 import javax.swing.WindowConstants;
64 import org.apache.commons.logging.Log;
65 import org.apache.commons.logging.LogFactory;
66 import org.scopemvc.core.View;
67 import org.scopemvc.util.Debug;
68 import org.scopemvc.util.ResourceLoader;
69 import org.scopemvc.util.ScopeConfig;
70 import org.scopemvc.view.awt.AWTUtilities;
71 import org.scopemvc.view.swing.SMenuItem;
72 import org.scopemvc.view.swing.SwingUtil;
73 import org.scopemvc.view.swing.SwingView;
74 import org.scopemvc.controller.basic.ViewContext;
75
76 /***
77 * <P>
78 *
79 * Swing implementation of {@link org.scopemvc.controller.basic.ViewContext} to
80 * show views inside JFrames or JDialogs and show errors using JOptionPanes.
81 * <br>
82 * Also allows Views to take ownership of SMenuItems from their containing
83 * Window. </P>
84 *
85 * @author <A HREF="mailto:smeyfroi@users.sourceforge.net">Steve Meyfroidt</A>
86 * @created 05 August 2002
87 * @version $Revision: 1.17 $ $Date: 2002/09/12 18:23:24 $
88 * @see org.scopemvc.controller.basic.ViewContext
89 */
90 public class SwingContext extends ViewContext {
91
92 /***
93 * The property in ScopeConfig for the delay before showing the wait cursor
94 * when startProgress once startProgress() has been called, value in
95 * milliseconds
96 */
97 public static final String PROGRESS_START_DELAY_PROPERTY =
98 "org.scopemvc.controller.swing.SwingContext.progress_start_delay";
99
100 private static final Log LOG = LogFactory.getLog(SwingContext.class);
101
102 private static final long PROGRESS_START_DELAY =
103 ScopeConfig.getInteger(PROGRESS_START_DELAY_PROPERTY).longValue();
104
105 // ----------------- Shared null frame ----------------
106
107 /***
108 * The parent of views that get shown when no parent can be found. Ensures
109 * everything has the application icon.
110 */
111 private Frame sharedNullFrame;
112
113 // ----------------- Visible View management ----------------
114
115 /***
116 * Keep track of all open Frames and Dialogs by keeping references to their
117 * JRootPane. Don't bother tracking Message Boxes because they're modal and
118 * don't interact with Controllers directly. This is an ordered list: the
119 * last opened rootpane is at the end.
120 */
121 private LinkedList rootpanes = new LinkedList();
122
123 /***
124 * The timer used to delay the display of the wait cursor when {@link
125 * #startProgress} is called
126 */
127 private Timer progressStartTimer = new Timer(true);
128 private TimerTask task;
129
130
131 /***
132 * Constructor for the SwingContext object
133 */
134 public SwingContext() { }
135
136
137 /***
138 * Find the SMenuItem in the menu.
139 *
140 * @param inMenu A menu
141 * @param inControlID The control ID of the menu item to find
142 * @return The SMenuItem matching the control ID, or null if not found
143 */
144 protected static SMenuItem findMenuItemInMenu(JMenu inMenu, String inControlID) {
145 if (inControlID == null) {
146 throw new IllegalArgumentException("ControlID is null");
147 }
148
149 for (int i = 0; i < inMenu.getItemCount(); i++) {
150 JMenuItem item = inMenu.getItem(i);
151 if (item instanceof JMenu) {
152 SMenuItem result = findMenuItemInMenu((JMenu) item, inControlID);
153 if (result != null) {
154 return result;
155 }
156 continue;
157 } else if (item instanceof SMenuItem
158 && inControlID.equals(((SMenuItem) item).getControlID())) {
159 return (SMenuItem) item;
160 }
161 }
162 return null;
163 }
164
165
166 /***
167 * Show the view. <br>
168 * Depending on the display mode of the view, the view is displayed in a
169 * frame or a dialog.
170 *
171 * @param inView The view to show. Must be a subclass of SwingView
172 */
173 public void showView(View inView) {
174 if (LOG.isDebugEnabled()) {
175 LOG.debug("showView: " + inView);
176 }
177
178 if (!(inView instanceof SwingView)) {
179 throw new IllegalArgumentException("Can only show SwingViews: " + inView);
180 }
181
182 // Get topmost SwingView container
183 Container parentContainer = getTopmostContainer((SwingView) inView);
184 if (!(parentContainer instanceof SwingView)) {
185 throw new IllegalArgumentException("Can only show SwingViews: " + parentContainer);
186 }
187 SwingView view = (SwingView) parentContainer;
188
189 // Try to find the Dialog or Frame that holds View
190 // If one exists, bring it to the front and return.
191 JRootPane rootpane = findRootPaneFor(view);
192 if (rootpane != null) {
193 Container window = rootpane.getParent();
194 if (Debug.ON) {
195 Debug.assertTrue(window instanceof Window, "window not window: " + window.getClass());
196 }
197 ((Window) window).toFront();
198 return;
199 }
200
201 // OK, doesn't exist so create a new Dialog or Frame and show it
202 if (view.getDisplayMode() == SwingView.PRIMARY_WINDOW) {
203 showViewInPrimaryWindow(view);
204 } else {
205 showViewInDialog(view);
206 }
207 if (Debug.ON) {
208 Debug.assertTrue(findRootPaneFor(view) != null, "null findRootPaneFor");
209 }
210 }
211
212
213 /***
214 * Find the Window that is showing this View and then close it on Swing's
215 * event-handling thread. Does nothing if the passed View isn't showing.
216 * <br>
217 * This method disposes the Window from memory.
218 *
219 * @param inView The view to hide. Must be a subclass of SwingView
220 */
221 public void hideView(View inView) {
222 if (!(inView instanceof SwingView)) {
223 throw new IllegalArgumentException("Can only hide SwingViews: " + inView);
224 }
225
226 // Get topmost SwingView container
227 Container parentContainer = getTopmostContainer((SwingView) inView);
228 if (!(parentContainer instanceof SwingView)) {
229 throw new IllegalArgumentException("Can only hide SwingViews: " + parentContainer);
230 }
231 SwingView view = (SwingView) parentContainer;
232
233 JRootPane rootpane = findRootPaneFor(view);
234 if (rootpane == null) {
235 LOG.warn("Found no root pane for view " + view + ". View has not been shown");
236 return;
237 }
238
239 // Save bounds of window for when reshown
240 if (Debug.ON) {
241 Debug.assertTrue(rootpane.getParent() != null, "parent: " + rootpane.getParent());
242 }
243 view.setViewBounds(rootpane.getParent().getBounds());
244
245 hideRootPane(rootpane);
246 }
247
248
249 /***
250 * Hide all open Views.
251 */
252 public void hideAllViews() {
253 while (!rootpanes.isEmpty()) {
254 JRootPane rootpane = (JRootPane) rootpanes.getLast();
255 hideRootPane(rootpane);
256 }
257 }
258
259
260 /***
261 * Are there any Views left open?
262 *
263 * @return true if all views are closed
264 */
265 public boolean areAllViewsClosed() {
266 return (rootpanes.size() < 1);
267 }
268
269
270 // ----------------- Message boxes ----------------
271
272 /***
273 * Show an error message in a JOptionPane
274 *
275 * @param inErrorTitle The title for the error message
276 * @param inErrorMessage The error message
277 */
278 public void showError(final String inErrorTitle, final String inErrorMessage) {
279 if (LOG.isDebugEnabled()) {
280 LOG.debug("showError: " + inErrorTitle + ", " + inErrorMessage);
281 }
282
283 SwingUtil.runFromSwingEventThread(
284 new Runnable() {
285 public void run() {
286 if (LOG.isDebugEnabled()) {
287 LOG.debug("showError: " + inErrorTitle);
288 }
289 JOptionPane.showMessageDialog(getFocussedRootPane(), inErrorMessage, inErrorTitle,
290 JOptionPane.ERROR_MESSAGE);
291 }
292 });
293 }
294
295
296 /***
297 * Show a message in a JOptionPane
298 *
299 * @param inTitle The title for the message
300 * @param inMessage The message
301 */
302 public void showMessage(final String inTitle, final String inMessage) {
303 SwingUtil.runFromSwingEventThread(
304 new Runnable() {
305 public void run() {
306 JOptionPane.showMessageDialog(getFocussedRootPane(), inMessage, inTitle,
307 JOptionPane.INFORMATION_MESSAGE);
308 }
309 });
310 }
311
312
313 // protected Object showOKCancelWarning(final String inTitle, final String inMessage) {
314 // OKCancelOptionDialogShower s = new OKCancelOptionDialogShower(parentComponent, inTitle, inMessage,
315 // JOptionPane.WARNING_MESSAGE);
316 // Display.runFromSwingEventThread(s);
317 // return s.result;
318 // }
319 //
320 //
321 // protected Object showYesNoWarning(final String inTitle, final String inMessage) {
322 // YesNoOptionDialogShower s = new YesNoOptionDialogShower(parentComponent, inTitle, inMessage,
323 // JOptionPane.WARNING_MESSAGE);
324 // Display.runFromSwingEventThread(s);
325 // return s.result;
326 // }
327
328
329 /***
330 * Exit the application
331 */
332 public void exit() {
333 hideAllViews();
334 // default Swing operation
335 System.exit(0);
336 }
337
338
339 /***
340 * Start a progress indicator to notify the user that a long operation is
341 * running. <br>
342 * In the SwingContext, the progress indicator is a wait cursor, and it is
343 * displayed after a delay of n milliseconds defined in the Scope property
344 * 'org.scopemvc.controller.swing.SwingContext.progress_start_delay'
345 */
346 public void startProgress() {
347 if (task != null) {
348 task.cancel();
349 }
350 task =
351 new TimerTask() {
352 public void run() {
353 getDefaultParentWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
354 }
355 };
356 progressStartTimer.schedule(task, PROGRESS_START_DELAY);
357 }
358
359
360 /***
361 * Stop the progress indicator
362 */
363 public void stopProgress() {
364 if (task != null) {
365 task.cancel();
366 }
367 getDefaultParentWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
368 }
369
370
371 // ------------------------------------ Menu handling ------------------------------
372
373 /***
374 * Hook a menu item to a view. <br>
375 * The view and its bound controller will receive the Controls issued by the
376 * menu item.
377 *
378 * @param inView the view to hook the menu item to.
379 * @param inControlID The control ID used to identity the menu item
380 * @param inEnabled Set to true to enable the menu item
381 */
382 public void hookMenuItem(SwingView inView, String inControlID, boolean inEnabled) {
383 SMenuItem item = findMenuItem(inView, inControlID);
384 if (item == null) {
385 LOG.error("Can't find menuitem for: " + inControlID, new Throwable());
386 return;
387 }
388
389 item.setOwner(inView);
390 item.setEnabled(inEnabled);
391 }
392
393
394 /***
395 * Get the frame used as default parent for the views. <br>
396 * This frame uses the default application icon.
397 *
398 * @return The sharedNullFrame value
399 */
400 protected Frame getSharedNullFrame() {
401 if (sharedNullFrame == null) {
402 try {
403 sharedNullFrame = new NullFrame();
404 sharedNullFrame.setIconImage(getDefaultWindowIcon());
405 AWTUtilities.centreOnScreen(sharedNullFrame);
406 } catch (UnsupportedOperationException ignore) {
407 // thrown by JDK 1.4
408 }
409 }
410 return sharedNullFrame;
411 }
412
413
414 /***
415 * Get the default icon. <br>
416 * The icon is initialised from the property
417 * 'org.scopemvc.controller.swing.SwingContext.window_icon' defined in the
418 * Scope configuration. This property should contain the location of the
419 * icon resource. The icon is loaded with the ResourceLoader.
420 *
421 * @return The defaultWindowIcon value
422 * @see org.scopemvc.util.ResourceLoader
423 */
424 protected Image getDefaultWindowIcon() {
425 String iconPath = ScopeConfig.getString("org.scopemvc.controller.swing.SwingContext.window_icon");
426 if (iconPath == null || iconPath.length() < 1) {
427 return null;
428 }
429 try {
430 return ResourceLoader.getImage(iconPath);
431 } catch (RuntimeException e) {
432 LOG.warn("getDefaultWindowIconPath: (" + iconPath + ")", e);
433 return null;
434 }
435 }
436
437
438 /***
439 * Find the rootpane that currently contains the focussed component, or null
440 * if none.
441 *
442 * @return The focussedRootPane value
443 */
444 protected JRootPane getFocussedRootPane() {
445 for (Iterator i = rootpanes.iterator(); i.hasNext(); ) {
446 Object o = i.next();
447 if (Debug.ON) {
448 Debug.assertTrue(o instanceof JRootPane, "not JRootPane: " + o.getClass());
449 }
450 JRootPane r = (JRootPane) o;
451 Container w = r.getParent();
452 if (Debug.ON) {
453 Debug.assertTrue(w instanceof Window, "not Window: " + w.getClass());
454 }
455 if (isFocusOwner((Window) w)) {
456 return r;
457 }
458 }
459 return null;
460 }
461
462
463 /***
464 * <p>
465 *
466 * Returns true if the window owns the focus. </p> <p>
467 *
468 * Swing loses focus from the current component when a menu is pulled down
469 * so for a Window to have focus we say it needs to either contain the focus
470 * owner OR parent a Window (not a Dialog/Frame) that owns the focus.</p>
471 *
472 * @param inWindow The Window to test for focus
473 * @return True if the window or one of its child owns the focus
474 */
475 protected boolean isFocusOwner(Window inWindow) {
476 if (inWindow.getFocusOwner() != null) {
477 return true;
478 }
479 Window[] children = inWindow.getOwnedWindows();
480 if (children == null) {
481 return false;
482 }
483 for (int i = 0; i < children.length; i++) {
484 Window child = children[i];
485 if (child instanceof Dialog || child instanceof Frame) {
486 continue;
487 }
488 if (isFocusOwner(child)) {
489 return true;
490 }
491 }
492 return false;
493 }
494
495
496 /***
497 * For dialogs to be opened, find the currently focussed window, or if none,
498 * the last opened window or if none, the shared null Frame.
499 *
500 * @return The defaultParentWindow value
501 */
502 protected Window getDefaultParentWindow() {
503
504 // The currently focussed window
505 JRootPane r = getFocussedRootPane();
506 if (r != null) {
507 Container c = r.getParent();
508 if (Debug.ON) {
509 Debug.assertTrue(c instanceof Window, "not Window: " + c.getClass());
510 }
511 return (Window) c;
512 }
513
514 // if no open windows, the shared null frame
515 if (rootpanes.size() == 0) {
516 if (LOG.isDebugEnabled()) {
517 LOG.debug("null frame");
518 }
519 return getSharedNullFrame();
520 }
521
522 // the last opened window
523 if (Debug.ON) {
524 Debug.assertTrue(rootpanes.getLast() instanceof JRootPane);
525 }
526 if (LOG.isDebugEnabled()) {
527 LOG.debug("last shown frame: " + (Window) ((JRootPane) rootpanes.getLast()).getParent());
528 }
529 return (Window) ((JRootPane) rootpanes.getLast()).getParent();
530 }
531
532
533 /***
534 * Finds the topmost Container, stopping before any Window structure.
535 *
536 * @param inView The View to get the topmost Container from
537 * @return The topmost Container
538 */
539 protected Container getTopmostContainer(SwingView inView) {
540
541 // Already in a JRootPane? Then find the content pane so we know when to stop below
542 Container contentPane = null;
543 JRootPane parentRootpane = inView.getRootPane();
544 if (parentRootpane != null) {
545 contentPane = parentRootpane.getContentPane();
546 }
547
548 Container result = inView;
549 while (result.getParent() != null && result.getParent() != contentPane) {
550 result = result.getParent();
551 }
552 return result;
553 }
554
555
556 /***
557 * Setup the window: insert the view in the window, setup the title and the
558 * menubar in the window and position the window on the screen.
559 *
560 * @param inRootPane The RootPane where to add the View
561 * @param inView The View to setup
562 * @param inCentreWindow If true, centre the window on the screen or on its
563 * parent window
564 */
565 protected void setupWindow(JRootPane inRootPane, SwingView inView, boolean inCentreWindow) {
566
567 Container c = inRootPane.getParent();
568 if (Debug.ON) {
569 Debug.assertTrue(c instanceof Window, "not Window: " + c.getClass());
570 }
571 final Window window = (Window) c;
572
573 // Keep track of the new RootPane
574 rootpanes.add(inRootPane);
575
576 // Put the View in the content pane
577 inRootPane.getContentPane().setLayout(new BorderLayout());
578 inRootPane.getContentPane().add(BorderLayout.CENTER, inView);
579
580 // Attach the View's menubar to the dialog
581 inRootPane.setJMenuBar(inView.getMenuBar());
582
583 // Restore last bounds of this View
584 Rectangle lastShownBounds = inView.getViewBounds();
585 if (lastShownBounds == null) {
586 window.pack();
587 if (inCentreWindow) {
588 if (Debug.ON) {
589 Debug.assertTrue(window.getParent() instanceof Window, "no window parent");
590 }
591 AWTUtilities.centreOnWindow((Window) window.getParent(), window);
592 }
593 } else if (lastShownBounds == SwingView.CENTRED) {
594 window.pack();
595 AWTUtilities.centreOnScreen(window);
596 } else {
597 window.setBounds(lastShownBounds);
598 }
599 // If too big for screen, adjust
600 AWTUtilities.fitOnScreen(window);
601
602 // WindowCloser to issue close Control
603 window.addWindowListener(new WindowCloser(inView));
604 // Don't let Swing handle the window close. Nasty... Swing needs an interface here
605 if (window instanceof JFrame) {
606 ((JFrame) window).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
607 } else if (window instanceof JDialog) {
608 ((JDialog) window).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
609 }
610
611 // Display safely from event queue
612 SwingUtil.runFromSwingEventThread(
613 new Runnable() {
614 public void run() {
615 window.setVisible(true);
616 }
617 });
618 }
619
620
621 /***
622 * Find the Rootpane that contains the SwingView or null if none can be
623 * found.
624 *
625 * @param inView The View to get the RootPane from
626 * @return The parent RootPane, or null
627 */
628 protected JRootPane findRootPaneFor(View inView) {
629 if (LOG.isDebugEnabled()) {
630 LOG.debug("findRootPaneFor: " + inView);
631 }
632 if (Debug.ON) {
633 Debug.assertTrue(inView instanceof JComponent, "not JComponent: " + inView.getClass().getName());
634 }
635 for (Iterator i = rootpanes.iterator(); i.hasNext(); ) {
636 Object o = i.next();
637 if (LOG.isDebugEnabled()) {
638 LOG.debug("findRootPaneFor: looking at: " + o);
639 }
640 if (Debug.ON) {
641 Debug.assertTrue(o instanceof JRootPane, "not JRootPane: " + o.getClass());
642 }
643 JRootPane r = (JRootPane) o;
644 if (r.isAncestorOf((JComponent) inView)) {
645 if (LOG.isDebugEnabled()) {
646 LOG.debug("findRootPaneFor: got it");
647 }
648 return r;
649 }
650 }
651 if (LOG.isDebugEnabled()) {
652 LOG.debug("findRootPaneFor: not found");
653 }
654 return null;
655 }
656
657
658 /***
659 * Hide the root pane and dispose of the parent window.
660 *
661 * @param inRootPane The RootPane to hide
662 */
663 protected void hideRootPane(JRootPane inRootPane) {
664 rootpanes.remove(inRootPane);
665 Container window = inRootPane.getParent();
666 if (window == sharedNullFrame) {
667 sharedNullFrame = null;
668 }
669
670 if (Debug.ON) {
671 Debug.assertTrue(window instanceof Window, "not Window: " + window);
672 }
673 hideWindow((Window) window);
674 if (areAllViewsClosed() && sharedNullFrame != null) {
675 hideWindow(sharedNullFrame);
676 sharedNullFrame = null;
677 }
678 }
679
680 /***
681 * Hide the window safely from the Swing event thread.
682 *
683 * @param window The window to close
684 */
685 protected void hideWindow(final Window window) {
686 SwingUtil.runFromSwingEventThread(
687 new Runnable() {
688 public void run() {
689 window.dispose();
690 }
691 });
692 }
693
694 /***
695 * Make a dialog (modal or modeless determined by {@link
696 * org.scopemvc.view.swing.SwingView#getDisplayMode the display mode})
697 * parented to either currently focussed window, or last shown, or null
698 * shared frame.
699 *
700 * @param inView The View to show
701 */
702 protected void showViewInDialog(SwingView inView) {
703
704 // Make a JDialog to contain the view.
705 Window parentWindow = getDefaultParentWindow();
706 if (Debug.ON) {
707 Debug.assertTrue(parentWindow != null, "null parentWindow");
708 }
709
710 final JDialog dialog;
711 if (parentWindow instanceof Dialog) {
712 dialog = new JDialog((Dialog) parentWindow);
713 } else {
714 if (Debug.ON) {
715 Debug.assertTrue(parentWindow instanceof Frame);
716 }
717 dialog = new JDialog((Frame) parentWindow);
718 }
719
720 // Set title, modality, resizability
721 if (inView.getTitle() != null) {
722 dialog.setTitle(inView.getTitle());
723 }
724 if (inView.getDisplayMode() == SwingView.MODAL_DIALOG) {
725 dialog.setModal(true);
726 } else {
727 dialog.setModal(false);
728 }
729 dialog.setResizable(inView.isResizable());
730
731 setupWindow(dialog.getRootPane(), inView, true);
732 }
733
734
735 /***
736 * Show the view in a new frame
737 *
738 * @param inView The View to show
739 */
740 protected void showViewInPrimaryWindow(SwingView inView) {
741
742 // Make a JFrame to contain the view
743 final JFrame frame = new JFrame();
744
745 // Set its title, icon, resizability
746 if (inView.getTitle() != null) {
747 frame.setTitle(inView.getTitle());
748 }
749 // All JFrames take the same icon
750 Image icon = getDefaultWindowIcon();
751 if (icon != null) {
752 frame.setIconImage(icon);
753 }
754 frame.setResizable(inView.isResizable());
755
756 setupWindow(frame.getRootPane(), inView, false);
757 }
758
759
760 /***
761 * Unhook a menu item from a view.
762 *
763 * @param inView the view where the menu item was hooked to.
764 * @param inControlID The control ID used to identity the menu item
765 */
766 protected void unhookMenuItemImpl(String inControlID, SwingView inView) {
767 SMenuItem item = findMenuItem(inView, inControlID);
768 if (item == null) {
769 LOG.error("Can't find menuitem for: " + inControlID, new Throwable());
770 return;
771 }
772
773 item.unsetOwner(inView);
774 }
775
776
777 /***
778 * Find the SMenuItem in the menu bar associated with the frame of the view.
779 *
780 * @param inView A view contained in a frame containing a menubar
781 * @param inControlID The control ID of the menu item to find
782 * @return The SMenuItem matching the control ID, or null
783 */
784 protected SMenuItem findMenuItem(SwingView inView, String inControlID) {
785 JRootPane rootPane = findRootPaneFor(inView);
786 if (rootPane == null) {
787 return null;
788 }
789
790 JMenuBar menuBar = rootPane.getJMenuBar();
791 if (menuBar == null) {
792 return null;
793 }
794
795 for (int i = 0; i < menuBar.getMenuCount(); i++) {
796 JMenu menu = menuBar.getMenu(i);
797 SMenuItem result = findMenuItemInMenu(menu, inControlID);
798 if (result != null) {
799 return result;
800 }
801 }
802 return null;
803 }
804
805
806 static class NullFrame extends Frame {
807 /***
808 * Sets the visible attribute
809 *
810 * @param inVisible The new visible value
811 */
812 public void setVisible(boolean inVisible) {
813 // Don't ever show!
814 }
815 }
816
817
818 // ----------------- Show/hide Views ----------------
819
820 /***
821 * Attached to windows opened by this manager so that they issue a Control
822 * on closing.
823 *
824 * @author smefroy
825 * @created 05 August 2002
826 */
827 static class WindowCloser extends WindowAdapter {
828 private SwingView view;
829
830 /***
831 * Constructor for the WindowCloser object
832 *
833 * @param inView The View to watch for close events.
834 */
835 WindowCloser(SwingView inView) {
836 view = inView;
837 }
838
839 /***
840 * Notifies that the Window is closing
841 *
842 * @param e the Window event
843 */
844 public void windowClosing(WindowEvent e) {
845 view.issueControl(view.getCloseControl());
846 }
847 }
848 }
This page was automatically generated by Maven