/************************************************************************** * Copyright (c) 2001, 2002, 2003 by Punch Telematix. All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Punch Telematix nor the names of * * other contributors may be used to endorse or promote products * * derived from this software without specific prior written permission.* * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL PUNCH TELEMATIX OR OTHER CONTRIBUTORS BE LIABLE * * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **************************************************************************/ package java.awt; import java.util.*; import java.awt.peer.*; import java.awt.event.*; public class Container extends Component { private LayoutManager layoutManager; private Vector children; ContainerListener containerListener; boolean focusCycleRoot; private boolean focusTraversalPolicyProvider; private FocusTraversalPolicy focusTraversalPolicy; boolean isRemoved; // set to true/false on removeNotify() enter/exit public Container() { // Assign default container size: width = 0; height = 0; // Setup component vector: children = new Vector(); // Set the default layout manager: layoutManager = new BorderLayout(); // Set the default listener (none): containerListener = null; } public Component add(Component component) { addImpl(component, null, -1); return component; } public void add(Component component, Object constraints) { addImpl(component, constraints, -1); } /** * @status implemented * @remark The third parameter 'int position' is currently ignored */ public void add(Component component, Object constraints, int position) { addImpl(component, constraints, position); } /** * @status implemented * @remark The third parameter 'int position' is currently ignored */ public Component add(Component component, int position) { addImpl(component, null, position); return component; } /** * @status implemented * @remark If the layout manager associated with this container, is of type * 'LayoutManager2', the container notifies the layout manager of the addition * by calling the layout manager's method 'addLayoutComponent(Component, Object)' * and not its method 'addLayoutComponent(String, Component)'. The effect is the * same (nothing is done) except that an IllegalArgumentException will be thrown. * In fact this is logical since a call of the present method with a LayoutManager2 * can be considered as a programming error. */ public Component add(String name, Component component) { addImpl(component, name, -1); return component; } /** * @status implemented to AWTEventMulticaster functionality */ public synchronized void addContainerListener(java.awt.event.ContainerListener listener) { containerListener = AWTEventMulticaster.add(containerListener, listener); } /** * @status implemented * @remark fully EventMulticaster-compliant throwing componentAdded(ContainerEvent) to all subscribed listeners */ protected void addImpl(Component component, Object constraints, int position) { if ((component instanceof Component) == false) { throw new IllegalArgumentException("You can only add types derived from java.awt.Component."); } toolkit.lockAWT(); try { // if(children.contains(component)) { // return; // } // Reparent the component and tidy up the tree's state: if (component.parent != null) { component.parent.removeComponent(component); } component.addNotify(); // Add component to underlying native data structure: if (component instanceof Container) { // Check whether is an instance of java.awt.Window: if (component instanceof Window) { System.out.println("You can't add a java.awt.Window to a java.awt.Container."); throw new IllegalArgumentException("You can't add a java.awt.Window to a java.awt.Container."); } // Check whether we don't create component loops: for (Container container = this; container != null; container = container.parent) { if (container == component) throw new IllegalArgumentException("Container.addImpl(): attempt container's parent to itself."); } } // Add component to data structure, taking position into account: if (position == -1) { children.addElement(component); } else { children.insertElementAt(component, position); } // Set parent: component.parent = this; // Set background color: // if (fg == false && parent.background != n component.background = parent.background; // Notify layoutmanger of added component: if (layoutManager != null) { if (layoutManager instanceof LayoutManager2) { ((LayoutManager2)layoutManager).addLayoutComponent(component, constraints); } else { layoutManager.addLayoutComponent((String)constraints, component); } } // throw ContainerEvent to listener super.dispatchEventImpl(new ContainerEvent(this, ContainerEvent.COMPONENT_ADDED, component)); // Redo the layout: if (valid) { invalidate(); } /* ** Normally addNotify will invalidate the children of a container when it's added ** to the component tree. Since we don't have this mechanism yet, we've added ** this obscure method to overcome this problem. It should be removed when addNotify ** does 'The Right Thing(tm)' */ invalidateChildren(); } finally { toolkit.unlockAWT(); } } public void addNotify() { /* Component c; for (int i = 0; i < getComponentCount(); i++) { c = (Component)children.elementAt(i); c.addNotify(); } */ if(notified == false) { super.addNotify(); } } public void removeNotify() { Component c; toolkit.lockAWT(); try { isRemoved = true; for (int i = 0; i < getComponentCount(); i++) { c = (Component)children.elementAt(i); c.removeNotify(); } super.removeNotify(); } finally { isRemoved = false; toolkit.unlockAWT(); } } public void doLayout() { toolkit.lockAWT(); try { if (layoutManager != null) { layoutManager.layoutContainer(this); } } finally { toolkit.unlockAWT(); } } public void layout() { doLayout(); } /** * @status Compliant to specs * @remark when using LayoutManager2 type manager, maps to LayoutManager2.getLayoutAlignmentX() (which is not implemented yet) */ public float getAlignmentX() { if(layoutManager == null || !(layoutManager instanceof LayoutManager2)) { // by default every component, this includes our container,is center.aligned // return super.getAalignmentX(); return Component.CENTER_ALIGNMENT; } else { //layoutManager is LayoutManager2 => get the manager's alignment return ((LayoutManager2)layoutManager).getLayoutAlignmentX(this); } } /** * @status Compliant to specs * @remark when using LayoutManager2 type manager, maps to LayoutManager2.getLayoutAlignmentY() (which is not implemented yet) */ public float getAlignmentY() { if (layoutManager == null || !(layoutManager instanceof LayoutManager2)) { // by default every component, this includes our container,is center.aligned // return super.getAalignmentX(); return Component.CENTER_ALIGNMENT; } else { //layoutManager is LayoutManager2 => get the manager's alignment return ((LayoutManager2)layoutManager).getLayoutAlignmentY(this); } } public Component getComponent(int index) { return (Component)children.elementAt(index); } /** * @status not implemented * @remark not implemented */ native public Component getComponentAt(int x, int y); /** * @status not implemented * @remark not implemented */ native public Component getComponentAt(Point point); public int getComponentCount() { return children.size(); } public Component[] getComponents() { Component[] components = new Component[this.children.size()]; return (Component[])(this.children.toArray(components)); } public Insets getInsets() { return new Insets(0, 0, 0, 0); } public LayoutManager getLayout() { return layoutManager; } public Dimension getMaximumSize() { toolkit.lockAWT(); try { if (maximumSize == null || valid == false) { if (layoutManager != null && layoutManager instanceof LayoutManager2) { maximumSize = ((LayoutManager2)layoutManager).maximumLayoutSize(this); } else { maximumSize = super.getMaximumSize(); } } return maximumSize; } finally { toolkit.unlockAWT(); } } /** * @status implemented * @remark compliant with the specification */ public Dimension getMinimumSize() { toolkit.lockAWT(); try { if (minSize == null || valid == false) { if (layoutManager != null) { minSize = layoutManager.minimumLayoutSize(this); } else { minSize = getBoundingBox(); } } return minSize; } finally { toolkit.unlockAWT(); } } private Dimension getBoundingBox() { Component c = null; int count = getComponentCount(); int wmax = 0; int hmax = 0;; int w; int h; int i; for (i = 0; i < count; i++) { c = (Component)children.elementAt(i); Dimension s = c.getSize(); Dimension d = c.getMinimumSize(); w = c.getX() + (int)Math.max(d.getWidth(), s.getWidth()); h = c.getY() + (int)Math.max(d.getHeight(), s.getHeight()); if (w > wmax) { wmax = w; } if (h > hmax) { hmax = h; } } return new Dimension (wmax + getInsets().right, hmax + getInsets().bottom); } public Dimension getPreferredSize() { toolkit.lockAWT(); try { if (prefSize == null || valid == false) { if (layoutManager != null) { prefSize = layoutManager.preferredLayoutSize(this); } else { prefSize = getBoundingBox(); } } return prefSize; } finally { toolkit.unlockAWT(); } } void invalidateChildren() { Component c; for (int i = 0; i < getComponentCount(); i++) { c = (Component)children.elementAt(i); c.invalidate(); if(c instanceof Container) { ((Container)c).invalidateChildren(); } } } public void invalidate() { toolkit.lockAWT(); try { super.invalidate(); if (layoutManager != null) { if (layoutManager instanceof LayoutManager2) { ((LayoutManager2)layoutManager).invalidateLayout(this); } } } finally { toolkit.unlockAWT(); } } /** * Is ancester of given component : * either is components parent, or is parent of parent of... of components parent * recursively: is ancestor when either is components parent or (parent excist and) is ancestor of components parent */ public boolean isAncestorOf(Component component) { Container parent = component.getParent(); if (parent == null) { return false; } else if (parent == this) { return true; } else { return isAncestorOf(parent); } } /** * @status not implemented * @remark not implemented */ native public void list(java.io.PrintStream out, int indent); /** * @status not implemented * @remark not implemented */ native public void list(java.io.PrintWriter out, int indent); /** * @status not implemented * @remark not implemented */ native public void paintComponents(Graphics context); /** * @status not implemented * @remark not implemented */ native protected String paramString(); /** * @status not implemented * @remark not implemented */ native public void print(Graphics context); /** * @status not implemented * @remark not implemented */ native public void printComponents(Graphics context); protected void processContainerEvent(java.awt.event.ContainerEvent event) { if (containerListener != null) { switch(event.getID()) { case ContainerEvent.COMPONENT_ADDED: containerListener.componentAdded(event); break; case ContainerEvent.COMPONENT_REMOVED: containerListener.componentRemoved(event); break; } } } protected void processEvent(AWTEvent event) { if (event instanceof ContainerEvent) { processContainerEvent((ContainerEvent) event); } else { super.processEvent(event); } } /** * @status implemented * @remark fully EventMulticaster-compliant throwing componentAdded(ContainerEvent) to all subscribed listeners */ private void removeComponent(Component component) { toolkit.lockAWT(); try { // Remove component from layout manager (if any): if (layoutManager != null) { layoutManager.removeLayoutComponent(component); } // Remove component from children: if (children.removeElement(component)) { // Set parent component to null: component.parent = null; // Invalidate container: if (valid) { invalidate(); } // throw ContainerEvent to listener super.dispatchEventImpl(new ContainerEvent(this, ContainerEvent.COMPONENT_REMOVED, component)); } } finally { toolkit.unlockAWT(); } } public void remove(Component component) { removeComponent(component); } public void remove(int position) { removeComponent((Component) children.elementAt(position)); } public void removeAll() { int size = children.size(); for (int i = 0; i < size; i++) { removeComponent((Component) children.elementAt(0)); // NOTE: we have to use "removeComponent()" rather than "remove()" because "remove()" can be overwritten. } } /** * @status implemented to AWTEventMulticaster functionality */ public synchronized void removeContainerListener(java.awt.event.ContainerListener listener) { containerListener = AWTEventMulticaster.remove(containerListener, listener); } public void setLayout(LayoutManager manager) { layoutManager = manager; if (valid) { invalidate(); } } public void validate() { if (valid == false) { toolkit.lockAWT(); try { ((ContainerPeer)peer).beginValidate(); validateTree(); ((ContainerPeer)peer).endValidate(); } finally { toolkit.unlockAWT(); } } } public void validateTree() { if (valid == false) { // Tell the renderer we are busy validating: validate = true; // Validate the container itself: valid = true; // Layout the container (if required): layout(); // Validate components of Container and validate nested Containers: for (int i = 0; i < children.size(); i++) { ((Component)children.elementAt(i)).validate(); } // Tell the renderer we are done validating: validate = false; } } public void setVisible(boolean condition) { super.setVisible(condition); sendComponentEvent(this, condition); } private void sendComponentEvent(Container container, boolean condition) { if(condition) { int count = container.getComponentCount(); for(int i=0; i<count; i++) { Component c = container.getComponent(i); if(c.visible) { if(c.componentListener != null) { c.dispatchEvent(new ComponentEvent(c, ComponentEvent.COMPONENT_SHOWN)); } if(c instanceof Container) { sendComponentEvent((Container)c, condition); } } } } } void enableAllEvents() { eventsEnabled = true; for (int i = 0; i < children.size(); i++) { Component c = (Component)children.elementAt(i); if(c instanceof Container) { ((Container)c).enableAllEvents(); } else { c.eventsEnabled = true; } } } void disableAllEvents() { eventsEnabled = false; for (int i = 0; i < children.size(); i++) { Component c = (Component)children.elementAt(i); if(c instanceof Container) { ((Container)c).disableAllEvents(); } else { c.eventsEnabled = false; } } } /* ** The following methods are deprecated... */ public int countComponents() { return getComponentCount(); } public Insets insets() { return getInsets(); } private void readObject(java.io.ObjectInputStream s) throws ClassNotFoundException, java.io.IOException { System.out.println("Not yet implemented"); } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { System.out.println("Not yet implemented"); } /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ public boolean isFocusCycleRoot(Container container) { toolkit.lockAWT(); try { if (focusCycleRoot && container == this) { return true; } return super.isFocusCycleRoot(container); } finally { toolkit.unlockAWT(); } } public boolean isFocusCycleRoot() { toolkit.lockAWT(); try { return focusCycleRoot; } finally { toolkit.unlockAWT(); } } public final boolean isFocusTraversalPolicyProvider() { return focusTraversalPolicyProvider; } public FocusTraversalPolicy getFocusTraversalPolicy() { toolkit.lockAWT(); try { if (isFocusTraversalPolicyProvider() || focusCycleRoot) { if (isFocusTraversalPolicySet()) { return focusTraversalPolicy; } Container root = getFocusCycleRootAncestor(); return ((root != null) ? root.getFocusTraversalPolicy() : KeyboardFocusManager .getCurrentKeyboardFocusManager().getDefaultFocusTraversalPolicy()); } return null; } finally { toolkit.unlockAWT(); } } public boolean isFocusTraversalPolicySet() { toolkit.lockAWT(); try { return focusTraversalPolicy != null; } finally { toolkit.unlockAWT(); } } public void setFocusTraversalPolicy(FocusTraversalPolicy policy) { FocusTraversalPolicy oldPolicy; toolkit.lockAWT(); try { oldPolicy = focusTraversalPolicy; focusTraversalPolicy = policy; } finally { toolkit.unlockAWT(); } // TODO // firePropertyChange("focusTraversalPolicy", oldPolicy, policy); //$NON-NLS-1$ } public Set getFocusTraversalKeys(int id) { toolkit.lockAWT(); try { return super.getFocusTraversalKeys(id); } finally { toolkit.unlockAWT(); } } public void transferFocusDownCycle() { toolkit.lockAWT(); try { if (isFocusCycleRoot()) { KeyboardFocusManager kfm = KeyboardFocusManager .getCurrentKeyboardFocusManager(); Container root = kfm.getCurrentFocusCycleRoot(); FocusTraversalPolicy policy = getFocusTraversalPolicy(); if (root != this) { root = this; kfm.setGlobalCurrentFocusCycleRoot(root); } policy.getDefaultComponent(root).requestFocus(); } } finally { toolkit.unlockAWT(); } } /** * Find which focus cycle root to take when doing keyboard focus traversal * and focus owner is a container & focus cycle root itself. * * @return */ Container getFocusTraversalRoot() { KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root = kfm.getCurrentFocusCycleRoot(); Container container = this; while ((root != container) && (container != null)) { container = container.getFocusCycleRootAncestor(); } return (container == root) ? root : null; } int getComponentIndex(Component comp) { return children.indexOf(comp); } }