2
* @(#)WindowPresentation.java 1.22 06/10/30
4
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7
* This code is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License version 2 only, as
9
* published by the Free Software Foundation. Sun designates this
10
* particular file as subject to the "Classpath" exception as provided
11
* by Sun in the LICENSE file that accompanied this code.
13
* This code is distributed in the hope that it will be useful, but WITHOUT
14
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16
* version 2 for more details (a copy is included in the LICENSE file that
17
* accompanied this code).
19
* You should have received a copy of the GNU General Public License version
20
* 2 along with this work; if not, write to the Free Software Foundation,
21
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
24
* CA 95054 USA or visit www.sun.com if you need additional information or
30
import javax.swing.JDialog;
31
import javax.swing.JFrame;
32
import javax.swing.SwingUtilities;
33
import java.awt.Component;
34
import java.awt.Dialog;
35
import java.awt.Dimension;
37
import java.awt.Frame;
38
import java.awt.GraphicsConfiguration;
39
import java.awt.GraphicsDevice;
40
import java.awt.GraphicsEnvironment;
41
import java.awt.Image;
42
import java.awt.MenuComponent;
43
import java.awt.Point;
44
import java.awt.Rectangle;
45
import java.awt.Window;
46
import java.awt.event.WindowAdapter;
47
import java.awt.event.WindowEvent;
48
import java.awt.event.WindowListener;
49
import java.beans.PropertyChangeEvent;
50
import java.beans.PropertyChangeListener;
51
import java.lang.reflect.Method;
53
import java.util.Enumeration;
54
import java.util.Locale;
55
import javax.swing.ImageIcon;
58
* Window Presentation is an abstract class providing a generic interface for
59
* the development of Window Presentations. Each implementation of
60
* Presentation will need to override the static method getPresentation
61
* according to it's own needs.
63
* WindowPresentation implements several generic methods required in all
64
* window presentations. Includes the ability to handle modal and non-modal
65
* activation of the help window.
67
* @author Roger D.Brinkley
68
* @version 1.22 10/30/06
71
* @see javax.help.HelpSet
72
* @see javax.help.JHelpNavigator
73
* @see javax.help.HelpVisitListener
76
public abstract class WindowPresentation extends Presentation {
78
private HelpSet.Presentation hsPres=null;
79
private JFrame frame = null;
80
private JHelp jhelp = null;
81
private JDialog dialog = null;
82
private Window ownerWindow = null;
83
private boolean modallyActivated = false;
84
private Point location = null;
85
private String title = null;
86
private Image image = null;
87
private String currentView = null;
88
private boolean viewDisplayed = true;
89
private boolean toolbarDisplayed = true;
90
private boolean destroyOnExit = false;
91
private boolean titleFromDocument = false;
92
private WindowPropertyChangeListener propertyChangeListener = null;
93
private int screen = 0;
95
public WindowPresentation (HelpSet hs) {
100
* Set the Presentation attributes specific to WindowPresentations from a
101
* named presentation in a HelpSet.
103
* @params hsPres - the HelpSet.Presentation to retrieve the presentation
106
* @see HelpSet.Presentation
108
public void setHelpSetPresentation (HelpSet.Presentation hsPres) {
109
debug("setHelpSetPrsentation");
110
if (hsPres == null) {
114
// make sure the underlying presentation attributes are set
115
super.setHelpSetPresentation(hsPres);
117
// get the presentation location
118
Point location = hsPres.getLocation();
119
if (location != null) {
120
setLocation(location);
124
String title = hsPres.getTitle();
130
javax.help.Map.ID imageID = hsPres.getImageID();
131
if (imageID != null) {
132
ImageIcon icon = null;
134
javax.help.Map map = getHelpSet().getCombinedMap();
135
URL url = map.getURLFromID(imageID);
136
icon = new ImageIcon(url);
137
image = icon.getImage();
138
} catch (Exception e) {
142
if (hsPres.isToolbar()) {
143
setToolbarDisplayed(true);
146
if (hsPres.isViewDisplayed()) {
147
setViewDisplayed(true);
150
this.hsPres = hsPres;
154
* Return the HelpSet.Presentation if one was set
155
* @returns HelpSet.Presentation - the HelpSet.Presentation used in this
158
* @see HelpSet.Presentation
160
public HelpSet.Presentation getHelpSetPresentation() {
165
* Get the activation window.
167
* @returns Window - the activation window if activatated from a modal
168
* modal dialog, otherwise null.
170
public Window getActivationWindow() {
171
debug("getActivationWindow");
176
* Set the activation window. If the window is an instance of a
177
* Dialog and the is modal, modallyActivated help is set to true and
178
* ownerDialog is set to the window. In all other instances
179
* modallyActivated is set to false and ownerDialog is set to null.
180
* @param window the activating window
182
public void setActivationWindow(Window window) {
183
debug("setActivationWindow");
184
if (window != null && window instanceof Dialog) {
185
Dialog tmpDialog = (Dialog) window;
186
if (tmpDialog.isModal()) {
187
ownerWindow = window;
188
modallyActivated = true;
191
modallyActivated = false;
195
modallyActivated = false;
200
* Set the activation window from given Component or MenuItem. It find Window component
201
* in the component tree from given Component or MenuItem end call
202
* <pre>setActivationWindow</pre>.
203
* @parem comp the activation Component or MenuItem
206
* @see setActivationWindow
208
public void setActivationObject(Object comp) {
209
debug("setActivationObject");
210
while (comp instanceof MenuComponent) {
211
comp = ((MenuComponent)comp).getParent();
215
if (comp instanceof Frame) {
216
owner = (Window)comp;
217
} else if (comp instanceof Component) {
218
owner = SwingUtilities.windowForComponent((Component)comp);
221
setActivationWindow(owner);
225
* Determines the current navigator.
227
public String getCurrentView() {
228
debug("getCurrentView");
229
// always use the current view if the jhelp exists.
231
currentView = jhelp.getCurrentNavigator().getNavigatorName();
238
* Set the currentView to the navigator with the same
239
* name as the <tt>name</tt> parameter.
241
* @param name The name of the navigator to set as the
242
* current view. If nav is null or not a valid Navigator
243
* in this WindowPresentation then an
244
* IllegalArgumentException is thrown.
245
* @throws IllegalArgumentException if nav is null or not a valid Navigator.
247
public void setCurrentView(String name) {
248
debug("setCurrentView");
249
// if the jhelp already exists then set the currentview
252
JHelpNavigator nav = getNavigatorByName(name);
255
throw new IllegalArgumentException("Invalid view name");
257
jhelp.setCurrentNavigator(nav);
259
// jhelp didn't exist so make sure view is in HelpSet
260
HelpSet hs = getHelpSet();
261
NavigatorView view = hs.getNavigatorView(name);
263
throw new IllegalArgumentException("Invalid view name");
270
* Internal method to return a Navigator by name from a jhelp
272
private JHelpNavigator getNavigatorByName(String name) {
273
JHelpNavigator nav = null;
275
for (Enumeration e = jhelp.getHelpNavigators();
276
e.hasMoreElements(); ) {
277
nav = (JHelpNavigator) e.nextElement();
278
if (nav.getNavigatorName().equals(name)) {
289
* Determines if the presentation should be distroyed on exit
291
public boolean isDestroyedOnExit() {
292
debug("isDestoryedOnExit");
293
return destroyOnExit;
297
* Destory the window on exit
299
public void setDestroyOnExit(boolean destroy) {
300
debug("setDestoryOnExit");
301
destroyOnExit = destroy;
305
* Destroy this object. Implementation of WindowPresentation that
306
* maintian a list of objects should override this method and call
307
* super.destroy to clear up the WindowPresentation internal fields.
309
public void destroy() {
317
propertyChangeListener = null;
322
* Changes the HelpSet for this presentation.
323
* @param hs The HelpSet to set for this presentation.
324
* A null hs is valid parameter.
326
public void setHelpSet(HelpSet hs) {
329
HelpSet helpset = super.getHelpSet();
330
// If we already have a model check if the HelpSet has changed.
331
// If so change the model
332
// This could be made smarter to cache the helpmodels per HelpSet
333
if (hs != null && helpset != hs) {
334
super.setHelpSet(hs);
336
jhelp.setModel(super.getHelpModel());
342
* Displays the presentation to the user.
344
public void setDisplayed(boolean b) {
345
debug ("setDisplayed");
346
// if the jhelp is null and they don't want it displayed just return
347
if (jhelp == null && !b) {
351
// The call to createHelpWindow is necessary as the modality
352
// might have been changed and we need to change from a dialog
353
// to a frame. This is only done in createHelpWindow.
355
if (modallyActivated) {
364
// We should be able to just
366
// frame.setState(Frame.NORMAL)
367
// } catch (NoSuchMethodError ex) {
369
// but IE4.0 barfs very badly at this
373
Class types[] = {Integer.TYPE};
374
Method m = Frame.class.getMethod("setState", types);
377
Object args[] = {new Integer(0)}; // Frame.NORMAL
378
m.invoke(frame, args);
380
} catch (NoSuchMethodError ex) {
382
} catch (NoSuchMethodException ex) {
384
} catch (java.lang.reflect.InvocationTargetException ex) {
386
} catch (java.lang.IllegalAccessException ex) {
393
* Determines if the presentation is displayed.
395
public boolean isDisplayed() {
396
debug ("isDisplayed");
400
if (modallyActivated) {
401
if (dialog != null) {
402
return dialog.isShowing();
408
if (! frame.isShowing()) {
412
// We should be able to just
414
// return (frame.getState() == Frame.NORMAL)
415
// } catch (NoSuchMethodError ex) {
417
// but IE4.0 barfs very badly at this
421
Method m = Frame.class.getMethod("getState",
422
(java.lang.Class[]) null);
425
int value =((Integer)(m.invoke(frame,
426
(java.lang.Object[])null))).intValue();
433
} catch (NoSuchMethodError ex) {
435
} catch (NoSuchMethodException ex) {
437
} catch (java.lang.reflect.InvocationTargetException ex) {
439
} catch (java.lang.IllegalAccessException ex) {
442
// On 1.1 I can't tell if it's raised or not.
443
// It's on the screen so true.
453
* Sets the font for this this WindowPresentation.
456
public void setFont (Font f) {
459
if (jhelp != null && f != null) {
465
* Gets the font for this WindowPresentation
467
public Font getFont() {
469
Font font = super.getFont();
474
return jhelp.getFont();
480
* Sets the locale of this Presentation. The locale is propagated to
482
* @param l The locale to become this component's locale. A null locale
483
* is the same as the defaultLocale.
486
public void setLocale(Locale l) {
496
* internal method to test for Xinerama mode
498
private boolean isXinerama () {
499
GraphicsEnvironment ge =
500
GraphicsEnvironment.getLocalGraphicsEnvironment();
501
GraphicsDevice[] gds = ge.getScreenDevices();
502
if (gds.length == 1) {
505
for (int i=0; i<gds.length; i++) {
506
GraphicsConfiguration loopgc =
507
gds[i].getDefaultConfiguration();
508
Rectangle bounds = loopgc.getBounds();
509
if (bounds.x != 0 || bounds.y !=0) {
518
* Requests the location of the presentation.
520
* @returns Point the location of the presentation.
522
public Point getLocation() {
523
debug("getLocation");
524
if (location != null && jhelp == null) {
530
if (modallyActivated) {
531
Point dlocation = dialog.getLocation();
533
GraphicsConfiguration gc = dialog.getGraphicsConfiguration();
534
Rectangle gcBounds = gc.getBounds();
535
return new Point(dlocation.x - gcBounds.x,
536
dlocation.y - gcBounds.y);
540
Point flocation = frame.getLocation();
542
GraphicsConfiguration gc = frame.getGraphicsConfiguration();
543
Rectangle gcBounds = gc.getBounds();
544
return new Point(flocation.x - gcBounds.x,
545
flocation.y - gcBounds.y);
552
* Requests the presentation be located at a given position.
554
public void setLocation(Point p) {
555
debug("setLocation");
560
if (modallyActivated) {
561
if (dialog != null) {
562
GraphicsConfiguration gc =
563
dialog.getGraphicsConfiguration();
564
Rectangle gcBounds = gc.getBounds();
565
Point loc = new Point (gcBounds.x + p.x,
567
dialog.setLocation(loc);
571
GraphicsConfiguration gc =
572
frame.getGraphicsConfiguration();
573
Rectangle gcBounds = gc.getBounds();
574
Point loc = new Point (gcBounds.x + p.x,
576
frame.setLocation(loc);
583
* Requests the screen of the presentation
584
* @returns int the screen of the presentation
586
public int getScreen() {
588
// If there is no jhelp componet then it hasn't been "realized"
589
// yet so just return the screen
594
// Help is showing so get the screen from the presentation
595
GraphicsConfiguration gc = null;
596
if (modallyActivated) {
597
if (dialog != null) {
598
gc = dialog.getGraphicsConfiguration();
602
gc = frame.getGraphicsConfiguration();
606
GraphicsDevice device = gc.getDevice();
607
GraphicsEnvironment ge =
608
GraphicsEnvironment.getLocalGraphicsEnvironment();
609
GraphicsDevice[] gs = ge.getScreenDevices();
610
for (int i=0; i < gs.length; i++) {
611
if (gs[i] == device) {
622
* Sets the screen of the presentation
623
* @param screen the screen number
624
* @throws IllegalArgumentException if the screen is invalid
626
public void setScreen(int screen) {
629
if (screen == this.screen) {
630
// There is nothing to do as it is either already the screen
636
throw new IllegalArgumentException("Invalid screen");
639
GraphicsEnvironment ge =
640
GraphicsEnvironment.getLocalGraphicsEnvironment();
641
GraphicsDevice[]gs = ge.getScreenDevices();
643
// make sure there is a screen device
644
if (gs.length <= screen) {
645
throw new IllegalArgumentException ("Invalid Screen");
648
this.screen = screen;
652
boolean xinerama = isXinerama();
654
GraphicsDevice gd = gs[screen];
655
GraphicsConfiguration gc = gd.getDefaultConfiguration();
656
Rectangle gcBounds = gc.getBounds();
657
if (modallyActivated) {
658
if (dialog != null) {
660
Point p = getLocation();
661
Point loc = new Point (gcBounds.x + p.x,
663
dialog.setLocation(loc);
665
location = getLocation();
674
Point p = getLocation();
675
Point loc = new Point (gcBounds.x + p.x,
677
frame.setLocation(loc);
679
location = getLocation();
680
frame.setVisible(false);
690
* Requests the size of the presentation.
691
* @returns Point the location of the presentation.
693
public Dimension getSize() {
695
// if the jhelp is created then just use the current sizes
697
if (modallyActivated) {
698
if (dialog != null) {
699
return dialog.getSize();
703
return frame.getSize();
707
return super.getSize();
711
* Requests the presentation be set to a given size. Updates the
712
* the presentation on the fly. This is an override of
713
* Presentation.SetSize.
715
public void setSize(Dimension d) {
719
if (modallyActivated) {
729
public String getTitle() {
732
// if the title comes from the document use that first if
734
if (titleFromDocument && jhelp != null) {
735
String docTitle = jhelp.getContentViewer().getDocumentTitle();
736
if (docTitle != null) {
741
// otherwise use the title that has been set...
745
// Unless there wasn't a title set and then use the HelpSet
747
HelpSet hs = getHelpSet();
749
title = hs.getTitle();
755
public void setTitle(String title) {
759
if (modallyActivated) {
760
dialog.setTitle(title);
763
frame.setTitle(title);
771
* Is the title set from the Document. This is generally useful
772
* in SecondaryWindows.
773
* @return boolean True if title is set from the Document, false otherwise.
775
public boolean isTitleSetFromDocument() {
776
debug("isTitleSetFromDocument");
777
return titleFromDocument;
781
* Set the title from the Document.
782
* @param b if true will set the title form the document, otherwise will
783
* set the title from the HelpSet.
785
public void setTitleFromDocument(boolean b) {
786
debug("setTitleFromDocument");
787
if (titleFromDocument != b) {
788
titleFromDocument = b;
789
if (titleFromDocument) {
790
propertyChangeListener = new WindowPropertyChangeListener();
792
jhelp.getContentViewer().
793
addPropertyChangeListener("page",
794
propertyChangeListener);
798
jhelp.getContentViewer().
799
removePropertyChangeListener("page",
800
propertyChangeListener);
807
* Determines if the current view is visible.
809
public boolean isViewDisplayed() {
810
debug ("isViewDisplayed");
812
return jhelp.isNavigatorDisplayed();
814
return viewDisplayed;
820
public void setViewDisplayed(boolean displayed) {
821
debug ("setViewDisplayed");
823
jhelp.setNavigatorDisplayed(displayed);
825
viewDisplayed = displayed;
829
* Determines if the toolbar is visible.
831
public boolean isToolbarDisplayed() {
832
debug ("isToolbarDisplayed");
834
return jhelp.isToolbarDisplayed();
836
return toolbarDisplayed;
840
* Hides/Shows Toolbar
842
public void setToolbarDisplayed(boolean displayed) {
843
debug ("setToolbarDisplayed=" + displayed);
845
jhelp.setToolbarDisplayed(displayed);
847
toolbarDisplayed = displayed;
850
private synchronized void createJHelp() {
851
debug ("createJHelp");
853
jhelp = new JHelp(getHelpModel(), null, getHelpSetPresentation());
854
Font font = super.getFont();
858
Locale locale = getLocale();
859
if (locale != null) {
860
jhelp.setLocale(locale);
862
jhelp.setToolbarDisplayed(toolbarDisplayed);
863
jhelp.setNavigatorDisplayed(viewDisplayed);
864
if (currentView != null) {
865
JHelpNavigator nav = getNavigatorByName(currentView);
867
jhelp.setCurrentNavigator(nav);
870
if (titleFromDocument) {
871
jhelp.getContentViewer().
872
addPropertyChangeListener("page", propertyChangeListener);
878
boolean modalDeactivated = true;
880
public synchronized void createHelpWindow() {
881
debug ("createHelpWindow");
882
// pos is used for determining the screen adjust location of a
883
// dialog or frame that already exist. This should only be used
884
// when a switch is required. If it is null this is a creation.
886
Dimension size = getSize();
887
JDialog tmpDialog = null;
892
// The graphics variables below are only used during the initial
893
// creation. If there is a modality change then the actual position
894
// of the Window would be used instead.
895
GraphicsEnvironment ge =
896
GraphicsEnvironment.getLocalGraphicsEnvironment();
897
GraphicsDevice[] gds = ge.getScreenDevices();
898
GraphicsDevice gd = gds[screen];
899
GraphicsConfiguration gc = gd.getDefaultConfiguration();
900
Rectangle gcBounds = gc.getBounds();
902
if (modallyActivated) {
903
// replace dialog.getOwner() with the following code
906
Method m = Window.class.getMethod("getOwner",
907
(java.lang.Class[]) null);
909
if (m != null && dialog != null) {
910
owner = (Window) m.invoke(dialog,
911
(java.lang.Class[]) null);
913
} catch (NoSuchMethodError ex) {
915
} catch (NoSuchMethodException ex) {
917
} catch (java.lang.reflect.InvocationTargetException ex) {
919
} catch (java.lang.IllegalAccessException ex) {
923
if (dialog == null || owner != ownerWindow || modalDeactivated) {
925
// pos is already screen adjusted
926
pos = frame.getLocation();
927
size = frame.getSize();
930
if (dialog != null) {
931
// pos is already screen adjusted
932
pos = dialog.getLocation();
933
size = dialog.getSize();
936
dialog = new JDialog((Dialog)ownerWindow, getTitle(),
939
// Modal dialogs are really tricky. When the modal dialog
940
// is dismissed the JDialog will be dismissed as well.
941
// When that happens we need to make sure the ownerWindow
942
// is set to null so that a new dialog will be created so
943
// that events aren't blocked in the HelpViewer.
944
dl = new WindowAdapter() {
945
public void windowClosing(WindowEvent e) {
946
debug ("modal window closing");
951
// JDK1.2.1 bug not closing owned windows
952
if (dialog.isShowing()) {
955
if (ownerWindow != null)
956
ownerWindow.removeWindowListener(dl);
958
modalDeactivated = true;
961
public void windowClosed(WindowEvent e) {
962
debug ("modal window closing");
969
debug ("adding windowlistener");
971
ownerWindow.addWindowListener(dl);
972
modalDeactivated = false;
974
dialog.setSize(size);
976
dialog.setSize(getSize());
979
// if the pos variable is not null then either a frame
980
// or a dialog already exists and you should use that position
981
// instead. If it is null then base the point on the location
982
// and screen or just the screen
984
dialog.setLocation(pos);
986
// set based on location and screen or just screen
988
if (location != null) {
990
loc = new Point (gcBounds.x + location.x,
991
gcBounds.y + location.y);
995
dialog.setLocation(loc);
998
dialog.setTitle(getTitle());
999
dialog.getContentPane().add(jhelp);
1000
if (tmpDialog != null) {
1006
if (frame == null) {
1007
frame = new JFrame(getTitle(), gc);
1009
WindowListener l = new WindowAdapter() {
1010
public void windowClosing(WindowEvent e) {
1011
if (destroyOnExit) {
1015
frame.setVisible(false);
1017
public void windowClosed(WindowEvent e) {
1018
frame.setVisible(false);
1019
if (destroyOnExit) {
1025
frame.addWindowListener(l);
1026
if (image != null) {
1027
frame.setIconImage(image);
1030
if (dialog != null) {
1031
// pos is already screen adjusted
1032
pos = dialog.getLocation();
1033
size = dialog.getSize();
1039
frame.setSize(size);
1041
frame.setSize(getSize());
1045
// if the pos variable is not null then either a frame
1046
// or a dialog already exists and you should use that position
1047
// instead. If it is null then base the point on the location
1048
// and screen or just the screen
1050
frame.setLocation(pos);
1052
// set based on location and screen or just screen
1054
if (location != null) {
1056
loc = new Point (gcBounds.x + location.x,
1057
gcBounds.y + location.y);
1061
frame.setLocation(loc);
1064
frame.getContentPane().add(jhelp);
1065
frame.setTitle(getTitle());
1071
* Get the current window that help is displayed in
1073
* @returns Window the current Window
1075
public Window getHelpWindow() {
1076
if (modallyActivated) {
1082
private class WindowPropertyChangeListener implements PropertyChangeListener {
1083
public void propertyChange(PropertyChangeEvent event) {
1084
String changeName = event.getPropertyName();
1085
if (changeName.equals("page")) {
1086
String title = getTitle();
1087
if (modallyActivated) {
1088
dialog.setTitle(title);
1090
frame.setTitle(title);
1100
private static final boolean debug = false;
1101
private static void debug(Object msg) {
1103
System.err.println("WindowPresentation: "+msg);