001: /*
002: * @(#)AbstractPage.java
003: *
004: * Copyright 2002 - 2003 JIDE Software. All rights reserved.
005: */
006: package com.jidesoft.dialog;
007:
008: import javax.swing.*;
009: import java.awt.*;
010:
011: /**
012: * AbstractPage is an abstract base class that provides functionality
013: * to defer populating a JPanel object until it is actually viewed.
014: * This is very useful when using CardLayout and tab panel
015: * views which have several pages. Delaying the construction means it will
016: * start up fast. Sometimes delay means never.
017: * <p/>
018: * If subclasses choose to override any of the following methods,
019: * it is their responsibility to ensure their overridden methods
020: * call the parent's method first. The methods are:
021: * <p/>
022: * <ul>
023: * <li>public void paint (Graphics)
024: * <li>public void paintComponents(Graphics)
025: * <li>public void paintAll (Graphics)
026: * <li>public void repaint ()
027: * <li>public void repaint (long)
028: * <li>public void repaint (int, int, int, int)
029: * <li>public void repaint (long, int, int, int, int)
030: * <li>public void update (Graphics)
031: * </ul>
032: * <p/>
033: * <p/>
034: * By default, if any of the methods is called, the panel will be
035: * populated. However user can setInvokeCondition() to customize
036: * when the panel be populated. See javadoc of setInvokeContion()
037: * for details.
038: * <p/>
039: * The idea of the lazy panel is from an article on JavaWorld at
040: * http://www.javaworld.com/javatips/jw-javatip90_p.html. The credit
041: * should be given to Mark Roulo. We modified the code he provided in
042: * the article to add additional things as we need. Things added are
043: * <ul>
044: * <li> Added setInvokeCondition()
045: * <li> Added addPageListener(), removePageListener() etc so that subclass can fire {@link PageEvent}
046: * </ul>
047: */
048: public abstract class AbstractPage extends JPanel implements Laziness {
049:
050: /**
051: * Used by setInvokeCondition(). This value means initialize
052: * will be called in all paint/repaint/update methods.
053: */
054: public static int INVOKE_ON_ALL = 0xFFFFFFFF;
055:
056: /**
057: * Used by setInvokeCondition(). This value means initialize
058: * will not be called. You have to call it manually.
059: */
060: public static int INVOKE_ON_NONE = 0x0;
061:
062: /**
063: * Used by setInvokeCondition(). This value means initialize
064: * will be called with paint() is called.
065: */
066: public static int INVOKE_ON_PAINT = 0x1;
067:
068: /**
069: * Used by setInvokeCondition(). This value means initialize
070: * will be called with repaint() is called.
071: */
072: public static int INVOKE_ON_REPAINT = 0x2;
073:
074: /**
075: * Used by setInvokeCondition(). This value means initialize
076: * will be called with update() is called.
077: */
078: public static int INVOKE_ON_UPDATE = 0x4;
079:
080: /**
081: * Used by setInvokeCondition(). This value means initialize
082: * will be called with invalidate(), revalidate() is called.
083: */
084: public static int INVOKE_ON_VALIDATE = 0x8;
085:
086: private boolean _allowClosing = true;
087:
088: private int _invokeCondition = INVOKE_ON_PAINT | INVOKE_ON_REPAINT
089: | INVOKE_ON_UPDATE;
090: /**
091: * Only one <code>DataChangeEvent</code> is needed per model instance
092: * since the event's only (read-only) state is the source property.
093: * The source of events generated here is always "this".
094: */
095: protected transient PageEvent _pageEvent = null;
096:
097: // We want to call the lazyConstructor only once.
098: private boolean _lazyConstructorCalled = false;
099:
100: // Some versions of Swing called paint() before
101: // the components were added to their containers.
102:
103: /**
104: * Creates an AbstractPage.
105: */
106: protected AbstractPage() {
107: }
108:
109: /**
110: * Gets the invoke condition. Invoke condition defines how lazy the
111: * page is. By default, the lazyInitialize() will be called on any update,
112: * paint or repaint method. However you can change the invoke condition to
113: * INVOKE_ON_PAINT. If so, lazyInitialize() will be called only when paint()
114: * method is called. You can even set the invoke condition to INVOKE_ON_NONE.
115: * If so, you will be responsible to call lazyInitialize() since none of those methods
116: * methods mentioned above will call lazyInitialize().
117: *
118: * @return the invocation condition
119: */
120: public int getInvokeCondition() {
121: return _invokeCondition;
122: }
123:
124: /**
125: * Sets the invoke condition.
126: *
127: * @param invokeCondition the invoke condition.
128: */
129: public void setInvokeCondition(int invokeCondition) {
130: _invokeCondition = invokeCondition;
131: }
132:
133: @Override
134: public void invalidate() {
135: if ((getInvokeCondition() & INVOKE_ON_VALIDATE) != 0) {
136: initialize();
137: }
138: super .invalidate();
139: }
140:
141: @Override
142: public void revalidate() {
143: if ((getInvokeCondition() & INVOKE_ON_VALIDATE) != 0) {
144: initialize();
145: }
146: super .revalidate();
147: }
148:
149: @Override
150: public void paint(Graphics g) {
151: if ((getInvokeCondition() & INVOKE_ON_PAINT) != 0) {
152: initialize();
153: }
154:
155: super .paint(g);
156: }
157:
158: @Override
159: public void paintAll(Graphics g) {
160: if ((getInvokeCondition() & INVOKE_ON_PAINT) != 0) {
161: initialize();
162: }
163:
164: super .paintAll(g);
165: }
166:
167: @Override
168: public void paintComponents(Graphics g) {
169: if ((getInvokeCondition() & INVOKE_ON_PAINT) != 0) {
170: initialize();
171: }
172:
173: super .paintComponents(g);
174: }
175:
176: @Override
177: public void repaint() {
178: if ((getInvokeCondition() & INVOKE_ON_REPAINT) != 0) {
179: initialize();
180: }
181: super .repaint();
182: }
183:
184: @Override
185: public void repaint(long l) {
186: if ((getInvokeCondition() & INVOKE_ON_REPAINT) != 0) {
187: initialize();
188: }
189: super .repaint(l);
190: }
191:
192: @Override
193: public void repaint(int i1, int i2, int i3, int i4) {
194: if ((getInvokeCondition() & INVOKE_ON_REPAINT) != 0) {
195: initialize();
196: }
197: super .repaint(i1, i2, i3, i4);
198: }
199:
200: @Override
201: public void repaint(long l, int i1, int i2, int i3, int i4) {
202: if ((getInvokeCondition() & INVOKE_ON_REPAINT) != 0) {
203: initialize();
204: }
205:
206: super .repaint(l, i1, i2, i3, i4);
207: }
208:
209: @Override
210: public void update(Graphics g) {
211: if ((getInvokeCondition() & INVOKE_ON_UPDATE) != 0) {
212: initialize();
213: }
214: super .update(g);
215: }
216:
217: /**
218: * Force the lazyInitialize() method implemented in the child class
219: * to be called. If this method is called more than once on
220: * a given object, all calls but the first do nothing.
221: */
222: public synchronized final void initialize() {
223: if (!_lazyConstructorCalled) {
224: _lazyConstructorCalled = true;
225: lazyInitialize();
226: validate();
227: }
228: }
229:
230: /**
231: * This method must be implemented by any child class. However you should never call
232: * this method directly. Call initialize() if you want to force a call to this method.
233: */
234: abstract public void lazyInitialize();
235:
236: /**
237: * Adds a <code>PageListener</code> to the page.
238: *
239: * @param l the <code>PageListener</code> to be added
240: */
241: public void addPageListener(PageListener l) {
242: listenerList.add(PageListener.class, l);
243: }
244:
245: /**
246: * Removes a <code>PageListener</code> from the page.
247: *
248: * @param l the <code>PageListener</code> to be removed
249: */
250: public void removePageListener(PageListener l) {
251: listenerList.remove(PageListener.class, l);
252: }
253:
254: /**
255: * Returns an array of all the <code>PageListener</code>s added
256: * to this <code>Page</code> with
257: * <code>addPageListener</code> .
258: *
259: * @return all of the <code>PageListener</code>s added, or an empty
260: * array if no listeners have been added
261: * @since 1.4
262: */
263: public PageListener[] getPageListeners() {
264: return (PageListener[]) listenerList
265: .getListeners(PageListener.class);
266: }
267:
268: /**
269: * Runs each <code>PageListener</code>'s
270: * <code>pageEventFired</code> method.
271: *
272: * @param id event id.
273: */
274: public void firePageEvent(int id) {
275: firePageEvent(this , id);
276: }
277:
278: /**
279: * Runs each <code>PageListener</code>'s
280: * <code>pageEventFired</code> method.
281: *
282: * @param source of this event
283: * @param id event id.
284: */
285: public void firePageEvent(Object source, int id) {
286: // make sure the page is initialized because user might add page listener in it.
287: // If the page is not initialized, what's the point firing event
288: initialize();
289:
290: if (source == null) { // set the source to this if it's null
291: source = this ;
292: }
293: Object[] listeners = listenerList.getListenerList();
294: for (int i = listeners.length - 2; i >= 0; i -= 2) {
295: if (listeners[i] == PageListener.class) {
296: _pageEvent = new PageEvent(source, id);
297: ((PageListener) listeners[i + 1])
298: .pageEventFired(_pageEvent);
299: }
300: }
301: }
302:
303: /**
304: * Sets allow closing. If true, the document cannot be closed. user can change the value
305: * in documentClosing() to prevent document from being closed.
306: *
307: * @param allowClosing true or false.
308: */
309: public void setAllowClosing(boolean allowClosing) {
310: _allowClosing = allowClosing;
311: }
312:
313: /**
314: * Allow this document closing. By default it return true.
315: * User can override this method to return based on conidition.
316: * A typical user case is: add a DocumentComponentListener.
317: * In documentComponentClosing, make this method return to false
318: * to prevent it from being closed.
319: *
320: * @return whether allow closing
321: */
322: public boolean allowClosing() {
323: return _allowClosing;
324: }
325: }
|