KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > wings > SComponent


1 /*
2  * $Id: SComponent.java,v 1.45 2005/05/27 15:20:53 blueshift Exp $
3  * Copyright 2000,2005 wingS development team.
4  *
5  * This file is part of wingS (http://www.j-wings.org).
6  *
7  * wingS is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1
10  * of the License, or (at your option) any later version.
11  *
12  * Please see COPYING for the complete licence.
13  */

14 package org.wings;
15
16
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.wings.border.SBorder;
20 import org.wings.event.SComponentEvent;
21 import org.wings.event.SComponentListener;
22 import org.wings.event.SParentFrameEvent;
23 import org.wings.event.SParentFrameListener;
24 import org.wings.event.SRenderEvent;
25 import org.wings.event.SRenderListener;
26 import org.wings.io.Device;
27 import org.wings.plaf.ComponentCG;
28 import org.wings.script.ScriptListener;
29 import org.wings.session.LowLevelEventDispatcher;
30 import org.wings.session.Session;
31 import org.wings.session.SessionManager;
32 import org.wings.style.CSSAttributeSet;
33 import org.wings.style.CSSProperty;
34 import org.wings.style.CSSSelector;
35 import org.wings.style.CSSStyle;
36 import org.wings.style.CSSStyleSheet;
37 import org.wings.style.Style;
38 import org.wings.util.ComponentVisitor;
39
40 import javax.swing.*;
41 import javax.swing.event.EventListenerList JavaDoc;
42 import java.awt.*;
43 import java.awt.event.ActionEvent JavaDoc;
44 import java.beans.BeanInfo JavaDoc;
45 import java.beans.Introspector JavaDoc;
46 import java.beans.PropertyDescriptor JavaDoc;
47 import java.io.IOException JavaDoc;
48 import java.io.Serializable JavaDoc;
49 import java.lang.reflect.Array JavaDoc;
50 import java.lang.reflect.Method JavaDoc;
51 import java.util.ArrayList JavaDoc;
52 import java.util.Arrays JavaDoc;
53 import java.util.Collection JavaDoc;
54 import java.util.Collections JavaDoc;
55 import java.util.EventListener JavaDoc;
56 import java.util.HashMap JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.Map JavaDoc;
59
60 /**
61  * The basic component implementation for all components in this package.
62  *
63  * @author <a HREF="mailto:haaf@mercatis.de">Armin Haaf</a>
64  * @version $Revision: 1.45 $
65  */

66 public abstract class SComponent
67         implements Cloneable JavaDoc, Serializable JavaDoc, Renderable {
68     private static final Object JavaDoc[] EMPTY_OBJECT_ARRAY = new Object JavaDoc[0];
69
70     private static final Log log = LogFactory.getLog(SComponent.class);
71
72     /* Components unique name. */
73     private String JavaDoc name;
74
75     /**
76      * the session
77      */

78     private transient Session session;
79
80     /**
81      * The code generation delegate, which is responsible for
82      * the visual representation of this component.
83      */

84     protected transient ComponentCG cg;
85
86     /**
87      * Vertical alignment
88      */

89     protected int verticalAlignment = SConstants.NO_ALIGN;
90
91     /**
92      * Horizontal alignment
93      */

94     protected int horizontalAlignment = SConstants.NO_ALIGN;
95
96     /**
97      * The name of the style class
98      */

99     protected String JavaDoc style;
100
101     /**
102      * List of dynamic styles
103      */

104     protected Map JavaDoc dynamicStyles;
105
106     /**
107      * Visibility.
108      */

109     protected boolean visible = true;
110
111     /**
112      * Enabled / disabled.
113      */

114     protected boolean enabled = true;
115
116     /**
117      * The container, this component resides in.
118      */

119     protected SContainer parent;
120
121     /**
122      * The frame in which this component resides.
123      */

124     protected SFrame parentFrame;
125
126     /**
127      * The border for the component.
128      */

129     protected SBorder border;
130
131     /**
132      * The tooltip for this component.
133      */

134     protected String JavaDoc tooltip;
135
136     /**
137      * The focus traversal Index
138      */

139     protected int focusTraversalIndex = -1;
140
141     /**
142      * Preferred size of component in pixel.
143      */

144     protected SDimension preferredSize;
145
146     /**
147      * This is for performance optimizations. With this flag is set, property change
148      * events are generated and so every property setter method has to test if a property
149      * has changed and temporarily store the old value to generate the property
150      * change event
151      */

152     private boolean fireComponentChangeEvents = false;
153
154     private boolean fireParentFrameChangeEvents = false;
155
156     private EventListenerList JavaDoc listeners;
157
158     private Boolean JavaDoc useNamedEvents;
159
160     private boolean showAsFormComponent = true;
161
162     private SPopupMenu popupMenu;
163
164     private boolean inheritsPopupMenu;
165
166     private InputMap inputMap;
167
168     private ActionMap actionMap;
169
170     private final Map JavaDoc actionEvents = new HashMap JavaDoc();
171
172     private final CSSSelector thisComponentCssSelector = new CSSSelector(this);
173
174     /**
175      * Default constructor.cript
176      * The method updateCG is called to get a cg delegate installed.
177      */

178     public SComponent() {
179         updateCG();
180     }
181
182     public SBorder getBorder() {
183         return border;
184     }
185
186     public void setBorder(SBorder border) {
187         reloadIfChange(this.border, border);
188         this.border = border;
189     }
190
191     /**
192      * Return the parent container.
193      *
194      * @return the container this component resides in
195      */

196     public final SContainer getParent() {
197         return parent;
198     }
199
200     /**
201      * Sets the parent container. Also gets the parent frame from the parent.
202      *
203      * @param parent the container
204      */

205     public void setParent(SContainer parent) {
206         reloadIfChange(this.parent, parent);
207         this.parent = parent;
208         if (parent != null)
209             setParentFrame(parent.getParentFrame());
210         else
211             setParentFrame(null);
212     }
213
214     /**
215      * Sets the parent frame.
216      *
217      * @param parentFrame the frame
218      */

219     protected void setParentFrame(SFrame parentFrame) {
220         if (this.parentFrame == parentFrame) {
221             return;
222         }
223
224         if (this.parentFrame != null) {
225             unregister();
226             fireParentFrameEvent(new SParentFrameEvent(this, SParentFrameEvent.PARENTFRAME_REMOVED, this.parentFrame));
227         }
228
229         this.parentFrame = parentFrame;
230
231         if (this.parentFrame != null) {
232             register();
233             // notify the listeners...
234
fireParentFrameEvent(new SParentFrameEvent(this, SParentFrameEvent.PARENTFRAME_ADDED, this.parentFrame));
235         }
236
237         if (this.popupMenu != null) {
238             popupMenu.setParentFrame(parentFrame);
239         }
240
241         reload();
242     }
243
244     public void setInheritsPopupMenu(boolean inheritsPopupMenu) {
245         reloadIfChange(this.inheritsPopupMenu, inheritsPopupMenu);
246         this.inheritsPopupMenu = inheritsPopupMenu;
247     }
248
249     public boolean getInheritsPopupMenu() {
250         return inheritsPopupMenu;
251     }
252
253     public void setComponentPopupMenu(SPopupMenu popupMenu) {
254         reloadIfChange(this.popupMenu, popupMenu);
255         if (this.popupMenu != null)
256             this.popupMenu.setParentFrame(null);
257         this.popupMenu = popupMenu;
258         if (this.popupMenu != null)
259             this.popupMenu.setParentFrame(getParentFrame());
260     }
261
262     public SPopupMenu getComponentPopupMenu() {
263         /* (OL) we probably don't need the recursive stuff here... */
264 // if (!getInheritsPopupMenu())
265
// return popupMenu;
266
//
267
// if (popupMenu == null) {
268
// // Search parents for its popup
269
// SContainer parent = getParent();
270
// while (parent != null) {
271
// if (parent instanceof SComponent) {
272
// return ((SComponent) parent).getComponentPopupMenu();
273
// }
274
// if (parent instanceof SFrame)
275
// break;
276
//
277
// parent = parent.getParent();
278
// }
279
// return null;
280
// }
281
return popupMenu;
282     }
283
284     public boolean hasComponentPopupMenu() {
285         return popupMenu != null;
286     }
287
288     public RequestURL getRequestURL() {
289         SFrame p = getParentFrame();
290         if (p == null)
291             throw new IllegalStateException JavaDoc("no parent frame");
292
293         return p.getRequestURL();
294     }
295
296     /**
297      * Set the preferred size of the receiving component in pixel.
298      * It is not guaranteed that the component accepts this property because of
299      * missing implementations in the component cg or html properties.
300      * If <i>width</i> or <i>height</i> is zero, it is ignored and the browser
301      * defines the size.
302      *
303      * @see org.wings.SComponent#getPreferredSize
304      */

305     public void setPreferredSize(SDimension preferredSize) {
306         reloadIfChange(this.preferredSize, preferredSize);
307         this.preferredSize = preferredSize;
308     }
309
310     /**
311      * Get the preferred size of this component.
312      *
313      * @see SComponent#setPreferredSize
314      */

315     public SDimension getPreferredSize() {
316         return preferredSize;
317     }
318
319
320     /**
321      * Adds the specified component listener to receive component events from
322      * this component.
323      * If l is null, no exception is thrown and no action is performed.
324      *
325      * @param l the component listener.
326      * @see org.wings.event.SComponentEvent
327      * @see org.wings.event.SComponentListener
328      * @see org.wings.SComponent#removeComponentListener
329      */

330     public final void addComponentListener(SComponentListener l) {
331         addEventListener(SComponentListener.class, l);
332         fireComponentChangeEvents = true;
333     }
334
335     /**
336      * Removes the specified component listener so that it no longer
337      * receives component events from this component. This method performs
338      * no function, nor does it throw an exception, if the listener
339      * specified by the argument was not previously added to this component.
340      * If l is null, no exception is thrown and no action is performed.
341      *
342      * @param l the component listener.
343      * @see org.wings.event.SComponentEvent
344      * @see org.wings.event.SComponentListener
345      * @see org.wings.SComponent#addComponentListener
346      */

347     public final void removeComponentListener(SComponentListener l) {
348         removeEventListener(SComponentListener.class, l);
349     }
350
351     /**
352      * Adds the specified parent frame listener to receive events from
353      * this component.
354      * If l is null, no exception is thrown and no action is performed.
355      *
356      * @param l the parent frame listener.
357      * @see org.wings.event.SParentFrameEvent
358      * @see org.wings.event.SParentFrameListener
359      * @see org.wings.SComponent#removeParentFrameListener
360      */

361     public final void addParentFrameListener(SParentFrameListener l) {
362         addEventListener(SParentFrameListener.class, l);
363         fireParentFrameChangeEvents = true;
364     }
365
366     /**
367      * Removes the specified parent frame listener so that it no longer
368      * receives events from this component. This method performs
369      * no function, nor does it throw an exception, if the listener
370      * specified by the argument was not previously added to this component.
371      * If l is null, no exception is thrown and no action is performed.
372      *
373      * @param l the parent frame listener.
374      * @see org.wings.event.SParentFrameEvent
375      * @see org.wings.event.SParentFrameListener
376      * @see org.wings.SComponent#addParentFrameListener
377      */

378     public final void removeParentFrameListener(SParentFrameListener l) {
379         removeEventListener(SParentFrameListener.class, l);
380     }
381
382     /**
383      * Reports a component change.
384      *
385      * @param aEvent report this event to all listeners
386      * @see org.wings.event.SComponentListener
387      */

388     protected void fireComponentChangeEvent(SComponentEvent aEvent) {
389         // maybe the better way to do this is to user the getListenerList
390
// and iterate through all listeners, this saves the creation of
391
// an array but it must cast to the apropriate listener
392
Object JavaDoc[] listeners = getListenerList();
393         for (int i = listeners.length - 2; i >= 0; i -= 2) {
394             if (listeners[i] == SComponentListener.class) {
395                 // Lazily create the event:
396
processComponentEvent((SComponentListener) listeners[i + 1],
397                         aEvent);
398             }
399         }
400
401     }
402
403     /**
404      * Reports a parent frame change.
405      *
406      * @param aEvent report this event to all listeners
407      * @see org.wings.event.SParentFrameListener
408      */

409     private void fireParentFrameEvent(SParentFrameEvent aEvent) {
410         // are listeners registered?
411
if (fireParentFrameChangeEvents) {
412             // maybe the better way to do this is to user the getListenerList
413
// and iterate through all listeners, this saves the creation of
414
// an array but it must cast to the apropriate listener
415
Object JavaDoc[] listeners = getListenerList();
416             for (int i = listeners.length - 2; i >= 0; i -= 2) {
417                 if (listeners[i] == SParentFrameListener.class) {
418                     // Lazily create the event:
419
processParentFrameEvent((SParentFrameListener) listeners[i + 1],
420                             aEvent);
421                 }
422             }
423         }
424
425     }
426
427     /**
428      * Processes parent frame events occurring on this component by
429      * dispatching them to any registered
430      * <code>SParentFrameListener</code> objects.
431      * <p/>
432      *
433      */

434     private void processParentFrameEvent(SParentFrameListener listener, SParentFrameEvent event) {
435         int id = event.getID();
436         switch (id) {
437             case SParentFrameEvent.PARENTFRAME_ADDED:
438                 listener.parentFrameAdded(event);
439                 break;
440             case SParentFrameEvent.PARENTFRAME_REMOVED:
441                 listener.parentFrameRemoved(event);
442                 break;
443         }
444     }
445
446     /**
447      * Processes component events occurring on this component by
448      * dispatching them to any registered
449      * <code>SComponentListener</code> objects.
450      * <p/>
451      * This method is not called unless component events are
452      * enabled for this component. Component events are enabled
453      * when one of the following occurs:
454      * <p><ul>
455      * <li>A <code>SComponentListener</code> object is registered
456      * via <code>addComponentListener</code>.
457      * </ul>
458      *
459      * @param e the component event.
460      * @see org.wings.event.SComponentEvent
461      * @see org.wings.event.SComponentListener
462      * @see org.wings.SComponent#addComponentListener
463      */

464     protected void processComponentEvent(SComponentListener listener, SComponentEvent e) {
465         int id = e.getID();
466         switch (id) {
467             case SComponentEvent.COMPONENT_RESIZED:
468                 listener.componentResized(e);
469                 break;
470             case SComponentEvent.COMPONENT_MOVED:
471                 listener.componentMoved(e);
472                 break;
473             case SComponentEvent.COMPONENT_SHOWN:
474                 listener.componentShown(e);
475                 break;
476             case SComponentEvent.COMPONENT_HIDDEN:
477                 listener.componentHidden(e);
478                 break;
479         }
480     }
481
482     /**
483      * Adds the specified component listener to receive component events from
484      * this component.
485      * If l is null, no exception is thrown and no action is performed.
486      * If there is already a ScriptListener which is equal, the new one is not
487      * added.
488      *
489      * @param listener the component listener.
490      * @see org.wings.event.SComponentEvent
491      * @see org.wings.event.SComponentListener
492      * @see org.wings.SComponent#removeComponentListener
493      */

494     public final void addScriptListener(ScriptListener listener) {
495         ScriptListener[] listeners = getScriptListeners();
496         for (int i = 0; i < listeners.length; i++) {
497             if (listeners[i].equals(listener)) {
498                 return;
499             }
500         }
501         addEventListener(ScriptListener.class, listener);
502     }
503
504
505     /**
506      * Removes the specified component listener so that it no longer
507      * receives component events from this component. This method performs
508      * no function, nor does it throw an exception, if the listener
509      * specified by the argument was not previously added to this component.
510      * If l is null, no exception is thrown and no action is performed.
511      *
512      * @param listener the component listener.
513      * @see org.wings.event.SComponentEvent
514      * @see org.wings.event.SComponentListener
515      * @see org.wings.SComponent#addComponentListener
516      */

517     public final void removeScriptListener(ScriptListener listener) {
518         removeEventListener(ScriptListener.class, listener);
519     }
520
521     public ScriptListener[] getScriptListeners() {
522         return (ScriptListener[]) getListeners(ScriptListener.class);
523     }
524
525     public void setName(String JavaDoc name) {
526         if (name != null) {
527             if (!Character.isJavaIdentifierStart(name.charAt(0)) || name.charAt(0) == '_')
528                 throw new IllegalArgumentException JavaDoc(name + " is not a valid identifier");
529             for (int i=1; i < name.length(); i++)
530                 if (!Character.isJavaIdentifierPart(name.charAt(i)) || name.charAt(0) == '_')
531                     throw new IllegalArgumentException JavaDoc(name + " is not a valid identifier");
532         }
533         reloadIfChange(this.name, name);
534         this.name = name;
535     }
536
537     public final String JavaDoc getName() {
538         if (name == null)
539             name = getSession().createUniqueId();
540         return name;
541     }
542
543     /**
544      * Return the session this component belongs to.
545      *
546      * @return the session
547      */

548     public final Session getSession() {
549         if (session == null) {
550             session = SessionManager.getSession();
551         }
552
553         return session;
554     }
555
556     /**
557      * Return the dispatcher.
558      *
559      * @return the dispatcher
560      */

561     public final LowLevelEventDispatcher getDispatcher() {
562         return getSession().getDispatcher();
563     }
564
565     /*
566      * If a subclass implements the {@link LowLevelEventListener} interface,
567      * it will be unregistered at the associated dispatcher.
568      */

569     private final void unregister() {
570         if (getDispatcher() != null && this instanceof LowLevelEventListener) {
571             getDispatcher().unregister((LowLevelEventListener) this);
572         }
573     }
574
575     /*
576      * If a subclass implements the {@link LowLevelEventListener} interface,
577      * it will be registered at the associated dispatcher.
578      */

579     private final void register() {
580         if (getDispatcher() != null && this instanceof LowLevelEventListener) {
581             getDispatcher().register((LowLevelEventListener) this);
582         }
583     }
584
585     /**
586      * Set the class of the laf-provided style.
587      *
588      * @param value the new value for style
589      */

590     public void setStyle(String JavaDoc value) {
591         reloadIfChange(style, value);
592         this.style = value;
593     }
594
595     /**
596      * @return the current style
597      */

598     public String JavaDoc getStyle() {
599         return style;
600     }
601
602     public void addDynamicStyle(Style style) {
603         if (dynamicStyles == null)
604             dynamicStyles = new HashMap JavaDoc(4);
605         dynamicStyles.put(style.getSelector(), style);
606         reload();
607     }
608
609     public void removeDynamicStyle(String JavaDoc selector) {
610         if (dynamicStyles == null)
611             return;
612         dynamicStyles.remove(selector);
613         reload();
614     }
615
616     public Style getDynamicStyle(Object JavaDoc selector) {
617         if (dynamicStyles == null)
618             return null;
619         return (Style) dynamicStyles.get(selector);
620     }
621
622     public void setDynamicStyles(Collection JavaDoc dynamicStyles) {
623         if (dynamicStyles == null)
624             return;
625         if (this.dynamicStyles == null)
626             this.dynamicStyles = new HashMap JavaDoc(4);
627         for (Iterator JavaDoc iterator = dynamicStyles.iterator(); iterator.hasNext();) {
628             Style style = (Style) iterator.next();
629             this.dynamicStyles.put(style.getSelector(), style);
630         }
631         reload();
632     }
633
634     public Collection JavaDoc getDynamicStyles() {
635         if (dynamicStyles == null || dynamicStyles.size() == 0)
636             return null;
637         return Collections.unmodifiableCollection(dynamicStyles.values());
638     }
639
640     /** @deprecated Use {@link #setAttribute(org.wings.style.CSSProperty, String)} */
641     public void setAttribute(String JavaDoc cssPropertyName, String JavaDoc value) {
642         setAttribute(thisComponentCssSelector, new CSSProperty(cssPropertyName), value);
643     }
644
645     public void setAttribute(CSSProperty property, String JavaDoc propertyValue) {
646          setAttribute(thisComponentCssSelector, property, propertyValue);
647     }
648
649     public void setAttribute(CSSSelector selector, CSSProperty property, SIcon icon) {
650         setAttribute(selector, property, icon != null ? "url('"+icon.getURL().toString()+"')" : "none");
651     }
652
653     public void setAttribute(CSSSelector selector, CSSProperty property, String JavaDoc propertyValue) {
654         CSSStyle style = (CSSStyle) getDynamicStyle(selector);
655         if (style == null) {
656             addDynamicStyle(new CSSStyle(selector, property, propertyValue));
657             reload();
658         } else {
659             String JavaDoc old = style.put(property, propertyValue);
660             reloadIfChange(old, propertyValue);
661         }
662     }
663
664     public void setAttributes(CSSAttributeSet attributes) {
665         log.debug("attributes = " + attributes);
666         setAttributes(thisComponentCssSelector, attributes);
667     }
668
669     public void setAttributes(CSSSelector selector, CSSAttributeSet attributes) {
670         CSSStyle style = (CSSStyle) getDynamicStyle(selector);
671         if (style == null) {
672             addDynamicStyle(new CSSStyle(selector, attributes));
673             reload();
674         } else {
675             boolean changed = style.putAll(attributes);
676             if (changed)
677                 reload();
678         }
679     }
680
681     /**
682      * Return the background color.
683      *
684      * @return the background color
685      */

686     public Color getBackground() {
687         return dynamicStyles == null || dynamicStyles.get(thisComponentCssSelector) == null ? null : CSSStyleSheet.getBackground((CSSAttributeSet) dynamicStyles.get(thisComponentCssSelector));
688     }
689
690     /**
691      * Set the foreground color.
692      *
693      * @param color the new foreground color
694      */

695     public void setBackground(Color color) {
696         setAttribute(thisComponentCssSelector, CSSProperty.BACKGROUND_COLOR, CSSStyleSheet.getAttribute(color));
697     }
698
699     /**
700      * Return the foreground color.
701      *
702      * @return the foreground color
703      */

704     public Color getForeground() {
705         return dynamicStyles == null || dynamicStyles.get(thisComponentCssSelector) == null ? null : CSSStyleSheet.getForeground((CSSAttributeSet) dynamicStyles.get(thisComponentCssSelector));
706     }
707
708     /**
709      * Set the foreground color.
710      *
711      * @param color the new foreground color
712      */

713     public void setForeground(Color color) {
714         setAttribute(thisComponentCssSelector, CSSProperty.COLOR, CSSStyleSheet.getAttribute(color));
715     }
716
717     /**
718      * Set the font.
719      *
720      * @param font the new font
721      */

722     public void setFont(SFont font) {
723         setAttributes(thisComponentCssSelector, CSSStyleSheet.getAttributes(font));
724     }
725
726     /**
727      * Return the font.
728      *
729      * @return the font
730      */

731     public SFont getFont() {
732         return dynamicStyles == null || dynamicStyles.get(thisComponentCssSelector) == null ? null : CSSStyleSheet.getFont((CSSAttributeSet) dynamicStyles.get(thisComponentCssSelector));
733     }
734
735     /**
736      * Set the visibility.
737      *
738      * @param visible wether this component will show or not
739      */

740     public void setVisible(boolean visible) {
741         boolean old = this.visible;
742         this.visible = visible;
743         if (fireComponentChangeEvents && (visible != old)) {
744             fireComponentChangeEvent(new SComponentEvent(this, visible
745                     ? SComponentEvent.COMPONENT_SHOWN
746                     : SComponentEvent.COMPONENT_HIDDEN));
747         }
748     }
749
750     /**
751      * Return the visibility.
752      *
753      * @return wether the component will show
754      */

755     public boolean isVisible() {
756         return visible;
757     }
758
759     /**
760      * Set wether this component should be enabled.
761      *
762      * @param enabled true if the component is enabled, false otherwise
763      */

764     public void setEnabled(boolean enabled) {
765         this.enabled = enabled;
766     }
767
768     /**
769      * Return true if this component is enabled.
770      *
771      * @return true if component is enabled
772      */

773     public boolean isEnabled() {
774         return enabled;
775     }
776
777     /**
778      * Mark the component as subject to reload.
779      * The component will be registered with the ReloadManager.
780      */

781     public final void reload() {
782         getSession().getReloadManager().reload(this);
783     }
784
785     /**
786      * Mark this component as subject to reload for the given
787      * aspect if the property, that is given in its old and new
788      * fashion, changed. Convenience method for {@link #reload()}
789      *
790      * @param oldVal the old value of some property
791      * @param newVal the new value of some property
792      */

793     protected final void reloadIfChange(Object JavaDoc oldVal, Object JavaDoc newVal) {
794         if (!((oldVal == newVal) || (oldVal != null && oldVal.equals(newVal)))) {
795             //System.err.println(getClass().getDescription() + ": reload. old:" + oldVal + "; new: "+ newVal);
796
reload();
797         }
798     }
799
800     /**
801      * Mark this component as subject to reload for the given
802      * aspect if the property, that is given in its old and new
803      * fashion, changed. Convenience method for {@link #reload()}
804      *
805      * @param oldVal the old value of some property
806      * @param newVal the new value of some property
807      */

808     protected final void reloadIfChange(int oldVal, int newVal) {
809         if (oldVal != newVal) {
810             reload();
811         }
812     }
813
814     /**
815      * Mark this component as subject to reload for the given
816      * aspect if the property, that is given in its old and new
817      * fashion, changed. Convenience method for {@link #reload()}
818      *
819      * @param oldVal the old value of some property
820      * @param newVal the new value of some property
821      */

822     protected final void reloadIfChange(boolean oldVal, boolean newVal) {
823         if (oldVal != newVal) {
824             reload();
825         }
826     }
827
828     /**
829      * Mark this component as subject to reload for the given
830      * aspect if the property, that is given in its old and new
831      * fashion, changed. Convenience method for {@link #reload()}
832      *
833      * @param oldVal the old value of some property
834      * @param newVal the new value of some property
835      */

836     protected final void reloadIfChange(byte oldVal, byte newVal) {
837         if (oldVal != newVal) {
838             reload();
839         }
840     }
841
842     /**
843      * Mark this component as subject to reload for the given
844      * aspect if the property, that is given in its old and new
845      * fashion, changed. Convenience method for {@link #reload()}
846      *
847      * @param oldVal the old value of some property
848      * @param newVal the new value of some property
849      */

850     protected final void reloadIfChange(short oldVal, short newVal) {
851         if (oldVal != newVal) {
852             reload();
853         }
854     }
855
856     /**
857      * Mark this component as subject to reload for the given
858      * aspect if the property, that is given in its old and new
859      * fashion, changed. Convenience method for {@link #reload()}
860      *
861      * @param oldVal the old value of some property
862      * @param newVal the new value of some property
863      */

864     protected final void reloadIfChange(long oldVal, long newVal) {
865         if (oldVal != newVal) {
866             reload();
867         }
868     }
869
870     /**
871      * Mark this component as subject to reload for the given
872      * aspect if the property, that is given in its old and new
873      * fashion, changed. Convenience method for {@link #reload()}
874      *
875      * @param oldVal the old value of some property
876      * @param newVal the new value of some property
877      */

878     protected final void reloadIfChange(float oldVal, float newVal) {
879         if (oldVal != newVal) {
880             reload();
881         }
882     }
883
884     /**
885      * Mark this component as subject to reload for the given
886      * aspect if the property, that is given in its old and new
887      * fashion, changed. Convenience method for {@link #reload()}
888      *
889      * @param oldVal the old value of some property
890      * @param newVal the new value of some property
891      */

892     protected final void reloadIfChange(double oldVal, double newVal) {
893         if (oldVal != newVal) {
894             reload();
895         }
896     }
897
898     /**
899      * Mark this component as subject to reload for the given
900      * aspect if the property, that is given in its old and new
901      * fashion, changed. Convenience method for {@link #reload()}
902      *
903      * @param oldVal the old value of some property
904      * @param newVal the new value of some property
905      */

906     protected final void reloadIfChange(char oldVal, char newVal) {
907         if (oldVal != newVal) {
908             reload();
909         }
910     }
911
912     /**
913      * Let the code generator deletate write the component's code
914      * to the device. The code generator is the actual 'plaf'.
915      *
916      * @param s the Device to write into
917      * @throws IOException Thrown if the connection to the client gets broken,
918      * for example when the user stops loading
919      */

920     public void write(Device s) throws IOException JavaDoc {
921         try {
922             if (visible)
923                 cg.write(s, this);
924         } catch (IOException JavaDoc se) {
925             // Typical double-clicks. Not severe
926
log.debug( "Socket exception during code generation for " + getClass().getName() + se);
927         } catch (Throwable JavaDoc t) {
928             log.warn( "Exception during code generation for " + getClass().getName(), t);
929         }
930     }
931
932     /**
933      * a string representation of this component. Just
934      * renders the component into a string.
935      */

936     public String JavaDoc toString() {
937         return paramString();
938     }
939
940
941     /**
942      * Generic implementation for generating a string that represents
943      * the components configuration.
944      *
945      * @return a string containing all properties
946      */

947     public String JavaDoc paramString() {
948         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(getClass().getName());
949         buffer.append("[");
950
951         try {
952             BeanInfo JavaDoc info = Introspector.getBeanInfo(getClass());
953             PropertyDescriptor JavaDoc[] descriptors = info.getPropertyDescriptors();
954
955             boolean first = true;
956             for (int i = 0; i < descriptors.length; i++) {
957                 try {
958                     Method JavaDoc getter = descriptors[i].getReadMethod();
959                     if (getter == null || getter.getName().startsWith("getParent"))
960                         continue;
961                     // System.out.println("invoking " + this.getClass().getDescription()+"."+getter.getDescription());
962
Object JavaDoc value = getter.invoke(this, null);
963                     if (first)
964                         first = false;
965                     else
966                         buffer.append(",");
967                     buffer.append(descriptors[i].getName() + "=" + value);
968                 } catch (Exception JavaDoc e) {
969                 }
970             }
971         } catch (Exception JavaDoc e) {
972         }
973
974         buffer.append("]");
975         return buffer.toString();
976     }
977
978     /**
979      * Encodes a low level event id for using it in a request parameter. Every
980      * {@link LowLevelEventListener} should encode its LowLevelEventId before
981      * using it in a request parameter. This encoding adds consistency checking
982      * for outtimed requests ("Back Button")
983      */

984     private String JavaDoc encodeLowLevelEventId(String JavaDoc lowLevelEventId) {
985         if (getParentFrame() != null)
986             if (!(this instanceof LowLevelEventListener) ||
987                     ((LowLevelEventListener) this).isEpochCheckEnabled()) {
988                 return (getParentFrame().getEventEpoch()
989                         + SConstants.UID_DIVIDER
990                         + lowLevelEventId);
991             }
992         return lowLevelEventId;
993     }
994
995     /**
996      * Encodes a low level event id for using it in a request parameter. Every
997      * {@link LowLevelEventListener} should encode its LowLevelEventId before
998      * using it in a request parameter. This encoding adds consistency checking
999      * for outtimed requests ("Back Button")
1000     */

1001    public final String JavaDoc getEncodedLowLevelEventId() {
1002        if (getUseNamedEvents() && getName() != null)
1003            return name;
1004        else
1005            return encodeLowLevelEventId(getLowLevelEventId());
1006    }
1007
1008    private boolean getUseNamedEvents() {
1009        if (useNamedEvents == null) {
1010            useNamedEvents = ("true".equalsIgnoreCase((String JavaDoc) getSession().getProperty("wings.event.usenames")))
1011                    ? Boolean.TRUE : Boolean.FALSE;
1012        }
1013        return useNamedEvents.booleanValue();
1014    }
1015
1016    /**
1017     * Default implementation of the method in
1018     * {@link LowLevelEventListener}.
1019     */

1020    public String JavaDoc getLowLevelEventId() {
1021        return getName();
1022    }
1023
1024    /**
1025     * Return the parent frame.
1026     *
1027     * @return the parent frame
1028     */

1029    public SFrame getParentFrame() {
1030        return parentFrame;
1031    }
1032
1033    /**
1034     * Return true, if this component is contained in a form.
1035     *
1036     * @return true, if this component resides in a form, false otherwise
1037     */

1038    public final boolean getResidesInForm() {
1039        SComponent parent = getParent();
1040
1041        boolean actuallyDoes = false;
1042        while (parent != null && !(actuallyDoes = (parent instanceof SForm))) {
1043            parent = parent.getParent();
1044        }
1045
1046        return actuallyDoes;
1047    }
1048
1049    /**
1050     * Set the tooltip text.
1051     *
1052     * @param t the new tooltip text
1053     */

1054    public void setToolTipText(String JavaDoc t) {
1055        tooltip = t;
1056    }
1057
1058    /**
1059     * Return the tooltip text.
1060     *
1061     * @return the tooltip text
1062     */

1063    public String JavaDoc getToolTipText() {
1064        return tooltip;
1065    }
1066
1067    /**
1068     * The index in which the focus is traversed using Tab. This is
1069     * a very simplified notion of traversing the focus, but that is,
1070     * what browser like interfaces currently offer. This has a bit rough
1071     * edge, since you have to make sure, that the index is unique within
1072     * the whole frame. You probably don't want to change this
1073     * programmatically, but this is set usually by the template property
1074     * manager.
1075     *
1076     * @param index the focus traversal index. Pressing the focus traversal
1077     * key (usually TAB) in the browser jumps to the next index.
1078     * Must not be zero.
1079     */

1080    public void setFocusTraversalIndex(int index) {
1081        focusTraversalIndex = index;
1082    }
1083
1084    /**
1085     * returns the focus traversal index.
1086     *
1087     * @see #setFocusTraversalIndex(int)
1088     */

1089    public int getFocusTraversalIndex() {
1090        return focusTraversalIndex;
1091    }
1092
1093    /**
1094     * Clone this component.
1095     *
1096     * @return a clone of this component
1097     */

1098    public Object JavaDoc clone() {
1099        try {
1100            return super.clone();
1101        } catch (Exception JavaDoc e) {
1102            e.printStackTrace();
1103            return null;
1104        }
1105    }
1106
1107    /**
1108     * Return the value of the horizontal alignment property.
1109     *
1110     * @return the horizontal alignment
1111     * @see SConstants
1112     */

1113    public int getHorizontalAlignment() {
1114        return horizontalAlignment;
1115    }
1116
1117    /**
1118     * Set the horizontal alignment.
1119     *
1120     * @param alignment new value for the horizontal alignment
1121     * @see SConstants
1122     */

1123    public void setHorizontalAlignment(int alignment) {
1124        horizontalAlignment = alignment;
1125    }
1126
1127    /**
1128     * Set the vertical alignment.
1129     *
1130     * @param alignment new value for the vertical alignment
1131     * @see SConstants
1132     */

1133    public void setVerticalAlignment(int alignment) {
1134        verticalAlignment = alignment;
1135    }
1136
1137    /**
1138     * Return the value of the vertical alignment property.
1139     *
1140     * @return the vertical alignment
1141     * @see SConstants
1142     */

1143    public int getVerticalAlignment() {
1144        return verticalAlignment;
1145    }
1146
1147    private Map JavaDoc clientProperties;
1148
1149    /**
1150     * @return a small HashMap
1151     * @see #putClientProperty
1152     * @see #getClientProperty
1153     */

1154    private Map JavaDoc getClientProperties() {
1155        if (clientProperties == null) {
1156            clientProperties = new HashMap JavaDoc(2);
1157        }
1158        return clientProperties;
1159    }
1160
1161
1162    /**
1163     * Returns the value of the property with the specified key. Only
1164     * properties added with <code>putClientProperty</code> will return
1165     * a non-null value.
1166     *
1167     * @return the value of this property or null
1168     * @see #putClientProperty
1169     */

1170    public final Object JavaDoc getClientProperty(Object JavaDoc key) {
1171        if (clientProperties == null) {
1172            return null;
1173        } else {
1174            return getClientProperties().get(key);
1175        }
1176    }
1177
1178    /**
1179     * Add an arbitrary key/value "client property" to this component.
1180     * <p/>
1181     * The <code>get/putClientProperty<code> methods provide access to
1182     * a small per-instance hashtable. Callers can use get/putClientProperty
1183     * to annotate components that were created by another module, e.g. a
1184     * layout manager might store per child constraints this way. For example:
1185     * <pre>
1186     * componentA.putClientProperty("to the left of", componentB);
1187     * </pre>
1188     * <p/>
1189     * If value is null this method will remove the property.
1190     * Changes to client properties are reported with PropertyChange
1191     * events. The name of the property (for the sake of PropertyChange
1192     * events) is <code>key.toString()</code>.
1193     * <p/>
1194     * The clientProperty dictionary is not intended to support large
1195     * scale extensions to SComponent nor should be it considered an
1196     * alternative to subclassing when designing a new component.
1197     *
1198     * @see #getClientProperty
1199     */

1200    public final void putClientProperty(Object JavaDoc key, Object JavaDoc value) {
1201        if (value != null) {
1202            getClientProperties().put(key, value);
1203        } else {
1204            getClientProperties().remove(key);
1205        }
1206    }
1207
1208
1209    /**
1210     * Set the look and feel delegate for this component.
1211     * SComponent subclasses generally override this method
1212     * to narrow the argument type, e.g. in STextField:
1213     * <pre>
1214     * public void setCG(TextFieldCG newCG) {
1215     * super.setCG(newCG);
1216     * }
1217     * </pre>
1218     *
1219     * @see #updateCG
1220     * @see org.wings.plaf.CGManager#getLookAndFeel
1221     * @see org.wings.plaf.CGManager#getCG
1222     */

1223    public void setCG(ComponentCG newCG) {
1224        /* We do not check that the CG instance is different
1225         * before allowing the switch in order to enable the
1226         * same CG instance *with different default settings*
1227         * to be installed.
1228         */

1229        if (cg != null) {
1230            cg.uninstallCG(this);
1231        }
1232        ComponentCG oldCG = cg;
1233        cg = newCG;
1234        if (cg != null) {
1235            cg.installCG(this);
1236        }
1237        reloadIfChange(cg, oldCG);
1238    }
1239
1240    /**
1241     * Return the look and feel delegate.
1242     *
1243     * @return the componet's cg
1244     */

1245    public ComponentCG getCG() {
1246        return cg;
1247    }
1248
1249    /**
1250     * Notification from the CGFactory that the L&F has changed.
1251     *
1252     * @see SComponent#updateCG
1253     */

1254    public void updateCG() {
1255        if (getSession() == null) {
1256            log.warn("no session yet.");
1257        } else if (getSession().getCGManager() == null) {
1258            log.warn("no CGManager");
1259        } else {
1260            setCG(getSession().getCGManager().getCG(this));
1261        }
1262    }
1263
1264    /**
1265     * Invite a ComponentVisitor.
1266     * Invokes visit(SComponent) on the ComponentVisitor.
1267     *
1268     * @param visitor the visitor to be invited
1269     */

1270    public void invite(ComponentVisitor visitor)
1271            throws Exception JavaDoc {
1272        visitor.visit(this);
1273    }
1274
1275    /**
1276     * use this method for changing a variable. if a new value is different
1277     * from the old value set the new one and notify e.g. the reloadmanager...
1278     */

1279    protected static final boolean isDifferent(Object JavaDoc oldObject,
1280                                               Object JavaDoc newObject) {
1281        if (oldObject == newObject)
1282            return false;
1283
1284        if (oldObject == null)
1285            return true;
1286
1287        return !oldObject.equals(newObject);
1288    }
1289
1290    protected final void addEventListener(Class JavaDoc type, EventListener JavaDoc listener) {
1291        if (listeners == null) {
1292            listeners = new EventListenerList JavaDoc();
1293        }
1294        listeners.add(type, listener);
1295    }
1296
1297    protected final void removeEventListener(Class JavaDoc type, EventListener JavaDoc listener) {
1298        if (listeners != null) {
1299            listeners.remove(type, listener);
1300        }
1301    }
1302
1303    /**
1304     * Returns the number of listeners of the specified type for this component.
1305     *
1306     * @param type The type of listeners
1307     * @return The number of listeners
1308     * @see EventListenerList
1309     */

1310    protected final int getListenerCount(Class JavaDoc type) {
1311        if (listeners != null) {
1312            return listeners.getListenerCount(type);
1313        } else {
1314            return 0;
1315        }
1316    }
1317
1318    /**
1319     * Returns all the listeners of this component. For performance reasons, this is the actual data
1320     * structure and so no modification of this array should be made.
1321     *
1322     * @return All listeners of this component. The result array has a pair structure,
1323     * the first element of each pair is the listener type, the second the listener
1324     * itself. It is guaranteed that this returns a non-null array.
1325     * @see EventListenerList
1326     */

1327    protected final Object JavaDoc[] getListenerList() {
1328        if (listeners == null) {
1329            return EMPTY_OBJECT_ARRAY;
1330        } else {
1331            return listeners.getListenerList();
1332        } // end of else
1333
}
1334
1335    /**
1336     * Creates an typed array of all listeners of the specified type
1337     *
1338     * @param type All listeners of this type are added to the result array
1339     * @return an array of the specified type with all listeners of the specified type
1340     * @see EventListenerList
1341     */

1342    protected final EventListener JavaDoc[] getListeners(Class JavaDoc type) {
1343        if (listeners != null) {
1344            return listeners.getListeners(type);
1345        } else {
1346            return (EventListener JavaDoc[]) Array.newInstance(type, 0);
1347        }
1348    }
1349
1350
1351    private transient SRenderEvent renderEvent;
1352
1353    /**
1354     * for performance reasons
1355     */

1356    private boolean fireRenderEvents = false;
1357
1358    public static final int START_RENDERING = 1;
1359    public static final int DONE_RENDERING = 2;
1360
1361    public final void addRenderListener(SRenderListener l) {
1362        addEventListener(SRenderListener.class, l);
1363        fireRenderEvents = true;
1364    }
1365
1366    public final void removeRenderListener(SRenderListener l) {
1367        removeEventListener(SRenderListener.class, l);
1368    }
1369
1370    public final void fireRenderEvent(int type) {
1371        if (fireRenderEvents) {
1372            // maybe the better way to do this is to user the getListenerList
1373
// and iterate through all listeners, this saves the creation of
1374
// an array but it must cast to the apropriate listener
1375
Object JavaDoc[] listeners = getListenerList();
1376            for (int i = listeners.length - 2; i >= 0; i -= 2) {
1377                if (listeners[i] == SRenderListener.class) {
1378                    // Lazily create the event:
1379
if (renderEvent == null) {
1380                        renderEvent = new SRenderEvent(this);
1381                    } // end of if ()
1382

1383                    switch (type) {
1384                        case START_RENDERING:
1385                            ((SRenderListener) listeners[i + 1]).startRendering(renderEvent);
1386                            break;
1387                        case DONE_RENDERING:
1388                            ((SRenderListener) listeners[i + 1]).doneRendering(renderEvent);
1389                            break;
1390                    }
1391                }
1392            }
1393        }
1394    }
1395
1396    /**
1397     * Forwards the scrollRectToVisible() message to the SComponent's
1398     * parent. Components that can service the request, such as
1399     * SScrollPane, override this method and perform the scrolling.
1400     *
1401     * @param aRect the visible Rectangle
1402     * @see SScrollPane
1403     */

1404    public void scrollRectToVisible(Rectangle aRect) {
1405        if (parent != null) {
1406            parent.scrollRectToVisible(aRect);
1407        }
1408    }
1409
1410    /**
1411     * requests the focus for this component
1412     */

1413    public void requestFocus() {
1414        if (getParentFrame() != null) {
1415            getParentFrame().setFocus(this);
1416        }
1417    }
1418
1419    public boolean isFocusOwner() {
1420        if (getParentFrame() != null)
1421            return this == getParentFrame().getFocus();
1422        return false;
1423    }
1424
1425    /**
1426     * Set display mode (href or form-component).
1427     * An AbstractButton can appear as HTML-Form-Button or as
1428     * HTML-HREF. If button is inside a {@link SForm} the default
1429     * is displaying it as html form button.
1430     * Setting <i>showAsFormComponent</i> to <i>false</i> will
1431     * force displaying as href even if button is inside
1432     * a form.
1433     *
1434     * @param showAsFormComponent if true, display as link, if false as html form component.
1435     */

1436    public void setShowAsFormComponent(boolean showAsFormComponent) {
1437        if (this.showAsFormComponent != showAsFormComponent) {
1438            this.showAsFormComponent = showAsFormComponent;
1439            reload();
1440        }
1441    }
1442
1443    /**
1444     * Test, what display method is set.
1445     *
1446     * @return true, if displayed as link, false when displayed as html form component.
1447     * @see #setShowAsFormComponent(boolean)
1448     */

1449    public boolean getShowAsFormComponent() {
1450        return showAsFormComponent && getResidesInForm();
1451    }
1452
1453    public void setActionMap(ActionMap actionMap) {
1454        this.actionMap = actionMap;
1455    }
1456
1457    public ActionMap getActionMap() {
1458        if (actionMap == null)
1459            actionMap = new ActionMap();
1460        return actionMap;
1461    }
1462
1463    public void setInputMap(InputMap inputMap) {
1464        this.inputMap = inputMap;
1465    }
1466
1467    public InputMap getInputMap() {
1468        return inputMap;
1469    }
1470
1471    protected void processLowLevelEvent(String JavaDoc name, String JavaDoc[] values) {
1472    }
1473
1474    protected boolean processKeyEvents(String JavaDoc[] values) {
1475        if (actionMap == null)
1476            return false;
1477
1478        if (log.isDebugEnabled())
1479            log.debug("processKeyEvents " + Arrays.asList(values));
1480
1481        boolean arm = false;
1482        for (int i = 0; i < values.length; i++) {
1483            String JavaDoc value = values[i];
1484            Action action = actionMap.get(value);
1485            if (action != null) {
1486                actionEvents.put(action, new ActionEvent JavaDoc(this, 0, value));
1487                arm = true;
1488            }
1489        }
1490        if (arm)
1491            SForm.addArmedComponent((LowLevelEventListener) this);
1492
1493        return arm;
1494    }
1495
1496    public void fireFinalEvents() {
1497        fireKeyEvents();
1498    }
1499
1500    protected void fireKeyEvents() {
1501        for (Iterator JavaDoc iterator = actionEvents.entrySet().iterator(); iterator.hasNext();) {
1502            Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
1503            Action action = (Action) entry.getKey();
1504            ActionEvent JavaDoc event = (ActionEvent JavaDoc) entry.getValue();
1505            action.actionPerformed(event);
1506        }
1507        actionEvents.clear();
1508    }
1509
1510    /**
1511     * Makes this <code>SComponent</code> unavailable.
1512     * This Method is called internal and should not be called directly
1513     */

1514    public void removeNotify() {
1515    }
1516
1517    public ArrayList JavaDoc getMenus() {
1518        ArrayList JavaDoc menus = new ArrayList JavaDoc();
1519        if (isVisible()) {
1520            SPopupMenu pmenu = getComponentPopupMenu();
1521            if (pmenu != null) {
1522                menus.add(pmenu);
1523            }
1524        }
1525        return menus;
1526    }
1527}
Popular Tags