001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings;
014:
015: import org.apache.commons.logging.Log;
016: import org.apache.commons.logging.LogFactory;
017: import org.wings.event.SContainerEvent;
018: import org.wings.event.SContainerListener;
019: import org.wings.plaf.CGManager;
020: import org.wings.plaf.ContainerCG;
021: import org.wings.util.ComponentVisitor;
022:
023: import java.util.ArrayList;
024: import java.util.Iterator;
025:
026: /**
027: * Can hold several other <code>SComponents</code>.
028: *
029: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>
030: * @see SLayoutManager
031: * @see SComponent
032: */
033: public class SContainer extends SComponent {
034: /**
035: * Commons Logger
036: */
037: private final static Log log = LogFactory.getLog(SContainer.class);
038: /**
039: * The layout for the component.
040: */
041: private SLayoutManager layout;
042:
043: private static String defaultLayout;
044:
045: /**
046: * The components in this container.
047: */
048: private ArrayList componentList;
049:
050: /**
051: * The constraints for the components.
052: */
053: private ArrayList constraintList;
054:
055: /**
056: * creates a new container with the given layout
057: *
058: * @param l the layout for this container
059: */
060: public SContainer(SLayoutManager l) {
061: setLayout(l);
062: }
063:
064: /**
065: * creates a new container with a Flowlayout as layout manager, like the
066: * Swing default.
067: */
068: public SContainer() {
069: // init defaultLayout if not initialized yet
070: if (defaultLayout == null) {
071: // lookup the default Layout Behaviour
072: final CGManager manager = getSession().getCGManager();
073: defaultLayout = (String) manager.getObject(
074: "SContainer.defaultLayoutBehaviour", String.class);
075: }
076: SLayoutManager layout = null;
077: if (defaultLayout == null) {
078: layout = new SFlowLayout();
079: } else if ("classic".equals(defaultLayout.toLowerCase())) {
080: layout = new SBoxLayout(SBoxLayout.VERTICAL);
081: } else if ("standard".equals(defaultLayout.toLowerCase())) {
082: layout = new SFlowLayout();
083: } else if ("none".equals(defaultLayout.toLowerCase())) {
084: layout = new SNullLayout();
085: } else { // fallback
086: layout = new SFlowLayout();
087: }
088: setLayout(layout);
089: }
090:
091: public void updateCG() {
092: super .updateCG();
093:
094: if (layout != null)
095: layout.updateCG();
096: }
097:
098: /**
099: * Sets a new layout manager.
100: *
101: * @param l
102: * new layout manager
103: */
104: public void setLayout(SLayoutManager l) {
105: if (layout != null) {
106: for (int i = 0; i < getComponentCount(); i++) {
107: layout.removeComponent(getComponent(i));
108: }
109: layout.setContainer(null);
110: }
111:
112: layout = l;
113:
114: if (layout != null) {
115: for (int i = 0; i < getComponentCount(); i++) {
116: layout.addComponent(getComponent(i),
117: getConstraintAt(i), i);
118: }
119:
120: layout.setContainer(this );
121: }
122: }
123:
124: /**
125: * Returns the current layout
126: *
127: * @return current layout
128: */
129: public SLayoutManager getLayout() {
130: return layout;
131: }
132:
133: /**
134: * Adds the specified container listener to receive container events
135: * from this container.
136: * If l is null, no exception is thrown and no action is performed.
137: *
138: * @param l the container listener
139: */
140: public void addContainerListener(SContainerListener l) {
141: addEventListener(SContainerListener.class, l);
142: }
143:
144: /**
145: * Removes the specified container listener so it no longer receives
146: * container events from this container.
147: * If l is null, no exception is thrown and no action is performed.
148: *
149: * @param l the container listener
150: */
151: public void removeContainerListener(SContainerListener l) {
152: removeEventListener(SContainerListener.class, l);
153: }
154:
155: protected void fireContainerEvent(int type, SComponent comp) {
156: SContainerEvent event = null;
157:
158: Object[] listeners = getListenerList();
159: for (int i = listeners.length - 2; i >= 0; i -= 2) {
160: if (listeners[i] == SContainerListener.class) {
161: // Lazily create the event:
162: if (event == null)
163: event = new SContainerEvent(this , type, comp);
164:
165: processContainerEvent(
166: (SContainerListener) listeners[i + 1], event);
167: }
168: }
169: }
170:
171: /**
172: * Processes container events occurring on this container by
173: * dispatching them to any registered ContainerListener objects.
174: * NOTE: This method will not be called unless container events
175: * are enabled for this component; this happens when one of the
176: * following occurs:
177: * a) A ContainerListener object is registered via addContainerListener()
178: * b) Container events are enabled via enableEvents()
179: *
180: * @param e the container event
181: */
182: protected void processContainerEvent(SContainerListener listener,
183: SContainerEvent e) {
184: switch (e.getID()) {
185: case SContainerEvent.COMPONENT_ADDED:
186: listener.componentAdded(e);
187: break;
188:
189: case SContainerEvent.COMPONENT_REMOVED:
190: listener.componentRemoved(e);
191: break;
192: }
193: }
194:
195: protected ArrayList getComponentList() {
196: if (componentList == null) {
197: componentList = new ArrayList(3);
198: }
199: return componentList;
200: }
201:
202: protected ArrayList getConstraintList() {
203: if (constraintList == null)
204: constraintList = new ArrayList(3);
205: return constraintList;
206: }
207:
208: /**
209: * returns the number of components in this container
210: *
211: * @return number of components
212: */
213: public int getComponentCount() {
214: return getComponentList().size();
215: }
216:
217: /**
218: * returns the component at the given position
219: *
220: * @param i position
221: * @return component at given pos
222: */
223: public SComponent getComponent(int i) {
224: return (SComponent) getComponentList().get(i);
225: }
226:
227: public SComponent[] getComponents() {
228: // vorsichtig mit Threads ( eigentlich TreeLock!!!)
229: return (SComponent[]) getComponentList().toArray(
230: new SComponent[getComponentCount()]);
231: }
232:
233: /**
234: * returns the constraint for the given component position
235: *
236: * @param i position
237: * @return constraint for component at given position
238: */
239: public Object getConstraintAt(int i) {
240: return getConstraintList().get(i);
241: }
242:
243: /**
244: * Removes the given component from the container.
245: *
246: * @param c the component to remove
247: * @see #remove(org.wings.SComponent)
248: */
249: public void remove(SComponent c) {
250: if (c == null)
251: return;
252:
253: if (layout != null)
254: layout.removeComponent(c);
255:
256: int index = getComponentList().indexOf(c);
257: if (getComponentList().remove(c)) {
258: getConstraintList().remove(index);
259: c.removeNotify();
260: fireContainerEvent(SContainerEvent.COMPONENT_REMOVED, c);
261:
262: c.setParent(null);
263: reload();
264: }
265: }
266:
267: /**
268: * Removes the component at the given position from the container.
269: *
270: * @param index remove the component at position <i>index</i>
271: * from this container
272: */
273: public void remove(int index) {
274: SComponent c = getComponent(index);
275: remove(c);
276: }
277:
278: /**
279: * Removes all components from the container.
280: */
281: public void removeAll() {
282: while (getComponentCount() > 0) {
283: remove(0);
284: }
285: }
286:
287: /**
288: * Adds a component to the container with null constraint at the end
289: * of the internal list.
290: *
291: * @param c the component to add
292: * @return the added component
293: */
294: public SComponent add(SComponent c) {
295: return addComponent(c, null);
296: }
297:
298: /**
299: * Adds a component to the container with the given constraint at the end
300: * of the internal list.
301: *
302: * @param c the component to add
303: * @param constraint the constraint for this component
304: */
305: public void add(SComponent c, Object constraint) {
306: addComponent(c, constraint);
307: }
308:
309: /**
310: * Adds a component to the container with null constraint at the given
311: * index.
312: *
313: * @param c the component to add
314: * @param index the index of the component
315: * @return the added component
316: */
317: public SComponent add(SComponent c, int index) {
318: return addComponent(c, null, index);
319: }
320:
321: /**
322: * Adds a component to the container with the given constraint at
323: * the given index.
324: *
325: * @param c the component to add
326: * @param index the index of the component
327: */
328: public void add(SComponent c, Object constraint, int index) {
329: addComponent(c, constraint, index);
330: }
331:
332: /**
333: * Adds a component to the container with null constraint at the end
334: * of the internal list.
335: *
336: * @param c the component to add
337: * @return the added component
338: */
339: public SComponent addComponent(SComponent c) {
340: return addComponent(c, null);
341: }
342:
343: /**
344: * Adds a component to the container with the given constraint at the end
345: * of the internal list.
346: *
347: * @param c the component to add
348: * @param constraint the constraint for this component
349: * @return the added component
350: */
351: public SComponent addComponent(SComponent c, Object constraint) {
352: return addComponent(c, constraint, getComponentList().size());
353: }
354:
355: /**
356: * Adds a component to the container with the given constraint at
357: * the given index.
358: *
359: * @param c the component to add
360: * @param index the index of the component
361: * @return the added component
362: */
363: public SComponent addComponent(SComponent c, int index) {
364: return addComponent(c, null, index);
365: }
366:
367: /**
368: * Adds a component to the container with the given constraint at
369: * the given index.
370: *
371: * @param c the component to add
372: * @param index the index of the component
373: * @return the added component
374: */
375: public SComponent addComponent(SComponent c, Object constraint,
376: int index) {
377: if (c != null) {
378: // Sanity check: Component is only allowed to be inside one container
379: // equal to Swing (1:n tree, not n:m tree)
380: if (c.getParent() != null) {
381: if (c.getParent() == this ) {
382: // Forstall confusing ArrayOutOfBoundsException which would occur in the remove.
383: throw new IllegalArgumentException(
384: "Component must only added exactly "
385: + "once to exactly one container!");
386: } else {
387: // Try to silently fix the double-add by removing it from the old parent.
388: c.getParent().remove(c);
389: }
390: }
391: if (index == -1)
392: index = getComponentList().size();
393:
394: getComponentList().add(index, c);
395: getConstraintList().add(index, constraint);
396: c.setParent(this );
397:
398: if (layout != null) {
399: layout.addComponent(c, constraint, index);
400: }
401: c.addNotify();
402: fireContainerEvent(SContainerEvent.COMPONENT_ADDED, c);
403:
404: reload();
405: }
406:
407: return c;
408: }
409:
410: /**
411: * Sets the parent frame.
412: *
413: * @param f parent frame
414: */
415: protected void setParentFrame(SFrame f) {
416: if (f != super .getParentFrame()) {
417: super .setParentFrame(f);
418: for (int i = 0; i < getComponentCount(); i++) {
419: getComponent(i).setParentFrame(getParentFrame());
420: }
421: }
422: }
423:
424: /**
425: * CAVEAT this did not work yet... We need to clone the layout manager as
426: * well, so SLayoutManager must be Cloneable
427: */
428: public Object clone() {
429: try {
430: SContainer erg = (SContainer) super .clone();
431: // uiuiui, layout manager must be cloned as well,...
432:
433: // componentList and constraintList contain references to the
434: // original components / constraints
435: erg.getComponentList().clear();
436: erg.getConstraintList().clear();
437: for (int i = 0; i < getComponentCount(); i++) {
438: erg.addComponent((SComponent) getComponent(i).clone());
439: }
440: return erg;
441: } catch (Exception e) {
442: log.error("Unable to clone container", e);
443: return null;
444: }
445: }
446:
447: public void setCG(ContainerCG cg) {
448: super .setCG(cg);
449: }
450:
451: /**
452: * Invite a ComponentVisitor.
453: * Invokes visit(SContainer) on the ComponentVisitor.
454: *
455: * @param visitor the visitor to be invited
456: */
457: public void invite(ComponentVisitor visitor) throws Exception {
458: visitor.visit(this );
459: }
460:
461: /**
462: * Calls the visitor on each SComponent this container has. You might
463: * want to call this in your visitor in visit(SContainer).
464: *
465: * @param visitor an implementation of the {@link ComponentVisitor}
466: * interface.
467: */
468: public void inviteEachComponent(ComponentVisitor visitor)
469: throws Exception {
470: Iterator iterator = getComponentList().iterator();
471: while (iterator.hasNext()) {
472: ((SComponent) iterator.next()).invite(visitor);
473: }
474: }
475:
476: /*
477: * @see SComponent#removeNotify()
478: * Notify all contained elements that this component has been removed from an container.
479: */
480: public void removeNotify() {
481: Iterator iterator = getComponentList().iterator();
482: while (iterator.hasNext()) {
483: ((SComponent) iterator.next()).removeNotify();
484: }
485: super .removeNotify();
486: }
487:
488: /*
489: * @see SComponent#addNotify()
490: * Notify all contained elements that this component has a new parent container.
491: */
492: public void addNotify() {
493: Iterator iterator = getComponentList().iterator();
494: while (iterator.hasNext()) {
495: ((SComponent) iterator.next()).addNotify();
496: }
497: super .addNotify();
498: }
499:
500: /**
501: * Collects all {@link SComponent#getComponentPopupMenu()} of all contained and visible components.
502: * @return all menus of all sub components (recursively)
503: */
504: /*public ArrayList getMenus() {
505: ArrayList menus = new ArrayList();
506: if (isVisible()) {
507: final Iterator iter = getComponentList().iterator();
508: while (iter.hasNext()) {
509: final SComponent comp = (SComponent)iter.next();
510: if (comp.isVisible()) {
511: final SPopupMenu componentMenu = comp.getComponentPopupMenu();
512: if (componentMenu != null && menus.contains(componentMenu) == false)
513: menus.add(componentMenu);
514: if (comp instanceof SContainer) {
515: SContainer container = (SContainer)comp;
516: menus.addAll(container.getMenus());
517: }
518: }
519: }
520: SPopupMenu pmenu = getComponentPopupMenu();
521: if (pmenu != null && !menus.contains(pmenu)) {
522: menus.add(pmenu);
523: }
524: }
525: return menus;
526: }*/
527:
528: /**
529: * Indicates if this container is actually showing it's children. Default is <code>true</code>
530: * @return <code>true</code> if {@link #getComponents()} are rendered, <code>false</code> if i.e the container
531: * hides them (i.e minimized MDI window).
532: */
533: protected boolean isShowingChildren() {
534: return true;
535: }
536: }
|