View Javadoc

1   /*
2    * Copyright (c) 2004-2005 by Michael Connor. All Rights Reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    *
7    *  o Redistributions of source code must retain the above copyright notice,
8    *    this list of conditions and the following disclaimer.
9    *
10   *  o Redistributions in binary form must reproduce the above copyright notice,
11   *    this list of conditions and the following disclaimer in the documentation
12   *    and/or other materials provided with the distribution.
13   *
14   *  o Neither the name of FormLayoutBuilder or Michael Connor nor the names of
15   *    its contributors may be used to endorse or promote products derived
16   *    from this software without specific prior written permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.mlc.swing.layout;
31  
32  import com.jgoodies.forms.layout.CellConstraints;
33  import com.jgoodies.forms.layout.FormLayout;
34  import java.awt.Component;
35  import java.awt.LayoutManager2;
36  import java.beans.*;
37  import java.lang.reflect.Method;
38  import java.util.*;
39  
40  /***
41   * This class acts as a surogate layout manager for the JGoodies
42   * (www.jgoodies.com) FormLayout manager. This layout manager enables us to
43   * associate names with components and then define the constraints for the
44   * component elsewhere (like xml)
45   *
46   * @author Michael Connor
47   */
48  public class ContainerLayout implements LayoutManager2
49  {
50    java.util.List<String> rowSpecs = new ArrayList<String>();
51  
52    java.util.List<String> columnSpecs = new ArrayList<String>();
53  
54    LinkedHashMap<String, CellConstraints> componentConstraints = new LinkedHashMap<String, CellConstraints>();
55  
56    Map<Component, String> componentsToNames = new HashMap<Component, String>();
57  
58    Map<String, Map<String, Object>> componentNameToCustomProps = new HashMap<String, Map<String, Object>>();
59  
60    Map<String, ComponentDef> componentNameToComponentDef = new HashMap<String, ComponentDef>();
61  
62    FormLayout formLayout;
63  
64    String name;
65  
66    public ContainerLayout(String name, String columnSpecs, String rowSpecs)
67    {
68      this.name = name;
69      StringTokenizer cols = new StringTokenizer(columnSpecs, ",", false);
70      StringTokenizer rows = new StringTokenizer(rowSpecs, ",", false);
71  
72      while (cols.hasMoreTokens())
73        this.columnSpecs.add(cols.nextToken());
74  
75      while (rows.hasMoreTokens())
76        this.rowSpecs.add(rows.nextToken());
77  
78      formLayout = new FormLayout(columnSpecs, rowSpecs);
79  
80    }
81  
82    private void buildLayout() throws IllegalArgumentException
83    {
84      formLayout = new FormLayout(delimit(columnSpecs), delimit(rowSpecs));
85  
86      // now we have to add all of the compenents to the new form
87      for (Iterator i = componentsToNames.keySet().iterator(); i.hasNext();)
88      {
89        Component component = (Component) i.next();
90        String componentName = componentsToNames.get(component);
91        CellConstraints constraints = componentConstraints.get(componentName);
92        formLayout.addLayoutComponent(component, constraints);
93      }
94    }
95  
96    private String delimit(List<String> values)
97    {
98      StringBuffer buffer = new StringBuffer();
99  
100     for (int index = 0; index < values.size(); index++)
101     {
102       buffer.append(values.get(index));
103       if (index < values.size() - 1)
104         buffer.append(",");
105     }
106 
107     return buffer.toString();
108   }
109 
110   protected Map<Component, String> getComponentsToNames()
111   {
112     return Collections.unmodifiableMap(componentsToNames);
113   }
114 
115   /***
116    * Registers the value of the name property
117    *
118    * @param name
119    *          The value of the property
120    */
121   public void setName(String name)
122   {
123     this.name = name;
124   }
125 
126   /***
127    * Returns the value of the name property
128    *
129    * @return The value
130    */
131   public String getName()
132   {
133     return this.name;
134   }
135 
136   /***
137    * Returns custom properties for the component. If no custom props exist then
138    * an empty map will be returned.
139    */
140   public Map<String, Object> getCustomProperties(String componentName)
141   {
142     return componentNameToCustomProps.containsKey(componentName) ? componentNameToCustomProps
143         .get(componentName)
144         : new HashMap<String, Object>();
145   }
146 
147   /***
148    * Set a user defined property for this component so that the tool can manage
149    * the properties of the component thus reducing the burden on the user
150    */
151   public void setProperty(String componentName, String property, Object value)
152   {
153     Map<String, Object> customProps = componentNameToCustomProps.get(componentName);
154     if (customProps == null)
155     {
156       customProps = new HashMap<String, Object>();
157       componentNameToCustomProps.put(componentName, customProps);
158     }
159     customProps.put(property, value);
160   }
161 
162   public void setCellConstraints(String componentName,
163       CellConstraints constraints)
164   {
165     componentConstraints.put(name, constraints);
166 
167     for (Iterator i = componentsToNames.keySet().iterator(); i.hasNext();)
168     {
169       Component component = (Component) i.next();
170       String thisName = componentsToNames.get(component);
171       if (thisName.equals(componentName))
172       {
173         formLayout.setConstraints(component, constraints);
174         break;
175       }
176     }
177   }
178 
179   public LinkedHashMap<String, CellConstraints> getCellConstraints()
180   {
181     return componentConstraints;
182   }
183 
184   public void addComponent(String componentName, ComponentDef componentDef,
185       CellConstraints constraints)
186   {
187     componentConstraints.put(componentName, constraints);
188     componentNameToComponentDef.put(componentName, componentDef);
189   }
190 
191   public ComponentDef getComponentDef(String componentName)
192   {
193     return componentNameToComponentDef.get(componentName);
194   }
195 
196   public String getColumnSpecsString()
197   {
198     StringBuffer buffer = new StringBuffer();
199     for (Iterator i = columnSpecs.iterator(); i.hasNext();)
200     {
201       buffer.append(i.next());
202       if (i.hasNext())
203         buffer.append(",");
204     }
205 
206     return buffer.toString();
207   }
208 
209   public String getRowSpecsString()
210   {
211     StringBuffer buffer = new StringBuffer();
212     for (Iterator i = rowSpecs.iterator(); i.hasNext();)
213     {
214       buffer.append(i.next());
215       if (i.hasNext())
216         buffer.append(",");
217     }
218 
219     return buffer.toString();
220   }
221 
222   public int getRowCount()
223   {
224     return rowSpecs.size();
225   }
226 
227   public int getColumnCount()
228   {
229     return columnSpecs.size();
230   }
231 
232   public List<String> getRowSpecs()
233   {
234     return this.rowSpecs;
235   }
236 
237   public List<String> getColumnSpecs()
238   {
239     return this.columnSpecs;
240   }
241 
242   public void constraintsChanged(String name, CellConstraints constraints)
243   {
244     componentConstraints.put(name, constraints);
245   }
246 
247   public CellConstraints getCellConstraints(String name)
248   {
249     return componentConstraints.get(name);
250   }
251 
252   public void addCellConstraints(String name, CellConstraints constraints)
253   {
254     componentConstraints.put(name, constraints);
255   }
256 
257   public CellConstraints removeCellConstraints(String name)
258   {
259     CellConstraints constraints = (CellConstraints) componentConstraints
260         .remove(name);
261     return constraints;
262   }
263 
264   public void addColumnSpec(String columnSpec) throws IllegalArgumentException
265   {
266     columnSpecs.add(columnSpec);
267     buildLayout();
268   }
269 
270   public String getRowSpec(int index)
271   {
272     return rowSpecs.get(index);
273   }
274 
275   public String getColumnSpec(int index)
276   {
277     return columnSpecs.get(index);
278   }
279 
280   public void setRowSpec(int index, String rowSpec)
281       throws IllegalArgumentException
282   {
283     rowSpecs.set(index, rowSpec);
284     buildLayout();
285   }
286 
287   public void setColumnSpec(int index, String columnSpec)
288       throws IllegalArgumentException
289   {
290     columnSpecs.set(index, columnSpec);
291     buildLayout();
292   }
293 
294   public void addRowSpec(String rowSpec) throws IllegalArgumentException
295   {
296     rowSpecs.add(rowSpec);
297     buildLayout();
298   }
299 
300   public String removeRowSpec(int index)
301   {
302     String rowSpec = (String) rowSpecs.remove(index);
303     try
304     {
305       buildLayout();
306     }
307     catch (IllegalArgumentException e)
308     {
309       throw new RuntimeException(e);
310     }
311 
312     return rowSpec;
313   }
314 
315   public String removeColumnSpec(int index)
316   {
317     String spec = columnSpecs.remove(index);
318     try
319     {
320       buildLayout();
321     }
322     catch (IllegalArgumentException e)
323     {
324       throw new RuntimeException(e);
325     }
326 
327     return spec;
328   }
329 
330   public void addRowSpec(int index, String rowSpec)
331       throws IllegalArgumentException
332   {
333     rowSpecs.add(index, rowSpec);
334     buildLayout();
335   }
336 
337   public void addColumnSpec(int index, String columnSpec)
338       throws IllegalArgumentException
339   {
340     columnSpecs.add(index, columnSpec);
341     buildLayout();
342   }
343 
344   /* the following methods realize the LayoutManager interface */
345 
346   public String getComponentName(Component component)
347   {
348     return componentsToNames.get(component);
349   }
350 
351   /***
352    * Returns the component with the given name or null if not found
353    */
354   public Component getComponentByName(String name)
355   {
356     for (Component component : componentsToNames.keySet())
357     {
358       String testName = componentsToNames.get(component);
359       if (testName.equals(name))
360         return component;
361     }
362     return null;
363   }
364 
365   public CellConstraints getComponentConstraints(Component component)
366   {
367     String name = componentsToNames.get(component);
368     if (name == null)
369       throw new RuntimeException("Unable to find name for component "
370           + component);
371     return componentConstraints.get(name);
372   }
373 
374   // interface for LayoutManager2
375   public void addLayoutComponent(String name, java.awt.Component comp)
376   {
377     throw new RuntimeException(
378         "This method should not be called.  Call addLayoutComponent (Component, Object) instead");
379   }
380 
381   public float getLayoutAlignmentX(java.awt.Container target)
382   {
383     return formLayout.getLayoutAlignmentX(target);
384   }
385 
386   public float getLayoutAlignmentY(java.awt.Container target)
387   {
388     return formLayout.getLayoutAlignmentY(target);
389   }
390 
391   public FormLayout.LayoutInfo getLayoutInfo(java.awt.Container container)
392   {
393     // KBR added to allow FormDebugPanel to work with ContainerLayout
394     return this.formLayout.getLayoutInfo(container);
395   }
396 
397   public void invalidateLayout(java.awt.Container target)
398   {
399     formLayout.invalidateLayout(target);
400   }
401 
402   public void layoutContainer(java.awt.Container parent)
403   {
404     formLayout.layoutContainer(parent);
405   }
406 
407   public java.awt.Dimension maximumLayoutSize(java.awt.Container target)
408   {
409     return formLayout.maximumLayoutSize(target);
410   }
411 
412   public java.awt.Dimension minimumLayoutSize(java.awt.Container parent)
413   {
414     return formLayout.minimumLayoutSize(parent);
415   }
416 
417   public java.awt.Dimension preferredLayoutSize(java.awt.Container parent)
418   {
419     return formLayout.preferredLayoutSize(parent);
420   }
421 
422   public void removeLayoutComponent(java.awt.Component comp)
423   {
424     String componentName = componentsToNames.get(comp);
425     componentsToNames.remove(comp);
426     componentConstraints.remove(componentName);
427     formLayout.removeLayoutComponent(comp);
428   }
429 
430   public void addLayoutComponent(java.awt.Component comp, Object constraints)
431   {
432     if (!(constraints instanceof String))
433       throw new RuntimeException(
434           "The constraints must be a String name which should reference a CellConstraints entry in the xml file");
435     String componentName = (String) constraints;
436     CellConstraints cellConstraints = componentConstraints.get(componentName);
437     if (cellConstraints == null)
438     {
439       System.out.println("Warning : " + componentName
440           + " was added without constraints");
441       cellConstraints = new CellConstraints();
442       componentConstraints.put(componentName, cellConstraints);
443       comp.setVisible(false);
444     }
445     else
446     {
447 
448       Map<String, Object> customProps = componentNameToCustomProps
449           .get(componentName);
450       if (customProps != null)
451       {
452         for (String prop : customProps.keySet())
453         {
454           Object value = customProps.get(prop);
455           // KBR Class compClass = comp.getClass();
456           try
457           {
458             BeanInfo beanInfo = Introspector.getBeanInfo(comp.getClass());
459             PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
460             for (int index = 0; index < props.length; index++)
461             {
462               PropertyDescriptor propertyDescriptor = props[index];
463               if (propertyDescriptor.getName().equals(prop))
464               {
465                 Method writeMethod = propertyDescriptor.getWriteMethod();
466                 writeMethod.invoke(comp, new Object[] { value });
467                 break;
468               }
469             }
470           }
471           catch (Exception e)
472           {
473             throw new RuntimeException(e);
474           }
475         }
476       }
477     }
478 
479     componentsToNames.put(comp, componentName);
480     formLayout.addLayoutComponent(comp, cellConstraints);
481   }
482 
483   private class LocationScore implements Comparable<LocationScore>
484   {
485     public int score;
486 
487     public int row;
488 
489     public int col;
490 
491     public int width;
492 
493     public LocationScore(int score, int row, int col, int width)
494     {
495       this.score = score;
496       this.row = row;
497       this.col = col;
498       this.width = width;
499     }
500 
501     public int compareTo(LocationScore testScore)
502     {
503       return this.score < testScore.score ? -1
504           : this.score > testScore.score ? 1 : 0;
505     }
506   }
507 
508   public static void main(String[] args)
509   {
510   }
511 
512 }