001: /* *************************************************************************
002:
003: Millstone(TM)
004: Open Sourced User Interface Library for
005: Internet Development with Java
006:
007: Millstone is a registered trademark of IT Mill Ltd
008: Copyright (C) 2000-2005 IT Mill Ltd
009:
010: *************************************************************************
011:
012: This library is free software; you can redistribute it and/or
013: modify it under the terms of the GNU Lesser General Public
014: license version 2.1 as published by the Free Software Foundation.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: *************************************************************************
026:
027: For more information, contact:
028:
029: IT Mill Ltd phone: +358 2 4802 7180
030: Ruukinkatu 2-4 fax: +358 2 4802 7181
031: 20540, Turku email: info@itmill.com
032: Finland company www: www.itmill.com
033:
034: Primary source for MillStone information and releases: www.millstone.org
035:
036: ********************************************************************** */
037:
038: package org.millstone.base.ui;
039:
040: import java.util.Collection;
041: import java.util.HashSet;
042: import java.util.LinkedList;
043: import java.util.Locale;
044: import java.util.Map;
045: import java.util.Set;
046:
047: import org.millstone.base.Application;
048: import org.millstone.base.terminal.PaintException;
049: import org.millstone.base.terminal.PaintTarget;
050: import org.millstone.base.terminal.Resource;
051: import org.millstone.base.terminal.VariableOwner;
052:
053: /** Custom component provides simple implementation of Component interface for
054: * creation of new UI components by composition of existing components.
055: * <p>The component is used by inheriting the CustomComponent class and setting
056: * composite root inside the Custom component. The composite root itself
057: * can contain more components, but their interfaces are hidden from the
058: * users.</p>
059: *
060: * @author IT Mill Ltd.
061: * @version 3.1.1
062: * @since 3.0
063: */
064: public class CustomComponent implements Component {
065:
066: /** The root component implementing the custom component */
067: private Component root = null;
068:
069: /** The visibility of the component */
070: private boolean visible = true;
071:
072: /** The parent of the component */
073: private Component parent = null;
074:
075: /** Dependencies of the component, or null */
076: private HashSet dependencies = null;
077:
078: /** Type of the component */
079: private String componentType = null;
080:
081: /** List of repaint request listeners or null if not listened at all */
082: private LinkedList repaintRequestListeners = null;
083:
084: /** Are all the repaint listeners notified about recent changes ? */
085: private boolean repaintRequestListenersNotified = false;
086:
087: /** Construct new custom component.
088: *
089: * <p>The component is implemented by wrapping the methods of the
090: * composition root component given as parameter. The composition
091: * root must be set before the component can be used.</p>
092: */
093: public CustomComponent() {
094: }
095:
096: /** Construct new custom component.
097: *
098: * <p>The component is implemented by wrapping the methods of the
099: * composition root component given as parameter. The composition
100: * root must not be null and can not be changed after the composition.</p>
101: *
102: * @param compositionRoot The root of the composition component tree.
103: */
104: public CustomComponent(Component compositionRoot) {
105: setCompositionRoot(compositionRoot);
106: }
107:
108: /** Returns the composition root.
109: * @return Component Composition root
110: */
111: protected final Component getCompositionRoot() {
112: return root;
113: }
114:
115: /** Sets the compositions root.
116: * <p>The composition root must be set to non-null value before the
117: * component can be used. The composition root can only be set once.</p>
118: * @param compositionRoot The root of the composition component tree.
119: */
120: protected final void setCompositionRoot(Component compositionRoot) {
121: if (compositionRoot != root && root != null)
122: root.setParent(null);
123: this .root = compositionRoot;
124: if (root != null)
125: root.setParent(this );
126: }
127:
128: /* Basic component features ------------------------------------------ */
129:
130: public void attach() {
131: if (root != null)
132: root.attach();
133: }
134:
135: public void detach() {
136: if (root != null)
137: root.detach();
138: }
139:
140: public Application getApplication() {
141: if (parent == null)
142: return null;
143: return parent.getApplication();
144: }
145:
146: /** The caption of the custom component is by default the the
147: * caption of the root component, or null if the root is not set
148: */
149: public String getCaption() {
150: if (root == null)
151: return null;
152: return root.getCaption();
153: }
154:
155: /** The icon of the custom component is by default the the
156: * icon of the root component, or null if the root is not set
157: */
158: public Resource getIcon() {
159: if (root == null)
160: return null;
161: return root.getIcon();
162: }
163:
164: /** The icon of the custom component is by default the the
165: * locale of the parent or null if the parent is not set.
166: */
167: public Locale getLocale() {
168: if (parent == null)
169: return null;
170: return parent.getLocale();
171: }
172:
173: public Component getParent() {
174: return parent;
175: }
176:
177: /** Custom component does not implement custom styles by default and
178: * this function returns null.
179: */
180: public String getStyle() {
181: return null;
182: }
183:
184: public Window getWindow() {
185: if (parent == null)
186: return null;
187: return parent.getWindow();
188: }
189:
190: /** Custom component is allways enabled by default */
191: public boolean isEnabled() {
192: return true;
193: }
194:
195: /** Custom component is by default in the non-immediate mode. The immediateness
196: * of the custom component is defined by the components it is composed of.
197: */
198: public boolean isImmediate() {
199: return false;
200: }
201:
202: /** The custom components are not readonly by default. */
203: public boolean isReadOnly() {
204: return false;
205: }
206:
207: public boolean isVisible() {
208: return visible;
209: }
210:
211: /* Documentation copied from interface */
212: public void requestRepaint() {
213:
214: // The effect of the repaint request is identical to case where a
215: // child requests repaint
216: childRequestedRepaint(null);
217: }
218:
219: /* Documentation copied from interface */
220: public void childRequestedRepaint(Collection alreadyNotified) {
221:
222: // Notify listeners only once
223: if (!repaintRequestListenersNotified) {
224:
225: // Notify the listeners
226: if (repaintRequestListeners != null
227: && !repaintRequestListeners.isEmpty()) {
228: Object[] listeners = repaintRequestListeners.toArray();
229: RepaintRequestEvent event = new RepaintRequestEvent(
230: this );
231: for (int i = 0; i < listeners.length; i++) {
232: if (alreadyNotified == null)
233: alreadyNotified = new LinkedList();
234: if (!alreadyNotified.contains(listeners[i])) {
235: ((RepaintRequestListener) listeners[i])
236: .repaintRequested(event);
237: alreadyNotified.add(listeners[i]);
238: }
239: }
240: }
241:
242: repaintRequestListenersNotified = true;
243:
244: // Notify the parent
245: Component parent = getParent();
246: if (parent != null)
247: parent.childRequestedRepaint(alreadyNotified);
248:
249: }
250: }
251:
252: /* Documentation copied from interface */
253: public void addListener(RepaintRequestListener listener) {
254: if (repaintRequestListeners == null)
255: repaintRequestListeners = new LinkedList();
256: if (!repaintRequestListeners.contains(listener)) {
257: repaintRequestListeners.add(listener);
258: }
259: }
260:
261: /* Documentation copied from interface */
262: public void removeListener(RepaintRequestListener listener) {
263: if (repaintRequestListeners != null) {
264: repaintRequestListeners.remove(listener);
265: if (repaintRequestListeners.isEmpty())
266: repaintRequestListeners = null;
267: }
268: }
269:
270: /** The custom component is allways enabled by default. */
271: public void setEnabled(boolean enabled) {
272: }
273:
274: public void setParent(Component parent) {
275:
276: // If the parent is not changed, dont do nothing
277: if (parent == this .parent)
278: return;
279:
280: // Send detach event if the component have been connected to a window
281: if (getApplication() != null) {
282: detach();
283: this .parent = null;
284: }
285:
286: // Connect to new parent
287: this .parent = parent;
288:
289: // Send attach event if connected to a window
290: if (getApplication() != null)
291: attach();
292: }
293:
294: /** Changing the read-only mode of the component is not supported by default.
295: */
296: public void setReadOnly(boolean readOnly) {
297: }
298:
299: /** Changing the style of the component is not supported by default.
300: */
301: public void setStyle(String style) {
302: }
303:
304: public void setVisible(boolean visible) {
305: this .visible = visible;
306: }
307:
308: /* Documented in super interface */
309: public void requestRepaintRequests() {
310: repaintRequestListenersNotified = false;
311: }
312:
313: /* Documented in super interface */
314: public void paint(PaintTarget target) throws PaintException {
315: if (root == null)
316: throw new IllegalStateException(
317: "Composition root must be set to"
318: + " non-null value before the "
319: + getClass().getName() + " can be painted");
320:
321: if (isVisible()) {
322: String type = getComponentType();
323: if (type != null) {
324: if (!target.startTag(this , "component")) {
325: target.addAttribute("type", type);
326: root.paint(target);
327: }
328: target.endTag("component");
329: } else
330: root.paint(target);
331: }
332: repaintRequestListenersNotified = false;
333: }
334:
335: /** The custom component does not have any variables by default */
336: public void changeVariables(Object source, Map variables) {
337: }
338:
339: public void dependsOn(VariableOwner depended) {
340: if (depended == null)
341: return;
342: if (dependencies == null)
343: dependencies = new HashSet();
344: dependencies.add(depended);
345: }
346:
347: public Set getDirectDependencies() {
348: return dependencies;
349: }
350:
351: public void removeDirectDependency(VariableOwner depended) {
352: if (dependencies == null)
353: return;
354: dependencies.remove(depended);
355: if (dependencies.isEmpty())
356: dependencies = null;
357: }
358:
359: /* Event functions are not implemented by default -------------------- */
360:
361: /** Custom component does not implement any component events by default */
362: public void addListener(Component.Listener listener) {
363: }
364:
365: /** Custom component does not implement any component events by default */
366: public void removeListener(Component.Listener listener) {
367: }
368:
369: /** Gets the component type.
370: *
371: * The component type is textual type of the component. This is included
372: * in the UIDL as component tag attribute. If the component type is null
373: * (default), the component tag is not included in the UIDL at all.
374: *
375: * Returns the componentType.
376: * @return String
377: */
378: public String getComponentType() {
379: return componentType;
380: }
381:
382: /**
383: * Sets the component type.
384: *
385: * The component type is textual type of the component. This is included
386: * in the UIDL as component tag attribute. If the component type is null
387: * (default), the component tag is not included in the UIDL at all.
388: *
389: * @param componentType The componentType to set
390: */
391: public void setComponentType(String componentType) {
392: this.componentType = componentType;
393: }
394:
395: }
|