0001: /*
0002: * Copyright Javelin Software, All rights reserved.
0003: */
0004:
0005: package com.javelin.swinglets;
0006:
0007: import java.awt.*;
0008: import java.util.*;
0009: import java.awt.event.*;
0010: import java.io.*;
0011: import java.beans.*;
0012:
0013: import javax.servlet.http.*;
0014:
0015: import com.javelin.swinglets.border.*;
0016: import com.javelin.swinglets.plaf.*;
0017: import com.javelin.swinglets.event.*;
0018:
0019: /**
0020: * SComponent is the top level object in the Swinglet Document Model.
0021: * <P>
0022: * The Swinglet DOM model is designed to look like the Swing DOM model.
0023: * <P>
0024: * There are many issues that prevent the Swing classes unsuitable for
0025: * use in a server. For example the Swing code runs in is own thread.
0026: * Another issue is the LookAndFeel which is VM wide. In Swinglets it
0027: * needs to vary on a Thread by Thread, and even Component by Component
0028: * basis. Another issue is that Swing paints its components onto a
0029: * Graphic area, whilst HTML is written to an output stream. Swinglets
0030: * has been designed to handle both scenarios.
0031: * <P>
0032: * Every component can set a Look and Feel. The Look and feel determines
0033: * how to render the Component.
0034: * <P>
0035: * Every component has a name. This property is infrequently used in Swing
0036: * but is used to heavily in Swinglets to reference the Components.
0037: * <P>
0038: * Every component is associated with a SwingletManager. The SwingletManager
0039: * is used to manage the context of the components.
0040: * <P>
0041: * Every component fires property change events for bound properties. These can
0042: * be listening to using the property change listeners. Every component also
0043: * has a hashtable of key-value pairs associated with it called clientProperties,
0044: * <P>
0045: * Every component can have a number of scripts associated with it.
0046: *
0047: * @author Robin Sharp
0048: */
0049:
0050: public abstract class SComponent {
0051: /**
0052: * Construct a new SComponent;
0053: */
0054: public SComponent() {
0055: this .lookAndFeel = SUIManager.getLookAndFeel();
0056: setUI(lookAndFeel.getUI(this ));
0057: }
0058:
0059: /**
0060: * Returns the MIME type for the current components.
0061: */
0062: public String getContentType() {
0063: return getLookAndFeel().getContentType();
0064: }
0065:
0066: /**
0067: * Get the SwingletManager associated with this session.
0068: * SwingletManagers are associated by thread. This delegates the property
0069: * to the SwingletManager method.
0070: */
0071: public SwingletManager getSwingletManager() {
0072: return SwingletManager.getSwingletManager();
0073: }
0074:
0075: /**
0076: * Set the SwingletManager associated with this session. If this is
0077: * null it is removed. This delegates the property to the SwingletManager
0078: * method.
0079: */
0080: public void setSwingletManager(SwingletManager swingletManager) {
0081: dirty = true;
0082: SwingletManager.setSwingletManager(swingletManager);
0083: }
0084:
0085: /**
0086: * Returns the name of the L&F class that renders this component.
0087: */
0088: public Class getUIClass() {
0089: return SComponent.class;
0090: }
0091:
0092: /**
0093: * Set the UI on this component.
0094: */
0095: public SComponent setUI(SComponentUI ui) {
0096: dirty = true;
0097: this .ui = ui;
0098: return this ;
0099: }
0100:
0101: /**
0102: * Get the UI on this component.
0103: */
0104: public SComponentUI getUI() {
0105: if (ui == null) {
0106: throw new IllegalArgumentException("UI not set for "
0107: + getClass().getName());
0108: }
0109:
0110: return ui;
0111: }
0112:
0113: /**
0114: * Set the Look and Feel, and update the UI. Because this is
0115: * multi-user environment look and feel can vary on a per
0116: * component hierarchy basis.
0117: */
0118: public SComponent setLookAndFeel(String lookAndFeel) {
0119: return setLookAndFeel(SUIManager.getLookAndFeel(lookAndFeel));
0120: }
0121:
0122: /**
0123: * Set the Look and Feel, and update the UI. Because this is
0124: * multi-user environment look and feel can vary on a per
0125: * component hierarchy basis.
0126: */
0127: public SComponent setLookAndFeel(SLookAndFeel lookAndFeel) {
0128: if (this .lookAndFeel == lookAndFeel)
0129: return this ;
0130:
0131: this .lookAndFeel = lookAndFeel;
0132:
0133: setUI(this .lookAndFeel.getUI(this ));
0134:
0135: return this ;
0136: }
0137:
0138: /**
0139: * Get the LookAndFeel
0140: */
0141: public SLookAndFeel getLookAndFeel() {
0142: return lookAndFeel;
0143: }
0144:
0145: /**
0146: * Set the value as Text. By default this does nothing.
0147: */
0148: public SComponent setValueAsText(String text) {
0149: return this ;
0150: }
0151:
0152: /**
0153: * Construct a name for this component. Called by getName() when the
0154: * name is null. This based on an incrementing counter, so that every
0155: * component is guaranteed to have a unique name within a VM.
0156: */
0157: protected String constructComponentName() {
0158: return getUIClass().getName().substring(
0159: getUIClass().getName().lastIndexOf('.') + 1)
0160: + (COUNTER++);
0161: }
0162:
0163: /**
0164: * Gets the name of the component.
0165: */
0166: public String getName() {
0167: if (name == null) {
0168: name = constructComponentName();
0169: }
0170:
0171: return name;
0172: }
0173:
0174: /**
0175: * Sets the name of the component to the specified string.
0176: */
0177: public SComponent setName(String name) {
0178: firePropertyChange("name", this .name, this .name = name);
0179: return this ;
0180: }
0181:
0182: /**
0183: * Get a sub component by name. This will descend the component
0184: * hierarchy and return the SComponent, or null.
0185: */
0186: public SComponent getComponent(String name) {
0187: if (getName().equals(name))
0188: return this ;
0189:
0190: return null;
0191: }
0192:
0193: /**
0194: * Gets the parent of this component.
0195: */
0196: public SContainer getParent() {
0197: return parent;
0198: }
0199:
0200: /**
0201: * Convenience method for searching above this in the
0202: * component hierarchy and returns the first object of clazz it
0203: * finds. Can return null, if a clazz cannot be found.
0204: */
0205: public SContainer getAncestorOfClass(Class clazz) {
0206: if (clazz == null)
0207: return null;
0208:
0209: SContainer parent = getParent();
0210: while (parent != null && !clazz.isInstance(parent)) {
0211: parent = parent.getParent();
0212: }
0213:
0214: return parent;
0215: }
0216:
0217: /**
0218: * Convenience method for searching above this in the
0219: * component hierarchy and returns the first object of name it
0220: * finds. Can return null, if name cannot be found.
0221: */
0222: public SContainer getAncestorNamed(String name) {
0223: if (name == null)
0224: return null;
0225:
0226: SContainer parent = getParent();
0227:
0228: while (parent != null && !name.equals(parent.getName())) {
0229: parent = parent.getParent();
0230: }
0231:
0232: return parent;
0233: }
0234:
0235: /**
0236: * Get the top most component in the containment hierarchy.
0237: * This will be a SContainer.
0238: */
0239: public SContainer getTopLevelAncestor() {
0240: for (SComponent p = this ; p != null; p = p.getParent()) {
0241: if (p.getParent() == null && p instanceof SContainer) {
0242: return (SContainer) p;
0243: }
0244: }
0245:
0246: return null;
0247: }
0248:
0249: /**
0250: * Sets the parent of this component.
0251: */
0252: public SComponent setParent(SContainer parent) {
0253: firePropertyChange("parent", this .parent, this .parent = parent);
0254: return this ;
0255: }
0256:
0257: /**
0258: * Determines whether this component is visible. Components are
0259: * initially visible.
0260: */
0261: public boolean isVisible() {
0262: return visible;
0263: }
0264:
0265: /**
0266: * Shows or hides this component depending on the value of parameter .
0267: */
0268: public SComponent setVisible(boolean visible) {
0269: firePropertyChange("visible", !visible, this .visible = visible);
0270: return this ;
0271: }
0272:
0273: /**
0274: * Determines whether this component is enabled.
0275: */
0276: public boolean isEnabled() {
0277: return enabled;
0278: }
0279:
0280: /**
0281: * Enables or disables this component depending on the value of parameter.
0282: * Netscape doesn't implement this. So the browser will have to sniff out
0283: * Netscape and replace the disabled form elements with IE images.
0284: */
0285: public SComponent setEnabled(boolean enabled) {
0286: firePropertyChange("enabled", !enabled, this .enabled = enabled);
0287: return this ;
0288: }
0289:
0290: /**
0291: * Get the tab index.
0292: */
0293: public int getTabIndex() {
0294: return tabIndex;
0295: }
0296:
0297: /**
0298: * Set the tab index.
0299: */
0300: public SComponent setTabIndex(int tabIndex) {
0301: firePropertyChange("tabIndex", this .tabIndex,
0302: this .tabIndex = tabIndex);
0303: return this ;
0304: }
0305:
0306: /**
0307: * Gets the foreground color of this component.
0308: */
0309: public SColor getForeground() {
0310: if (foreground == null && parent != null) {
0311: return parent.getForeground();
0312: }
0313:
0314: return foreground;
0315: }
0316:
0317: /**
0318: * Sets the foreground color of this component.
0319: */
0320: public SComponent setForeground(SColor foreground) {
0321: firePropertyChange("foreground", this .foreground,
0322: this .foreground = foreground);
0323: return this ;
0324: }
0325:
0326: /**
0327: * Gets the background color of this component, or the parents background.
0328: */
0329: public SColor getBackground() {
0330: if (background == null && parent != null) {
0331: return parent.getBackground();
0332: }
0333:
0334: return background;
0335: }
0336:
0337: /**
0338: * Sets the background color of this component.
0339: */
0340: public SComponent setBackground(SColor background) {
0341: firePropertyChange("background", this .background,
0342: this .background = background);
0343: return this ;
0344: }
0345:
0346: /**
0347: * Check whether this component is opaque. If true the
0348: * background is painted, other wise it is inherited from
0349: * it context.
0350: */
0351: public boolean isOpaque() {
0352: return opaque;
0353: }
0354:
0355: /**
0356: * Sets the opacity background color of this component.
0357: */
0358: public SComponent setOpaque(boolean opaque) {
0359: firePropertyChange("opaque", this .opaque, this .opaque = opaque);
0360: return this ;
0361: }
0362:
0363: /**
0364: * Gets the font of this component.
0365: */
0366: public SFont getFont() {
0367: if (parent == null) {
0368: return font;
0369: }
0370:
0371: SFont pfont = parent.getFont();
0372:
0373: if (pfont == null) {
0374: return font;
0375: }
0376:
0377: if (font == null) {
0378: return pfont;
0379: }
0380:
0381: String newname = font.getName();
0382: int newstyle = font.getStyle();
0383: int newsize = font.getSize();
0384:
0385: if (newname.length() == 0) {
0386: newname = pfont.getName();
0387: }
0388: if (newstyle == -1) {
0389: newstyle = pfont.getStyle();
0390: }
0391: if (newsize == 0) {
0392: newsize = pfont.getSize();
0393: }
0394:
0395: return SFont.getFont(newname, newstyle, newsize);
0396: }
0397:
0398: /**
0399: * Sets the font of this component. Uses SFont to find font.
0400: */
0401: public SComponent setFont(String name, int style, int size) {
0402: firePropertyChange("font", this .font, this .font = SFont
0403: .getFont(name, style, size));
0404: return this ;
0405: }
0406:
0407: /**
0408: * Sets the font of this component.
0409: */
0410: public SComponent setFont(SFont font) {
0411: this .font = font;
0412: return this ;
0413: }
0414:
0415: /**
0416: * Returns the alignment of the component along the X axis.
0417: */
0418: public int getHorizontalAlignment() {
0419: return horizontalAlignment;
0420: }
0421:
0422: /**
0423: * Sets the alignment of the component along the X axis.
0424: * One of SConstants LEFT, CENTER, RIGHT
0425: */
0426: public SComponent setHorizontalAlignment(int horizontalAlignment) {
0427: firePropertyChange("horizontalAlignment",
0428: this .horizontalAlignment,
0429: this .horizontalAlignment = horizontalAlignment);
0430: return this ;
0431: }
0432:
0433: /**
0434: * Returns the alignment of the component along the Y axis.
0435: */
0436: public int getVerticalAlignment() {
0437: return verticalAlignment;
0438: }
0439:
0440: /**
0441: * Sets the alignment of the component along the Y axis.
0442: * One of SConstants TOP, MIDDLE, BOTTOM
0443: */
0444: public SComponent setVerticalAlignment(int verticalAlignment) {
0445: firePropertyChange("verticalAlignment", this .verticalAlignment,
0446: this .verticalAlignment = verticalAlignment);
0447: return this ;
0448: }
0449:
0450: /**
0451: * Sets the border of this component. The Border object is
0452: * responsible for defining the insets for the component
0453: * (overriding any insets set directly on the component) and
0454: * for optionally rendering any border decorations within the
0455: * bounds of those insets.
0456: */
0457: public SComponent setBorder(SBorder border) {
0458: firePropertyChange("border", this .border, this .border = border);
0459: return this ;
0460: }
0461:
0462: /**
0463: * Returns the border of this component or null if no border is
0464: * currently set.
0465: */
0466: public SBorder getBorder() {
0467: return border;
0468: }
0469:
0470: /**
0471: * Gets the locale of this component.
0472: */
0473: public Locale getLocale() {
0474: if (locale != null) {
0475: return locale;
0476: }
0477:
0478: SContainer parent = this .parent;
0479:
0480: if (parent == null) {
0481: throw new IllegalStateException(
0482: "This component must have a parent in order to determine its locale");
0483: } else {
0484: return parent.getLocale();
0485: }
0486: }
0487:
0488: /**
0489: * Sets the locale of this component.
0490: */
0491: public SComponent setLocale(Locale locale) {
0492: firePropertyChange("locale", this .locale, this .locale = locale);
0493: return this ;
0494: }
0495:
0496: /**
0497: * Returns the size of this component in the form of a
0498: * <codeDimension</code object. The <codeheight</code
0499: * field of the <codeDimension</code object contains
0500: * this component's height, and the <codewidth</code
0501: * field of the <codeDimension</code object contains
0502: * this component's width.
0503: */
0504: public Dimension getSize() {
0505: if (size == null) {
0506: size = new Dimension(0, 0);
0507: }
0508:
0509: return size;
0510: }
0511:
0512: /**
0513: * Resizes this component so that it has width <codewidth</code
0514: * and <codeheight</code.
0515: * <p
0516: * This is used in the STable to fix the cell width or height.
0517: * A negative width of height denotes a percentage.
0518: */
0519: public SComponent setSize(int width, int height) {
0520: firePropertyChange("size", this .size,
0521: this .size = new Dimension(width, height));
0522: return this ;
0523: }
0524:
0525: /**
0526: * Resizes this component so that it has width <codewidth</code
0527: * and <codeheight</code.
0528: */
0529: public SComponent setSize(Dimension size) {
0530: firePropertyChange("size", this .size, this .size = size);
0531: return this ;
0532: }
0533:
0534: /**
0535: * Get the cursor.
0536: */
0537: public Cursor getCursor() {
0538: return cursor;
0539: }
0540:
0541: /**
0542: * Set the cursor.
0543: */
0544: public void setCursor(Cursor cursor) {
0545: firePropertyChange("cursor", this .cursor, this .cursor = cursor);
0546: }
0547:
0548: /**
0549: * Notifies this component that it has been added to a container.
0550: */
0551: public void addNotify() {
0552: }
0553:
0554: /**
0555: * Notifies this component that it has been remove from its container.
0556: */
0557: public void removeNotify() {
0558: }
0559:
0560: /**C
0561: * Registers the text to display in a tool tip.
0562: */
0563: public SComponent setToolTipText(String toolTipText) {
0564: firePropertyChange("toolTipText", this .toolTipText,
0565: this .toolTipText = toolTipText);
0566: return this ;
0567: }
0568:
0569: /**
0570: * Return the tooltip string that has been set with setToolTipText()
0571: */
0572: public String getToolTipText() {
0573: return toolTipText;
0574: }
0575:
0576: // CLIENT PRPOERTIES //////////////////////////////////////////////////////////
0577:
0578: /**
0579: * @return a count of the client properties.
0580: */
0581: public int getClientPropertyCount() {
0582: if (clientProperties == null) {
0583: return 0;
0584: }
0585:
0586: return clientProperties.size();
0587: }
0588:
0589: /**
0590: * @return an enumeration of keys.
0591: */
0592: public Enumeration getClientKeys() {
0593: if (clientProperties == null) {
0594: clientProperties = new Hashtable(2);
0595: }
0596: return clientProperties.keys();
0597: }
0598:
0599: /**
0600: * Returns the value of the property with the specified key. Only
0601: * properties added with <codeputClientProperty</code will return
0602: * a non-null value.
0603: */
0604: public final Object getClientProperty(Object key) {
0605: if (clientProperties == null) {
0606: return null;
0607: } else {
0608: return clientProperties.get(key);
0609: }
0610: }
0611:
0612: /**
0613: * Returns the value of the property with the specified key.
0614: * If no value exists the defaul value is returned.
0615: */
0616: public final Object getClientProperty(Object key,
0617: Object defaultValue) {
0618: if (clientProperties == null) {
0619: return defaultValue;
0620: } else {
0621: Object value = clientProperties.get(key);
0622: return value == null ? defaultValue : value;
0623: }
0624: }
0625:
0626: /**
0627: * Add an arbitrary key/value "client property" to this component.
0628: * <p
0629: * The clientProperty dictionary is not intended to support large
0630: * scale extensions to SComponent nor should be it considered an
0631: * alternative to subclassing when designing a new component.
0632: */
0633: public final SComponent putClientProperty(Object key, Object value) {
0634: if (clientProperties == null) {
0635: clientProperties = new Hashtable();
0636: }
0637: if (value == null) {
0638: clientProperties.remove(key);
0639: } else {
0640: clientProperties.put(key, value);
0641: }
0642:
0643: return this ;
0644: }
0645:
0646: /**
0647: * @see com.javelin.swinglets.SComponent#firePropertyChange()
0648: */
0649: public void firePropertyChange() {
0650: if (propertyChangeSupport != null) {
0651: propertyChangeSupport.firePropertyChange(null, null, null);
0652: }
0653: }
0654:
0655: /**
0656: * @see com.javelin.swinglets.SComponent#setFiringSuspended(boolean)
0657: * @see com.javelin.beans.PropertyChangeSupport#setFiringSuspended(boolean)
0658: */
0659: public void setFiringSuspended(boolean firingSuspended) {
0660: this .firingSuspended = firingSuspended;
0661: }
0662:
0663: /**
0664: * @see com.javelin.swinglets.SComponent#isFiringSuspended
0665: * @see com.javelin.beans.PropertyChangeSupport#isFiringSuspended
0666: */
0667: public boolean isFiringSuspended() {
0668: return firingSuspended;
0669: }
0670:
0671: /**
0672: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0673: */
0674: public final void firePropertyChange(String propertyName,
0675: Object oldValue, Object newValue) {
0676: if (oldValue != null && newValue != null
0677: && oldValue.equals(newValue))
0678: return;
0679:
0680: dirty = true;
0681:
0682: if (propertyChangeSupport == null)
0683: return;
0684:
0685: //System.out.println( "AbstractBean.firePropertyChange( " + propertyName + ")" );
0686: propertyChangeSupport.firePropertyChange(propertyName,
0687: oldValue, newValue);
0688: }
0689:
0690: /**
0691: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0692: */
0693: protected final void firePropertyChange(String propertyName,
0694: byte oldValue, byte newValue) {
0695: if (oldValue == newValue)
0696: return;
0697:
0698: dirty = true;
0699:
0700: if (propertyChangeSupport != null) {
0701: propertyChangeSupport.firePropertyChange(propertyName,
0702: new Byte(oldValue), new Byte(newValue));
0703: }
0704: }
0705:
0706: /**
0707: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0708: */
0709: protected final void firePropertyChange(String propertyName,
0710: char oldValue, char newValue) {
0711: if (oldValue == newValue)
0712: return;
0713:
0714: dirty = true;
0715:
0716: if (propertyChangeSupport != null) {
0717: propertyChangeSupport.firePropertyChange(propertyName,
0718: new Character(oldValue), new Character(newValue));
0719: }
0720: }
0721:
0722: /**
0723: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0724: */
0725: protected final void firePropertyChange(String propertyName,
0726: short oldValue, short newValue) {
0727: if (oldValue == newValue)
0728: return;
0729:
0730: dirty = true;
0731:
0732: if (propertyChangeSupport != null) {
0733: propertyChangeSupport.firePropertyChange(propertyName,
0734: new Short(oldValue), new Short(newValue));
0735: }
0736: }
0737:
0738: /**
0739: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0740: */
0741: protected final void firePropertyChange(String propertyName,
0742: int oldValue, int newValue) {
0743: if (oldValue == newValue)
0744: return;
0745:
0746: dirty = true;
0747:
0748: if (propertyChangeSupport != null) {
0749: propertyChangeSupport.firePropertyChange(propertyName,
0750: new Integer(oldValue), new Integer(newValue));
0751: }
0752: }
0753:
0754: /**
0755: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0756: */
0757: protected final void firePropertyChange(String propertyName,
0758: long oldValue, long newValue) {
0759: if (oldValue == newValue)
0760: return;
0761:
0762: dirty = true;
0763:
0764: if (propertyChangeSupport != null) {
0765: propertyChangeSupport.firePropertyChange(propertyName,
0766: new Long(oldValue), new Long(newValue));
0767: }
0768: }
0769:
0770: /**
0771: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0772: */
0773: protected final void firePropertyChange(String propertyName,
0774: float oldValue, float newValue) {
0775: if (oldValue == newValue)
0776: return;
0777:
0778: dirty = true;
0779:
0780: if (propertyChangeSupport != null) {
0781: propertyChangeSupport.firePropertyChange(propertyName,
0782: new Float(oldValue), new Float(newValue));
0783: }
0784: }
0785:
0786: /**
0787: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0788: */
0789: protected final void firePropertyChange(String propertyName,
0790: double oldValue, double newValue) {
0791: if (oldValue == newValue)
0792: return;
0793:
0794: dirty = true;
0795:
0796: if (propertyChangeSupport != null) {
0797: propertyChangeSupport.firePropertyChange(propertyName,
0798: new Double(oldValue), new Double(newValue));
0799: }
0800: }
0801:
0802: /**
0803: * @see com.javelin.swinglets.SComponent#firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object)
0804: */
0805: protected final void firePropertyChange(String propertyName,
0806: boolean oldValue, boolean newValue) {
0807: if (oldValue == newValue)
0808: return;
0809:
0810: dirty = true;
0811:
0812: if (propertyChangeSupport != null) {
0813: propertyChangeSupport.firePropertyChange(propertyName,
0814: new Boolean(oldValue), new Boolean(newValue));
0815: }
0816: }
0817:
0818: /**
0819: * @see com.javelin.swinglets.SComponent#addPropertyChangeListener(java.beans.PropertyChangeListener)
0820: */
0821: public synchronized SComponent addPropertyChangeListener(
0822: PropertyChangeListener listener)
0823: throws TooManyListenersException {
0824: if (propertyChangeSupport == null) {
0825: propertyChangeSupport = new PropertyChangeSupport(this );
0826: }
0827:
0828: propertyChangeSupport.addPropertyChangeListener(listener);
0829:
0830: return this ;
0831: }
0832:
0833: /**
0834: * @see com.javelin.swinglets.SComponent#addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
0835: * @since JDK 1.2
0836: */
0837: public synchronized SComponent addPropertyChangeListener(
0838: String propertyName, PropertyChangeListener listener)
0839: throws TooManyListenersException {
0840: if (propertyChangeSupport == null) {
0841: propertyChangeSupport = new PropertyChangeSupport(this );
0842: }
0843:
0844: propertyChangeSupport.addPropertyChangeListener(propertyName,
0845: listener);
0846:
0847: return this ;
0848: }
0849:
0850: /**
0851: * @see com.javelin.swinglets.SComponent#removePropertyChangeListener(java.beans.PropertyChangeListener)
0852: */
0853: public synchronized SComponent removePropertyChangeListener(
0854: PropertyChangeListener listener) {
0855: if (propertyChangeSupport != null) {
0856: propertyChangeSupport
0857: .removePropertyChangeListener(listener);
0858: }
0859: return this ;
0860: }
0861:
0862: /**
0863: * @see com.javelin.swinglets.SComponent#removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
0864: * @since JDK 1.2
0865: */
0866: public synchronized SComponent removePropertyChangeListener(
0867: String propertyName, PropertyChangeListener listener) {
0868: if (propertyChangeSupport != null) {
0869: propertyChangeSupport.removePropertyChangeListener(
0870: propertyName, listener);
0871: }
0872:
0873: return this ;
0874: }
0875:
0876: /**
0877: * Check if there are any listeners on the bean.
0878: * @since JDK 1.2
0879: */
0880: protected final boolean hasListeners() {
0881: if (propertyChangeSupport == null) {
0882: return false;
0883: } else {
0884: return true;
0885: }
0886: }
0887:
0888: /**
0889: * Check if there are any listeners for a specific property.
0890: */
0891: protected final boolean hasListeners(String propertyName) {
0892: if (propertyChangeSupport != null) {
0893: return propertyChangeSupport.hasListeners(propertyName);
0894: }
0895: return false;
0896: }
0897:
0898: // SCRIPTS ///////////////////////////////////////////////////////////////////
0899:
0900: /**
0901: * Get script count.
0902: */
0903: public int getScriptCount() {
0904: if (scripts == null)
0905: return 0;
0906:
0907: return scripts.size();
0908: }
0909:
0910: /**
0911: * Get the script.
0912: */
0913: public Enumeration getScripts() {
0914: if (scripts == null) {
0915: scripts = new Vector(2);
0916: }
0917:
0918: return scripts.elements();
0919: }
0920:
0921: /**
0922: * Add the script. This will add one script.
0923: */
0924: public SComponent addScript(SScript script) {
0925: dirty = true;
0926:
0927: if (scripts == null) {
0928: scripts = new Vector(2);
0929: }
0930:
0931: scripts.addElement(script);
0932:
0933: return this ;
0934: }
0935:
0936: /**
0937: * Remove the script. This will remove one script.
0938: */
0939: public SComponent removeScript(SScript script) {
0940: if (scripts == null)
0941: return this ;
0942:
0943: dirty = true;
0944:
0945: scripts.removeElement(script);
0946:
0947: return this ;
0948: }
0949:
0950: // DISPATCH & EVENTS //////////////////////////////////////////////////////
0951:
0952: /**
0953: * Utility method to add a listener to the current UI.
0954: */
0955: protected SComponent addUIListener(EventListener listener) {
0956: dirty = true;
0957: getUI().addListener(listener);
0958: return this ;
0959: }
0960:
0961: /**
0962: * Utility method to remove a listener to the current UI.
0963: */
0964: protected SComponent removeUIListener(EventListener listener) {
0965: dirty = true;
0966: getUI().removeListener(listener);
0967: return this ;
0968: }
0969:
0970: /**
0971: * Adds the specified component listener to receive component events from
0972: * this component.
0973: * <P>
0974: * This method will set the listener on the current look and feel.
0975: */
0976: public SComponent addComponentListener(ComponentListener listener) {
0977: addUIListener(listener);
0978: return this ;
0979: }
0980:
0981: /**
0982: * Removes the specified component listener so that it no longer
0983: * receives component events from this component.
0984: * <P>
0985: * This method will set the listener on the current look and feel.
0986: */
0987: public SComponent removeComponentListener(ComponentListener listener) {
0988: removeUIListener(listener);
0989: return this ;
0990: }
0991:
0992: /**
0993: * Adds the specified focus listener to receive focus events from
0994: * this component when this component gains input focus.
0995: * <P>
0996: * This method will set the listener on the current look and feel.
0997: */
0998: public SComponent addFocusListener(FocusListener listener) {
0999: addUIListener(listener);
1000: return this ;
1001: }
1002:
1003: /**
1004: * Removes the specified focus listener so that it no longer
1005: * receives focus events from this component.
1006: * <P>
1007: * This method will set the listener on the current look and feel.
1008: */
1009: public SComponent removeFocusListener(FocusListener listener) {
1010: removeUIListener(listener);
1011: return this ;
1012: }
1013:
1014: /**
1015: * Adds the specified key listener to receive key events from
1016: * this component.
1017: * <P>
1018: * This method will set the listener on the current look and feel.
1019: */
1020: public SComponent addKeyListener(KeyListener listener) {
1021: addUIListener(listener);
1022: return this ;
1023: }
1024:
1025: /**
1026: * Removes the specified key listener so that it no longer
1027: * receives key events from this component.
1028: * <P>
1029: * This method will set the listener on the current look and feel.
1030: */
1031: public SComponent removeKeyListener(KeyListener listener) {
1032: removeUIListener(listener);
1033: return this ;
1034: }
1035:
1036: /**
1037: * Adds the specified mouse listener to receive mouse events from
1038: * this component.
1039: * <P>
1040: * This method will set the listener on the current look and feel.
1041: */
1042: public SComponent addMouseListener(MouseListener listener) {
1043: addUIListener(listener);
1044: return this ;
1045: }
1046:
1047: /**
1048: * Removes the specified mouse listener so that it no longer
1049: * receives mouse events from this component.
1050: * <P>
1051: * This method will set the listener on the current look and feel.
1052: */
1053: public SComponent removeMouseListener(MouseListener listener) {
1054: removeUIListener(listener);
1055: return this ;
1056: }
1057:
1058: /**
1059: * Adds the specified mouse motion listener to receive mouse motion events from
1060: * this component.
1061: * <P>
1062: * This method will set the listener on the current look and feel.
1063: */
1064: public SComponent addMouseMotionListener(
1065: MouseMotionListener listener) {
1066: addUIListener(listener);
1067: return this ;
1068: }
1069:
1070: /**
1071: * Removes the specified mouse motion listener so that it no longer
1072: * receives mouse motion events from this component.
1073: * <P>
1074: * This method will set the listener on the current look and feel.
1075: */
1076: public SComponent removeMouseMotionListener(
1077: MouseMotionListener listener) {
1078: removeUIListener(listener);
1079: return this ;
1080: }
1081:
1082: /**
1083: * Dispatches an event to this component or one of its sub components.
1084: */
1085: public void dispatchEvent(AWTEvent event) {
1086: if (event.getSource() == null)
1087: return;
1088:
1089: if (event.getSource() instanceof SComponent) {
1090: dirty = true;
1091: processEvent(event);
1092: }
1093: }
1094:
1095: /**
1096: * Processes events occurring on this component. By default this
1097: * method calls the appropriate process event method for the given
1098: * class of event.
1099: */
1100: protected void processEvent(AWTEvent event) {
1101: if (event instanceof ActionEvent) {
1102: processActionEvent((ActionEvent) event);
1103: }
1104: }
1105:
1106: /**
1107: * Process an ActionEvent. The default behaviour is to consume the event.
1108: */
1109: public void processActionEvent(ActionEvent event) {
1110: if (actionListener != null) {
1111: actionListener.actionPerformed(event);
1112: }
1113: }
1114:
1115: /**
1116: * Add an ActionEvent listener.
1117: */
1118: public SComponent addActionListener(ActionListener l) {
1119: actionListener = AWTEventMulticaster.add(actionListener, l);
1120: return this ;
1121: }
1122:
1123: /**
1124: * Remove an ActionEvent listener.
1125: */
1126: public SComponent removeActionListener(ActionListener l) {
1127: actionListener = AWTEventMulticaster.remove(actionListener, l);
1128: return this ;
1129: }
1130:
1131: /**
1132: * Get the URL for this component. So that its action event will be called back.
1133: * <P>
1134: * If the SwingletManger.getUrl() is set that is prepended.
1135: * <P>
1136: * [URL] + SOURCE_CONTAINER + SOURCE_COMPONENT.
1137: */
1138: public String getComponentUrl() {
1139: if (componentUrl == null) {
1140: StringBuffer buf = new StringBuffer();
1141:
1142: //Get the absolute Path
1143: if (getSwingletManager().getUrl() != null) {
1144: buf.append(getSwingletManager().getUrl());
1145: }
1146:
1147: //Get the Relative Path
1148: buf.append("?");
1149:
1150: buf.append(SConstants.SOURCE_CONTAINER);
1151: buf.append("=");
1152: SContainer container = getTopLevelAncestor();
1153:
1154: if (container == null) {
1155: buf.append(getName());
1156: } else {
1157: buf.append(container.getName());
1158: }
1159:
1160: buf.append("&");
1161: buf.append(SConstants.SOURCE_COMPONENT);
1162: buf.append("=");
1163: buf.append(getName());
1164:
1165: componentUrl = buf.toString();
1166: }
1167:
1168: return componentUrl;
1169: }
1170:
1171: // PAINTING ///////////////////////////////////////////////////////////////////////////
1172:
1173: /**
1174: * Paint this component header, then body to the Object
1175: * This can be a PrintWriter, OutputStream or Graphics,
1176: * depending on the LookAndFeel.
1177: */
1178: public void paint(Object out) {
1179: paintHeader(out);
1180: paintComponentHeader(out);
1181: paintComponent(out);
1182: paintComponentFooter(out);
1183: }
1184:
1185: /**
1186: * This is the first time this object is painted. This
1187: * can be used by sub classes to construct the object
1188: * the first time it is rendered.
1189: */
1190: public void onFirstPaint() {
1191: }
1192:
1193: /**
1194: * Paint this component in the header.
1195: */
1196: public void paintHeader(Object out) {
1197: if (!rendered) {
1198: onFirstPaint();
1199: rendered = true;
1200: }
1201:
1202: onPaintHeader();
1203:
1204: getUI().updateHeader(out, this );
1205: }
1206:
1207: /**
1208: * This is called everytime a component header gets rendered
1209: * can be used by sub classes to make last minute changes based on state
1210: */
1211: public void onPaintHeader() {
1212: }
1213:
1214: /**
1215: * Paint this component header.
1216: */
1217: public void paintComponentHeader(Object out) {
1218: if (!rendered) {
1219: onFirstPaint();
1220: rendered = true;
1221: }
1222:
1223: onPaintComponentHeader();
1224:
1225: if (border != null) {
1226: border.paintHeader(out, this );
1227: }
1228:
1229: getUI().updateComponentHeader(out, this );
1230: }
1231:
1232: /**
1233: * This is called BEFORE a component header gets rendered
1234: * can be used by sub classes to make last minute changes based on state
1235: */
1236: public void onPaintComponentHeader() {
1237: }
1238:
1239: /**
1240: * Paint this component body.
1241: */
1242: public void paintComponent(Object out) {
1243: if (!rendered) {
1244: onFirstPaint();
1245: rendered = true;
1246: }
1247:
1248: onPaintComponent();
1249:
1250: if (border != null) {
1251: border.paint(out, this );
1252: } else {
1253: getUI().update(out, this );
1254: }
1255: }
1256:
1257: /**
1258: * This is called everytime a component gets rendered
1259: * can be used by sub classes to make last minute changes based on state
1260: */
1261: public void onPaintComponent() {
1262: }
1263:
1264: /**
1265: * Paint this component footer.
1266: */
1267: public void paintComponentFooter(Object out) {
1268: if (!rendered) {
1269: onFirstPaint();
1270: rendered = true;
1271: }
1272:
1273: getUI().updateComponentFooter(out, this );
1274:
1275: if (border != null) {
1276: border.paintFooter(out, this );
1277: }
1278:
1279: onPaintComponentFooter();
1280: }
1281:
1282: /**
1283: * This is called AFTER a component footer gets rendered
1284: * can be used by sub classes to make last minute changes based on state
1285: */
1286: public void onPaintComponentFooter() {
1287: }
1288:
1289: /**
1290: * Check whether the painting cached in a String. If this is false then
1291: * the getSwingletManager().isCached() policy will be checked.
1292: */
1293: public boolean isCached() {
1294: if (!getSwingletManager().isCached())
1295: return false;
1296:
1297: return cached;
1298: }
1299:
1300: /**
1301: * Set whether the painting cached in a String. To set a thread wide
1302: * policy set the getSwingletManager().setCached() property.
1303: */
1304: public void setCached(boolean cached) {
1305: if (cached == this .cached)
1306: return;
1307:
1308: this .cached = cached;
1309: }
1310:
1311: // OBJECT ///////////////////////////////////////////////////////////////
1312:
1313: /**
1314: * Hashcode. Is based on the name.
1315: */
1316: public int hashCode() {
1317: return getName().hashCode();
1318: }
1319:
1320: /**
1321: * To String returns the stream that would be painted. <br>
1322: * This is useful for debugging. <br>
1323: * This will not cache the data.
1324: */
1325: public String toString() {
1326: if (sw == null) {
1327: sw = new StringWriter();
1328: pw = new PrintWriter(sw);
1329: }
1330:
1331: if (dirty || !isCached()) {
1332: //Set the length to 0 and reuse the StringBuffer.
1333: sw.getBuffer().setLength(0);
1334:
1335: //paint the component
1336: paint(pw);
1337:
1338: //Mark the component as clean
1339: dirty = false;
1340: }
1341:
1342: return sw.toString();
1343: }
1344:
1345: /**
1346: * Equals is based on the name and class.
1347: */
1348: public boolean equals(Object object) {
1349: if (object == null)
1350: return false;
1351: if (this == object)
1352: return true;
1353:
1354: if (object instanceof SComponent
1355: && ((SComponent) object).getName() == getName()
1356: && object.getClass().equals(getClass())) {
1357: return true;
1358: }
1359:
1360: return false;
1361: }
1362:
1363: // PRIVATE //////////////////////////////////////////////////////////
1364:
1365: protected static long COUNTER;
1366:
1367: //Component properties
1368: protected Cursor cursor;
1369: protected String name;
1370: protected SContainer parent;
1371: protected boolean visible = true;
1372: protected boolean enabled = true;
1373: protected SColor background;
1374: protected SColor foreground;
1375: protected boolean opaque = true;
1376: protected SFont font;
1377: protected int horizontalAlignment = SConstants.DEFAULT;
1378: protected int verticalAlignment = SConstants.DEFAULT;
1379: protected Locale locale; //Move to SwingletManager
1380: protected Dimension size;
1381: protected String toolTipText;
1382: protected SBorder border;
1383: protected int tabIndex;
1384: protected String componentUrl;
1385: protected Hashtable clientProperties;
1386:
1387: //Look and Feel
1388: protected SComponentUI ui;
1389: protected SLookAndFeel lookAndFeel;
1390:
1391: //Events and Scripts
1392: protected boolean firingSuspended;
1393: protected PropertyChangeSupport propertyChangeSupport;
1394: protected ActionListener actionListener = null;
1395: protected Vector scripts;
1396:
1397: //Optimization - and caching.
1398: protected boolean cached;
1399: protected boolean rendered;
1400: protected boolean dirty = true;
1401:
1402: StringWriter sw = new StringWriter();
1403: PrintWriter pw = new PrintWriter(sw);
1404:
1405: }
|