replaced <code></code> with more concise {@code}
[idea/community.git] / java / compiler / forms-compiler / src / com / intellij / uiDesigner / lw / LwContainer.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.uiDesigner.lw;
17
18 import com.intellij.uiDesigner.UIFormXmlConstants;
19 import com.intellij.uiDesigner.compiler.UnexpectedFormElementException;
20 import com.intellij.uiDesigner.core.GridLayoutManager;
21 import com.intellij.uiDesigner.shared.BorderType;
22 import com.intellij.uiDesigner.shared.XYLayoutManager;
23 import org.jdom.Element;
24
25 import java.awt.*;
26 import java.util.ArrayList;
27 import java.util.Iterator;
28
29 /**
30  * @author Anton Katilin
31  * @author Vladimir Kondratyev
32  */
33 public class LwContainer extends LwComponent implements IContainer{
34   // PLEASE DO NOT USE GENERICS IN THIS FILE AS IT IS USED IN JAVAC2 ANT TASK THAT SHOULD BE RUNNABLE WITH JDK 1.3
35
36   /**
37    * Children components
38    */
39   private final ArrayList myComponents;
40   /**
41    * Describes border's type. This member is never {@code null}
42    */
43   private BorderType myBorderType;
44   /**
45    * Border's title. If border doesn't have any title then
46    * this member is {@code null}.
47    */
48   private StringDescriptor myBorderTitle;
49   private int myBorderTitleJustification;
50   private int myBorderTitlePosition;
51   private FontDescriptor myBorderTitleFont;
52   private ColorDescriptor myBorderTitleColor;
53   private Insets myBorderSize;
54   private ColorDescriptor myBorderColor;
55   private LayoutManager myLayout;
56   private String myLayoutManager;
57   protected LayoutSerializer myLayoutSerializer;
58
59   public LwContainer(final String className){
60     super(className);
61     myComponents = new ArrayList();
62
63     // By default container doesn't have any special border
64     setBorderType(BorderType.NONE);
65
66     myLayout = createInitialLayout();
67   }
68
69
70   protected LayoutManager createInitialLayout(){
71     return new XYLayoutManager();
72   }
73
74   public final LayoutManager getLayout() {
75     return myLayout;
76   }
77
78   public final void setLayout(final LayoutManager layout) {
79     myLayout = layout;
80   }
81
82   public String getLayoutManager() {
83     return myLayoutManager;
84   }
85
86   public final boolean isGrid(){
87     return getLayout() instanceof GridLayoutManager;
88   }
89
90   public final boolean isXY(){
91     return getLayout() instanceof XYLayoutManager;
92   }
93
94   /**
95    * @param component component to be added.
96    *
97    * @exception IllegalArgumentException if {@code component} is {@code null}
98    * @exception IllegalArgumentException if {@code component} already exist in the
99    * container
100    */
101   public final void addComponent(final LwComponent component){
102     if (component == null) {
103       throw new IllegalArgumentException("component cannot be null");
104     }
105     if (myComponents.contains(component)) {
106       throw new IllegalArgumentException("component is already added: " + component);
107     }
108     if (component.getParent() != null) {
109       throw new IllegalArgumentException("component already added to another container");
110     }
111
112     // Attach to new parent
113     myComponents.add(component);
114     component.setParent(this);
115   }
116
117   public final IComponent getComponent(final int index) {
118     return (IComponent)myComponents.get(index);
119   }
120
121   public final int getComponentCount() {
122     return myComponents.size();
123   }
124
125   public int indexOfComponent(final IComponent lwComponent) {
126     return myComponents.indexOf(lwComponent);
127   }
128
129   /**
130    * @return border's type. The method never return {@code null}.
131    *
132    * @see BorderType
133    */
134   public final BorderType getBorderType(){
135     return myBorderType;
136   }
137
138   public boolean accept(ComponentVisitor visitor) {
139     if (!super.accept(visitor)) {
140       return false;
141     }
142
143     for (int i = 0; i < getComponentCount(); i++) {
144       final IComponent c = getComponent(i);
145       if (!c.accept(visitor)) {
146         return false;
147       }
148     }
149
150     return true;
151   }
152
153   /**
154    * @see BorderType
155    *
156    * @exception IllegalArgumentException if {@code type}
157    * is {@code null}
158    */
159   public final void setBorderType(final BorderType type){
160     if(type==null){
161       throw new IllegalArgumentException("type cannot be null");
162     }
163     myBorderType=type;
164   }
165
166   /**
167    * @return border's title. If the container doesn't have any title then the
168    * method returns {@code null}.
169    */
170   public final StringDescriptor getBorderTitle(){
171     return myBorderTitle;
172   }
173
174   /**
175    * @param title new border's title. {@code null} means that
176    * the containr doesn't have have titled border.
177    */
178   public final void setBorderTitle(final StringDescriptor title){
179     myBorderTitle=title;
180   }
181
182   public int getBorderTitleJustification() {
183     return myBorderTitleJustification;
184   }
185
186   public int getBorderTitlePosition() {
187     return myBorderTitlePosition;
188   }
189
190   public FontDescriptor getBorderTitleFont() {
191     return myBorderTitleFont;
192   }
193
194   public ColorDescriptor getBorderTitleColor() {
195     return myBorderTitleColor;
196   }
197
198   public Insets getBorderSize() {
199     return myBorderSize;
200   }
201
202   public ColorDescriptor getBorderColor() {
203     return myBorderColor;
204   }
205
206   /**
207    * TODO[anton,vova] looks like it is better to pass contraints tag
208    * 
209    * @param element XML element which should contains 'constraints' tag
210    */
211   protected void readConstraintsForChild(final Element element, final LwComponent component){
212     if (myLayoutSerializer != null) {
213       final Element constraintsElement = LwXmlReader.getRequiredChild(element, "constraints");
214       myLayoutSerializer.readChildConstraints(constraintsElement, component);
215     }
216   }
217
218   /**
219    * 'border' is required subtag
220    */
221   protected final void readBorder(final Element element) {
222     final Element borderElement = LwXmlReader.getRequiredChild(element, UIFormXmlConstants.ELEMENT_BORDER);
223     setBorderType(BorderType.valueOf(LwXmlReader.getRequiredString(borderElement, UIFormXmlConstants.ATTRIBUTE_TYPE)));
224
225     StringDescriptor descriptor = LwXmlReader.getStringDescriptor(borderElement,
226                                                                   UIFormXmlConstants.ATTRIBUTE_TITLE,
227                                                                   UIFormXmlConstants.ATTRIBUTE_TITLE_RESOURCE_BUNDLE,
228                                                                   UIFormXmlConstants.ATTRIBUTE_TITLE_KEY);
229     if (descriptor != null) {
230       setBorderTitle(descriptor);
231     }
232
233     myBorderTitleJustification = LwXmlReader.getOptionalInt(borderElement, UIFormXmlConstants.ATTRIBUTE_TITLE_JUSTIFICATION, 0);
234     myBorderTitlePosition = LwXmlReader.getOptionalInt(borderElement, UIFormXmlConstants.ATTRIBUTE_TITLE_POSITION, 0);
235     Element fontElement = LwXmlReader.getChild(borderElement, UIFormXmlConstants.ELEMENT_FONT);
236     if (fontElement != null) {
237       myBorderTitleFont = LwXmlReader.getFontDescriptor(fontElement);
238     }
239     myBorderTitleColor = LwXmlReader.getOptionalColorDescriptor(LwXmlReader.getChild(borderElement, UIFormXmlConstants.ELEMENT_TITLE_COLOR));
240     myBorderColor = LwXmlReader.getOptionalColorDescriptor(LwXmlReader.getChild(borderElement, UIFormXmlConstants.ELEMENT_COLOR));
241     Element sizeElement = LwXmlReader.getChild(borderElement, UIFormXmlConstants.ELEMENT_SIZE);
242     if (sizeElement != null) {
243       try {
244         myBorderSize = LwXmlReader.readInsets(sizeElement);
245       }
246       catch(Exception e) {
247         myBorderSize = null;
248       }
249     }
250   }
251
252   /**
253    * 'children' is required attribute
254    */
255   protected final void readChildren(final Element element, final PropertiesProvider provider) throws Exception{
256     final Element childrenElement = LwXmlReader.getRequiredChild(element, "children");
257     for(Iterator i=childrenElement.getChildren().iterator(); i.hasNext();){
258       final Element child = (Element)i.next();
259       final LwComponent component = createComponentFromTag(child);
260       addComponent(component);
261       component.read(child, provider);
262     }
263   }
264
265   public static LwComponent createComponentFromTag(final Element child) throws Exception {
266     final String name = child.getName();
267     final LwComponent component;
268     if("component".equals(name)){
269       final String className = LwXmlReader.getRequiredString(child, UIFormXmlConstants.ATTRIBUTE_CLASS);
270       component = new LwAtomicComponent(className);
271     }
272     else if (UIFormXmlConstants.ELEMENT_NESTED_FORM.equals(name)) {
273       component = new LwNestedForm();
274     }
275     else if("vspacer".equals(name)){
276       component = new LwVSpacer();
277     }
278     else if("hspacer".equals(name)){
279       component = new LwHSpacer();
280     }
281     else if("xy".equals(name) || "grid".equals(name)){
282       String className = LwXmlReader.getOptionalString(child, UIFormXmlConstants.ATTRIBUTE_CLASS, "javax.swing.JPanel");
283       component = new LwContainer(className);
284     }
285     else if(UIFormXmlConstants.ELEMENT_SCROLLPANE.equals(name)) {
286       String className = LwXmlReader.getOptionalString(child, UIFormXmlConstants.ATTRIBUTE_CLASS, "javax.swing.JScrollPane");
287       component = new LwScrollPane(className);
288     }
289     else if(UIFormXmlConstants.ELEMENT_TABBEDPANE.equals(name)){
290       String className = LwXmlReader.getOptionalString(child, UIFormXmlConstants.ATTRIBUTE_CLASS, "javax.swing.JTabbedPane");
291       component = new LwTabbedPane(className);
292     }
293     else if(UIFormXmlConstants.ELEMENT_SPLITPANE.equals(name)){
294       String className = LwXmlReader.getOptionalString(child, UIFormXmlConstants.ATTRIBUTE_CLASS, "javax.swing.JSplitPane");
295       component = new LwSplitPane(className);
296     }
297     else if (UIFormXmlConstants.ELEMENT_TOOLBAR.equals(name)) {
298       String className = LwXmlReader.getOptionalString(child, UIFormXmlConstants.ATTRIBUTE_CLASS, "javax.swing.JToolBar");
299       component = new LwToolBar(className);
300     }
301     else{
302       throw new UnexpectedFormElementException("unexpected element: "+child);
303     }
304     return component;
305   }
306
307   /**
308    * 'xy' or 'grid'
309    */
310   protected final void readLayout(final Element element){
311     myLayoutManager = element.getAttributeValue("layout-manager");
312     if("xy".equals(element.getName())){
313       myLayoutSerializer = XYLayoutSerializer.INSTANCE;
314     }
315     else if("grid".equals(element.getName())){
316       createLayoutSerializer();
317     }
318     else{
319       throw new UnexpectedFormElementException("unexpected element: "+element);
320     }
321     myLayoutSerializer.readLayout(element, this);
322   }
323
324   public void setLayoutManager(final String layoutManager) {
325     myLayoutManager = layoutManager;
326     createLayoutSerializer();
327   }
328
329   private void createLayoutSerializer() {
330     if (UIFormXmlConstants.LAYOUT_BORDER.equals(myLayoutManager)) {
331       myLayoutSerializer = BorderLayoutSerializer.INSTANCE;
332     }
333     else if (UIFormXmlConstants.LAYOUT_FLOW.equals(myLayoutManager)) {
334       myLayoutSerializer = FlowLayoutSerializer.INSTANCE;
335     }
336     else if (UIFormXmlConstants.LAYOUT_CARD.equals(myLayoutManager)) {
337       myLayoutSerializer = CardLayoutSerializer.INSTANCE;
338     }
339     else if (UIFormXmlConstants.LAYOUT_XY.equals(myLayoutManager)) {
340       myLayoutSerializer = XYLayoutSerializer.INSTANCE;
341     }
342     else if (UIFormXmlConstants.LAYOUT_FORM.equals(myLayoutManager)) {
343       myLayoutSerializer = FormLayoutSerializer.INSTANCE;
344     }
345     else if (UIFormXmlConstants.LAYOUT_GRIDBAG.equals(myLayoutManager)) {
346       myLayoutSerializer = GridBagLayoutSerializer.INSTANCE;      
347     }
348     else {
349       myLayoutSerializer = GridLayoutSerializer.INSTANCE;
350     }
351   }
352
353   public void read(final Element element, final PropertiesProvider provider) throws Exception {
354     readBase(element);
355
356     // Layout
357     readLayout(element);
358
359     // Constraints and properties
360     readConstraints(element);
361     readProperties(element, provider);
362
363     // Border
364     readBorder(element);
365
366     readChildren(element, provider);
367   }
368
369   protected void readNoLayout(final Element element, final PropertiesProvider provider) throws Exception {
370     readBase(element);
371
372     // Constraints and properties
373     readConstraints(element);
374     readProperties(element, provider);
375
376     // Border
377     readBorder(element);
378
379     readChildren(element, provider);
380   }
381
382   public boolean areChildrenExclusive() {
383     return UIFormXmlConstants.LAYOUT_CARD.equals(myLayoutManager);
384   }
385 }