KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > form > layoutsupport > AbstractLayoutSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.form.layoutsupport;
21
22 import java.awt.*;
23 import java.beans.*;
24 import java.util.*;
25 import java.lang.reflect.Method JavaDoc;
26
27 import org.openide.ErrorManager;
28 import org.openide.nodes.Node;
29 import org.openide.util.Utilities;
30
31 import org.netbeans.modules.form.*;
32 import org.netbeans.modules.form.codestructure.*;
33
34 /**
35  * Default implementation of LayoutSupportDelegate interface. This class
36  * implements most of general methods of LayoutSupportDelegate and introduces
37  * other more specific methods which can be easily customized in subclasses.
38  *
39  * This class provides basic support for layouts following these rules:
40  * (1) the supported layout manager is a JavaBean (it means that it has an
41  * empty public constructor, the parameters are set as properties,
42  * BeanInfo is used to obtain the properties),
43  * (2) Container.setLayout(LayoutManager) method is used on the container to
44  * set the layout,
45  * (3) Container.add(Component) and Container.add(Component, Object) methods
46  * are used on the container to add components (the second method for
47  * adding with layout constraints).
48  *
49  * To create basic support for such a layout manager, it's enough to implement
50  * getSupportedClass method only.
51  *
52  * Note that the subclass should have public constructor without parameters,
53  * otherwise it should override cloneSupportInstance method.
54  *
55  * Note that the default implementation does not (and even cannot) provide any
56  * working support for layout constraints of components in general - this must
57  * be implemented in the sublasses individually. See BorderLayoutSupport for an
58  * example of using simple value constraints, AbsoluteLayoutSupport for complex
59  * object constraints (created by constructor), GridBagLayoutSupport for complex
60  * constraints with special initialization code.
61  *
62  * @author Tomas Pavek
63  */

64
65 public abstract class AbstractLayoutSupport implements LayoutSupportDelegate
66 {
67     /** Default icon URL. */
68     private static String JavaDoc iconURL =
69         "org/netbeans/modules/form/layoutsupport/resources/AbstractLayout.gif"; // NOI18N
70
/** Default icon URL. */
71     private static String JavaDoc icon32URL =
72         "org/netbeans/modules/form/layoutsupport/resources/AbstractLayout32.gif"; // NOI18N
73

74     private static Method JavaDoc simpleAddMethod = null;
75     private static Method JavaDoc addWithConstraintsMethod = null;
76     private static Method JavaDoc setLayoutMethod = null;
77
78     // ------
79

80     private LayoutSupportContext layoutContext;
81
82     private java.util.List JavaDoc componentCodeExpressions;
83     private java.util.List JavaDoc componentCodeGroups;
84     private java.util.List JavaDoc componentConstraints;
85
86     private BeanCodeManager layoutBeanCode;
87     private CodeGroup setLayoutCode;
88
89     private MetaLayout metaLayout;
90     private FormProperty[] allProperties;
91
92     // ------------------
93
// LayoutSupportDelegate interface implementation
94

95     /** Initialization of the layout delegate before the first use.
96      * There are three types of initialization supported:
97      * (1) default initialization for an empty (newly created) layout
98      * (lmInstance == null, fromCode == false),
99      * (2) initialization from an already existing instance of LayoutManager
100      * (lmInstance != null, fromCode == false),
101      * (3) initialization from persistent code structure,
102      * (lmInstance == null, fromCode == true).
103      * @param layoutContext provides a necessary context information for the
104      * layout delegate
105      * @param lmInstance LayoutManager instance for initialization (may be null)
106      * @param fromCode indicates whether to initialize from code structure
107      * @exception any Exception occurred during initialization
108      */

109     public void initialize(LayoutSupportContext layoutContext,
110                            LayoutManager lmInstance,
111                            boolean fromCode)
112         throws Exception JavaDoc
113     {
114         if (this.layoutContext == layoutContext) {
115             // already initialized - just reuse the delegate
116
if (setLayoutCode != null)
117                 setLayoutCode.removeAll();
118             else setLayoutCode =
119                      layoutContext.getCodeStructure().createCodeGroup();
120
121             readLayoutCode(setLayoutCode); // reinstate layout code (for sure)
122
return;
123         }
124
125         this.layoutContext = layoutContext;
126         clean();
127
128         Class JavaDoc cls = getSupportedClass();
129         if (cls != null && LayoutManager.class.isAssignableFrom(cls)) {
130             // create MetaLayout to manage layout manager as a bean
131
boolean defaultInstance = lmInstance == null;
132             if (lmInstance == null || !lmInstance.getClass().equals(cls)) {
133                 // no valid layout manager instance - create a default one
134
lmInstance = createDefaultLayoutInstance();
135                 defaultInstance = true;
136             }
137
138             if (lmInstance != null)
139                 metaLayout = new MetaLayout(this, lmInstance, defaultInstance);
140         }
141         else metaLayout = null;
142
143         // read layout code (if there's any)
144
readLayoutCode(setLayoutCode);
145
146         if (fromCode) {
147             // read components from code
148
CodeGroup componentCode = null;
149             Iterator it = CodeStructure.getDefinedStatementsIterator(
150                                           getActiveContainerCodeExpression());
151             while (it.hasNext()) {
152                 if (componentCode == null)
153                     componentCode =
154                         layoutContext.getCodeStructure().createCodeGroup();
155
156                 CodeStatement statement = (CodeStatement) it.next();
157                 CodeExpression compExp = readComponentCode(statement,
158                                                             componentCode);
159                 if (compExp != null) {
160                     componentCodeExpressions.add(compExp);
161                     componentCodeGroups.add(componentCode);
162                     componentCode = null;
163
164                     if (componentConstraints.size()
165                             < componentCodeExpressions.size())
166                         componentConstraints.add(null);
167                 }
168             }
169         }
170     }
171
172     /** States whether this support class is dedicted to some special container.
173      * @return true if only certain container is supported,
174      * false if a layout manager for use in any container is supported
175      */

176     public boolean isDedicated() {
177         Class JavaDoc cls = getSupportedClass();
178         return cls != null && !LayoutManager.class.isAssignableFrom(cls);
179     }
180
181     /** For dedicated supports: check whether given default container instance
182      * is empty. Default implementation returns true - it's up to subcalsses
183      * to check the special containers.
184      * @param cont default instance of Container
185      * @return true if the container can be used as default (empty) instance
186      * with this layout support
187      */

188     public boolean checkEmptyContainer(Container cont) {
189         return true;
190     }
191
192     /** Indicates whether the layout should be presented as a node in Component
193      * Inspector (for setting properties). The node is provided for layout
194      * managers typically (except null layou), and not for dedicated containers
195      * support.
196      * @return whether a node should be created for the layout
197      */

198     public boolean shouldHaveNode() {
199         Class JavaDoc cls = getSupportedClass();
200         return cls == null || LayoutManager.class.isAssignableFrom(cls);
201     }
202
203     /** Provides a display name for the layout node - derived from the name
204      * of supported class here.
205      * @return display name of supported layout
206      */

207     public String JavaDoc getDisplayName() {
208         Class JavaDoc cls = getSupportedClass();
209         String JavaDoc name;
210
211         if (cls != null) {
212             name = cls.getName();
213             int lastdot = name.lastIndexOf('.');
214             if (lastdot > 0)
215                 name = name.substring(lastdot + 1);
216         }
217         else name = "null"; // NOI18N
218

219         return name;
220     }
221
222     /** Provides an icon to be used for the layout node in Component
223      * Inspector. Only 16x16 color icon is required. The default implementation
224      * tries to obtain the icon from BeanInfo of the layout manager.
225      * @param type is one of BeanInfo constants: ICON_COLOR_16x16,
226      * ICON_COLOR_32x32, ICON_MONO_16x16, ICON_MONO_32x32
227      * @return icon to be used for layout node
228      */

229     public Image getIcon(int type) {
230         if (metaLayout != null) {
231             Image icon = metaLayout.getBeanInfo().getIcon(type);
232             if (icon != null)
233                 return icon;
234         }
235
236         switch (type) {
237             case BeanInfo.ICON_COLOR_16x16:
238             case BeanInfo.ICON_MONO_16x16:
239                 return Utilities.loadImage(iconURL);
240             default:
241                 return Utilities.loadImage(icon32URL);
242         }
243     }
244
245     /** This method provides properties of the supported layout - if it is
246      * a JavaBean class implementing LayoutManager. The properties are obtained
247      * from the BeanInfo of the layout manager. Note these are not properties
248      * of individual components constraints.
249      * @return properties of supported layout
250      */

251     public Node.PropertySet[] getPropertySets() {
252         Node.PropertySet[] propertySets;
253
254         FormProperty[] properties = getProperties();
255         if (properties == null) {
256             propertySets = metaLayout != null ?
257                                metaLayout.getProperties() : null;
258         }
259         else { // a subclass provides special properties
260
propertySets = new Node.PropertySet[1];
261             propertySets[0] = new Node.PropertySet(
262                 "properties", // NOI18N
263
FormUtils.getBundleString("CTL_PropertiesTab"), // NOI18N
264
FormUtils.getBundleString("CTL_PropertiesTabHint")) // NOI18N
265
{
266                 public Node.Property[] getProperties() {
267                     return AbstractLayoutSupport.this.getProperties();
268                 }
269             };
270         }
271
272         if (propertySets != null) {
273             ArrayList allPropsList = new ArrayList();
274             for (int i=0; i < propertySets.length; i++) {
275                 Node.Property[] props = propertySets[i].getProperties();
276                 for (int j=0; j < props.length; j++)
277                     if (props[j] instanceof FormProperty)
278                         allPropsList.add(props[j]);
279             }
280             allProperties = new FormProperty[allPropsList.size()];
281             allPropsList.toArray(allProperties);
282         }
283         else {
284             allProperties = new FormProperty[0];
285             propertySets = new Node.PropertySet[0];
286         }
287
288         return propertySets;
289     }
290
291     /** Returns a class of a customizer for the layout manager being used as
292      * a JavaBean. The class should be a java.awt.Component and
293      * java.beans.Customizer. The default implementation tries to get the
294      * customizer class from layout manager's BeanInfo.
295      * @return layout bean customizer class, null if no customizer is provided
296      */

297     public Class JavaDoc getCustomizerClass() {
298         return metaLayout == null ? null :
299             metaLayout.getBeanInfo().getBeanDescriptor().getCustomizerClass();
300     }
301
302     /** Returns an instance of a special customizer provided by the layout
303      * delegate. This customizer need not implement java.beans.Customizer,
304      * because its creation is under full control of the layout delegate - and
305      * vice versa, the customizer can have full control over the layout
306      * delegate (unlike the bean customizer which operates only with layout
307      * manager bean instance). The default implementation returns null.
308      * @return instance of layout support customizer
309      */

310     public Component getSupportCustomizer() {
311         return null;
312     }
313
314     /** Gets the complete code for setting up the layout (including adding
315      * components).
316      * @return whole container's layout code
317      */

318     public CodeGroup getLayoutCode() {
319         return setLayoutCode;
320     }
321
322     /** Gets code for setting up one component's constraints and adding the
323      * component to the layout (container).
324      * @return one component's layout code
325      */

326     public CodeGroup getComponentCode(int index) {
327         return (CodeGroup) componentCodeGroups.get(index);
328     }
329
330     /** Gets CodeExpression object representing one component.
331      * @param index index of the component in the layout
332      * @return CodeExpression for a component
333      */

334     public CodeExpression getComponentCodeExpression(int index) {
335         return (CodeExpression) componentCodeExpressions.get(index);
336     }
337
338     /** Gets number of components in the layout.
339      * @return number of components in the layout
340      */

341     public int getComponentCount() {
342         return componentCodeExpressions != null ?
343                  componentCodeExpressions.size() : 0;
344     }
345
346     /** This method is called to accept new components before they are added
347      * to the layout (by calling addComponents method). It may adjust the
348      * constraints, or refuse the components by throwing a RuntimeException
349      * (e.g. IllegalArgumentException). It's up to the delagate to display an
350      * error or warning message, the exception is not reported outside.
351      * The default implementation accepts any components - simply does nothing.
352      * @param compExpressions array of CodeExpression objects representing the
353      * components to be accepted
354      * @param constraints array of layout constraints of the components, may
355      * contain nulls
356      * @param index position at which the components are to be added (inserted);
357      * -1 means that the components will be added at the end
358      */

359     public void acceptNewComponents(CodeExpression[] compExpressions,
360                                     LayoutConstraints[] constraints,
361                                     int index)
362     {
363     }
364
365     /** This method is called after a property of the layout is changed by
366      * the user. Subclasses may check whether the layout is valid after the
367      * change and throw PropertyVetoException if the change should be reverted.
368      * It's up to the delagate to display an error or warning message, the
369      * exception is not reported outside. The default implementation accepts
370      * any change.
371      * @param ev PropertyChangeEvent object describing the change
372      */

373     public void acceptContainerLayoutChange(PropertyChangeEvent ev)
374         throws PropertyVetoException
375     {
376         // as this method is called for each change, we update the layout
377
// bean code here too
378
if (layoutBeanCode != null)
379             layoutBeanCode.updateCode();
380     }
381
382     /** This method is called after a constraint property of some component
383      * is changed by the user. Subclasses may check if the layout is valid
384      * after the change and throw PropertyVetoException if the change should
385      * be reverted. It's up to the delagate to display an error or warning
386      * message, the exception is not reported outside. The default
387      * implementation accepts any change.
388      * @param index index of the component in the layout
389      * @param ev PropertyChangeEvent object describing the change
390      */

391     public void acceptComponentLayoutChange(int index, PropertyChangeEvent ev)
392         throws PropertyVetoException
393     {
394     }
395
396     /** Adds new components to the layout. This is done just at the metadata
397      * level, no real components but their CodeExpression representations
398      * are added.
399      * The code structures describing the layout is updated immediately.
400      * @param compExpressions array of CodeExpression objects representing the
401      * components to be accepted
402      * @param constraints array of layout constraints of the components, may
403      * contain nulls
404      * @param index position at which the components should be added (inserted);
405      * if -1, the components should be added at the end
406      */

407     public void addComponents(CodeExpression[] newCompExps,
408                               LayoutConstraints[] newConstraints,
409                               int index)
410     {
411         if (index < 0 || index > componentCodeExpressions.size())
412             index = componentCodeExpressions.size();
413
414         CodeStructure codeStructure = layoutContext.getCodeStructure();
415
416         for (int i=0; i < newCompExps.length; i++) {
417             int ii = index + i;
418
419             CodeExpression compExp = newCompExps[i];
420             componentCodeExpressions.add(ii, compExp);
421
422             LayoutConstraints constr = newConstraints != null ?
423                                        newConstraints[i] : null;
424             if (constr == null)
425                 constr = createDefaultConstraints();
426
427             componentConstraints.add(ii, constr);
428
429             CodeGroup componentCode =
430                 codeStructure.createCodeGroup();
431             createComponentCode(componentCode, compExp, ii);
432             componentCodeGroups.add(ii, componentCode);
433         }
434     }
435
436     /** Removes one component from the layout (at metadata level).
437      * The code structures describing the layout is updated immediately.
438      * @param index index of the component in the layout
439      */

440     public void removeComponent(int index) {
441         componentCodeExpressions.remove(index);
442         componentCodeGroups.remove(index);
443         componentConstraints.remove(index);
444     }
445
446     /** Removes all components from the layout (at metadata level).
447      * The code structures describing the layout is updated immediately.
448      */

449     public void removeAll() {
450         if (componentCodeExpressions != null)
451             componentCodeExpressions.clear();
452         if (componentCodeGroups != null)
453             componentCodeGroups.clear();
454         if (componentConstraints != null)
455             componentConstraints.clear();
456     }
457
458     /** Indicates whether there's some change in the layout in comparison
459      * with the default layout of given container. If there's no change, no
460      * code needs to be delegate (e.g. default FlowLayout in JPanel).
461      * Note this is related to the container layout only, not to components.
462      * @param defaultContainer instance of the default container to compare with
463      * @param defaultContainerDelegate effective container delegate of the
464      * default container (e.g. like content pane of JFrame)
465      * @return whether the current layout is different from the default one
466      */

467     public boolean isLayoutChanged(Container defaultContainer,
468                                    Container defaultContainerDelegate)
469     {
470         if (isDedicated())
471             return false;
472
473         Class JavaDoc layoutClass = getSupportedClass();
474         LayoutManager lm = defaultContainerDelegate.getLayout();
475
476         if (layoutClass == null)
477             return lm != null;
478         if (lm == null)
479             return true;
480
481         //
482
if (!layoutClass.isAssignableFrom(lm.getClass()))
483             return true;
484
485         FormProperty[] props = getAllProperties();
486         for (int i=0; i < props.length; i++)
487             if (props[i].isChanged())
488                 return true;
489
490         return false;
491     }
492
493     /** Gets layout constraints for a component at the given index.
494      * @param index index of the component in the layout
495      * @return layout constraints of given component
496      */

497     public LayoutConstraints getConstraints(int index) {
498         return index < 0 || index >= componentConstraints.size() ? null :
499                (LayoutConstraints) componentConstraints.get(index);
500     }
501
502     /** This method is called when switching layout - giving an opportunity to
503      * convert the previous constrainst of components to constraints of the new
504      * layout (this layout). The default implementation does nothing.
505      * @param previousConstraints [input] layout constraints of components in
506      * the previous layout
507      * @param currentConstraints [output] array of converted constraints for
508      * the new layout - to be filled
509      * @param components [input] real components in a real container having the
510      * previous layout
511      */

512     public void convertConstraints(LayoutConstraints[] previousConstraints,
513                                    LayoutConstraints[] currentConstraints,
514                                    Component[] components)
515     {
516     }
517
518     /** Sets up the layout (without adding components) on a real container,
519      * according to the internal metadata representation.
520      * @param container instance of a real container to be set
521      * @param containerDelegate effective container delegate of the container
522      * (e.g. like content pane of JFrame)
523      */

524     public void setLayoutToContainer(Container container,
525                                      Container containerDelegate)
526     {
527         if (isDedicated())
528             return;
529
530         LayoutManager lm = null;
531         try {
532             if (containerDelegate == layoutContext.getPrimaryContainerDelegate()) {
533                 if (metaLayout != null) // use the instance of MetaLayout
534
lm = (LayoutManager) metaLayout.getBeanInstance();
535             }
536             else { // use cloned layout instance
537
lm = cloneLayoutInstance(container, containerDelegate);
538             }
539         }
540         catch (Exception JavaDoc ex) { // should not happen
541
ex.printStackTrace();
542         }
543
544         if (lm != null)
545             containerDelegate.setLayout(lm);
546     }
547
548     /** Adds real components to given container (according to layout
549      * constraints stored for the components).
550      * @param container instance of a real container to be added to
551      * @param containerDelegate effective container delegate of the container
552      * (e.g. like content pane of JFrame)
553      * @param components components to be added
554      * @param index position at which to add the components to container
555      */

556     public void addComponentsToContainer(Container container,
557                                          Container containerDelegate,
558                                          Component[] components,
559                                          int index)
560     {
561         for (int i=0; i < components.length; i++) {
562             LayoutConstraints constr = getConstraints(i + index);
563             if (constr != null)
564                 containerDelegate.add(components[i],
565                                       constr.getConstraintsObject(),
566                                       i + index);
567             else
568                 containerDelegate.add(components[i], i + index);
569         }
570     }
571
572     /** Removes a real component from a real container.
573      * @param container instance of a real container
574      * @param containerDelegate effective container delegate of the container
575      * (e.g. like content pane of JFrame)
576      * @param component component to be removed
577      * @return whether it was possible to remove the component (some containers
578      * may not support removing individual components reasonably)
579      */

580     public boolean removeComponentFromContainer(Container container,
581                                                 Container containerDelegate,
582                                                 Component component)
583     {
584         containerDelegate.remove(component);
585         component.setBounds(0, 0, 0, 0);
586         return true;
587     }
588
589     /** Removes all components from given real container.
590      * @param container instance of a real container to be cleared
591      * @param containerDelegate effective container delegate of the container
592      * (e.g. like content pane of JFrame)
593      * @return whether it was possible to clear the container (some containers
594      * may not support this)
595      */

596     public boolean clearContainer(Container container,
597                                   Container containerDelegate)
598     {
599         Component[] components = containerDelegate.getComponents();
600         containerDelegate.removeAll();
601         for (int i=0; i < components.length; i++)
602             components[i].setBounds(0, 0, 0, 0);
603         return true;
604     }
605
606     /** This method is called when user clicks on the container in form
607      * designer. The layout delegate may do something with the container,
608      * e.g. for JTabbedPane it might switch the selected TAB. The default
609      * implementation does nothing.
610      * @param p Point of click in the container
611      * @param real instance of the container when the click occurred
612      * @param containerDelegate effective container delegate of the container
613      * (e.g. like content pane of JFrame)
614      */

615     public void processMouseClick(Point p,
616                                   Container container,
617                                   Container containerDelegate)
618     {
619     }
620
621     /** This method is called when a component is selected in Component
622      * Inspector. If the layout delegate is interested in such information,
623      * it may store it and use it e.g. in arrangeContainer method.
624      * The default implementation does nothing.
625      * @param index position (index) of the selected component in container
626      */

627     public void selectComponent(int index) {
628     }
629
630     /** In this method, the layout delegate has a chance to "arrange" real
631      * container instance additionally - some other way that cannot be
632      * done through layout properties and added components. For example, the
633      * selected component index can be applied here (see delegates for
634      * CardLayout and JTabbedPane). The default implementation does nothing.
635      * @param container instance of a real container to be arranged
636      * @param containerDelegate effective container delegate of the container
637      * (e.g. like content pane of JFrame)
638      */

639     public void arrangeContainer(Container container,
640                                  Container containerDelegate)
641     {
642     }
643
644     /** This method should calculate layout constraints for a component dragged
645      * over a container (or just for mouse cursor being moved over container,
646      * without any component). This method is useful for "constraints oriented"
647      * layout managers (like e.g. BorderLayout or GridBagLayout).
648      * @param container instance of a real container over/in which the
649      * component is dragged
650      * @param containerDelegate effective container delegate of the container
651      * (e.g. like content pane of JFrame)
652      * @param component the real component being dragged, can be null
653      * @param index position (index) of the component in its current container;
654      * -1 if there's no dragged component
655      * @param posInCont position of mouse in the container delegate
656      * @param posInComp position of mouse in the dragged component; null if
657      * there's no dragged component
658      * @return new LayoutConstraints object corresponding to the position of
659      * the component in the container; may return null if the layout
660      * does not use component constraints, or if default constraints
661      * should be used
662      */

663     public LayoutConstraints getNewConstraints(Container container,
664                                                Container containerDelegate,
665                                                Component component,
666                                                int index,
667                                                Point posInCont,
668                                                Point posInComp)
669     {
670         return null;
671     }
672
673     /** This method should calculate position (index) for a component dragged
674      * over a container (or just for mouse cursor being moved over container,
675      * without any component). This method is useful for layout managers that
676      * don't use component constraints (like e.g. FlowLayout or GridLayout)
677      * @param container instance of a real container over/in which the
678      * component is dragged
679      * @param containerDelegate effective container delegate of the container
680      * (e.g. like content pane of JFrame)
681      * @param component the real component being dragged, can be null
682      * @param index position (index) of the component in its current container;
683      * -1 if there's no dragged component
684      * @param posInCont position of mouse in the container delegate
685      * @param posInComp position of mouse in the dragged component; null if
686      * there's no dragged component
687      * @return index corresponding to the position of the component in the
688      * container; may return -1 if the layout rather uses component
689      * constraints, or if a default index should be used
690      */

691     public int getNewIndex(Container container,
692                            Container containerDelegate,
693                            Component component,
694                            int index,
695                            Point posInCont,
696                            Point posInComp)
697     {
698         return -1;
699     }
700
701     /**
702      * Returns context for the assistant (context sensitive help bar).
703      *
704      * @rerurn context for the assistant.
705      */

706     public String JavaDoc getAssistantContext() {
707         return null;
708     }
709
710     /**
711      * Returns context parameters for the assistant (context sensitive help bar).
712      *
713      * @return context parameters for the assistant.
714      */

715     public Object JavaDoc[] getAssistantParams() {
716         return null;
717     }
718
719     /** This method should paint a feedback for a component dragged over
720      * a container (or just for mouse cursor being moved over container,
721      * without any component). In principle, it should present given component
722      * layout constraints or index graphically.
723      * @param container instance of a real container over/in which the
724      * component is dragged
725      * @param containerDelegate effective container delegate of the container
726      * (e.g. like content pane of JFrame) - here the feedback is painted
727      * @param component the real component being dragged, can be null
728      * @param newConstraints component layout constraints to be presented
729      * @param newIndex component's index position to be presented
730      * (if newConstraints == null)
731      * @param g Graphics object for painting (with color and line style set)
732      * @return whether any feedback was painted (may return false if the
733      * constraints or index are invalid, or if the painting is not
734      * implemented)
735      */

736     public boolean paintDragFeedback(Container container,
737                                      Container containerDelegate,
738                                      Component component,
739                                      LayoutConstraints newConstraints,
740                                      int newIndex,
741                                      Graphics g)
742     {
743         return false;
744     }
745
746     /** Provides resizing options for given component. It can combine the
747      * bit-flag constants RESIZE_UP, RESIZE_DOWN, RESIZE_LEFT, RESIZE_RIGHT.
748      * @param container instance of a real container in which the
749      * component is to be resized
750      * @param containerDelegate effective container delegate of the container
751      * (e.g. like content pane of JFrame)
752      * @param component real component to be resized
753      * @param index position of the component in its container
754      * @return resizing options for the component; 0 if no resizing is possible
755      */

756     public int getResizableDirections(Container container,
757                                       Container containerDelegate,
758                                       Component component,
759                                       int index)
760     {
761         return 0;
762     }
763
764     /** This method should calculate layout constraints for a component being
765      * resized.
766      * @param container instance of a real container in which the
767      * component is resized
768      * @param containerDelegate effective container delegate of the container
769      * (e.g. like content pane of JFrame)
770      * @param component real component being resized
771      * @param index position of the component in its container
772      * @param sizeChanges Insets object with size differences
773      * @param posInCont position of mouse in the container delegate
774      * @return component layout constraints for resized component; null if
775      * resizing is not possible or not implemented
776      */

777     public LayoutConstraints getResizedConstraints(Container container,
778                                                    Container containerDelegate,
779                                                    Component component,
780                                                    int index,
781                                                    Rectangle originalBounds,
782                                                    Insets sizeChanges,
783                                                    Point posInCont)
784     {
785         return null;
786     }
787
788     /** Cloning method - creates a copy of the layout delegate.
789      * @param targetContext LayoutSupportContext for the new layout delegate
790      * @param compExpressions array of CodeExpression objects representing the
791      * components for the new layout delegate (corresponding to the
792      * current ones)
793      * @return cloned layout delegate instance
794      */

795     public LayoutSupportDelegate cloneLayoutSupport(
796                                      LayoutSupportContext targetContext,
797                                      CodeExpression[] targetComponents)
798     {
799         AbstractLayoutSupport clone = createLayoutSupportInstance();
800         try {
801             clone.initialize(targetContext, null, false);
802         }
803         catch (Exception JavaDoc ex) { // should not fail (not reading from code)
804
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
805             return null;
806         }
807
808         FormProperty[] sourceProperties = getAllProperties();
809         FormProperty[] targetProperties = clone.getAllProperties();
810         FormUtils.copyProperties(sourceProperties,
811                                  targetProperties,
812                                  FormUtils.CHANGED_ONLY
813                                    | FormUtils.DISABLE_CHANGE_FIRING);
814
815         int compCount = getComponentCount();
816         LayoutConstraints[] constraints = new LayoutConstraints[compCount];
817         for (int i=0; i < compCount; i++) {
818             LayoutConstraints constr = getConstraints(i);
819             constraints[i] = constr != null ? constr.cloneConstraints() : null;
820         }
821
822         clone.addComponents(targetComponents, constraints, 0);
823
824         return clone;
825     }
826
827     // ------------------
828
// extended API for AbstractLayoutSupport subclasses
829

830     /** Creates a default instance of LayoutManager (for internal use).
831      * Override this method if the layout manager is not a bean (cannot
832      * be created from default constructor).
833      * @return new (default) instance of supported layout manager
834      */

835     protected LayoutManager createDefaultLayoutInstance()
836         throws Exception JavaDoc
837     {
838         return (LayoutManager)
839                CreationFactory.createDefaultInstance(getSupportedClass());
840     }
841
842     /** Cloning method - creates a clone of the reference LayoutManager
843      * instance (for external use). Override this method if the layout manager
844      * is not a bean (cannot be created from default constructor, and copied
845      * using properties).
846      * @param container instance of a real container in whose container
847      * delegate the layout manager will be probably used
848      * @param containerDelegate effective container delegate of the container
849      * (e.g. like content pane of JFrame)
850      * @return new instance of layout manager representing the layout (with
851      * all properties set)
852      */

853     protected LayoutManager cloneLayoutInstance(Container container,
854                                                 Container containerDelegate)
855         throws Exception JavaDoc
856     {
857         return metaLayout == null ? null :
858                (LayoutManager) metaLayout.cloneBeanInstance(null);
859     }
860
861     /** Cloning method - creates a new instance of this layout support, just
862      * not initialized yet.
863      * @return new instance of this layout support
864      */

865     protected AbstractLayoutSupport createLayoutSupportInstance() {
866         try {
867             return (AbstractLayoutSupport) getClass().newInstance();
868         }
869         catch (Exception JavaDoc ex) { // should not happen for AbstractLayoutSupport subclasses
870
return null;
871         }
872     }
873
874     /** This methods returns the code expression to be used for container on
875      * which the layout is set and to which components are added. This can be
876      * either container, or container delegate expression. In fact, it is
877      * container delegate in most cases (so this method needs to be overridden
878      * very rarely). But there's e.g. JScrollPane which has its viewport as the
879      * container delegate, but we work with the JScrollPane (whole container).
880      * @return code expression representing the effective container
881      */

882     protected CodeExpression getActiveContainerCodeExpression() {
883         return layoutContext.getContainerDelegateCodeExpression();
884     }
885
886     /** Cleans all data before the delegate is initialized.
887      */

888     protected void clean() {
889         if (componentCodeExpressions != null)
890             componentCodeExpressions.clear();
891         else componentCodeExpressions = new ArrayList();
892
893         if (componentCodeGroups != null)
894             componentCodeGroups.clear();
895         else componentCodeGroups = new ArrayList();
896
897         if (componentConstraints != null)
898             componentConstraints.clear();
899         else componentConstraints = new ArrayList();
900
901         if (setLayoutCode != null)
902             setLayoutCode.removeAll();
903         else setLayoutCode = layoutContext.getCodeStructure().createCodeGroup();
904
905         layoutBeanCode = null;
906         metaLayout = null;
907
908         allProperties = null;
909     }
910
911     /** This method is used for "reading layout from code", called from
912      * initialize method. It recognizes relevant code which sets the layout
913      * manager on the container and reads the layout information from the code.
914      * This includes the code for setting up the layout manager itself and the
915      * code for setting the layout manger to container. For setting up just the
916      * layout manager bean, the method readInitLayoutCode is used.
917      * Reading components code is not done here.
918      * @param layoutCode CodeGroup to be filled with relevant layout code
919      * @see readInitLayoutCode method
920      */

921     protected void readLayoutCode(CodeGroup layoutCode) {
922         if (isDedicated())
923             return;
924
925         CodeGroup initLayoutCode =
926             getCodeStructure().createCodeGroup();
927         CodeStatement setLayoutStatement = null;
928
929         Iterator it = CodeStructure.getDefinedStatementsIterator(
930                                         getActiveContainerCodeExpression());
931         CodeStatement[] statements = CodeStructure.filterStatements(
932                                                      it, getSetLayoutMethod());
933         if (statements.length > 0) { // read from code
934
setLayoutStatement = statements[0];
935             readInitLayoutCode(setLayoutStatement.getStatementParameters()[0],
936                                initLayoutCode);
937         }
938         else { // create new
939
CodeExpression layoutExp = createInitLayoutCode(initLayoutCode);
940             if (layoutExp != null)
941                 setLayoutStatement = CodeStructure.createStatement(
942                          getActiveContainerCodeExpression(),
943                          getSetLayoutMethod(),
944                          new CodeExpression[] { layoutExp });
945         }
946
947         if (setLayoutStatement != null) {
948             layoutCode.addGroup(initLayoutCode);
949             layoutCode.addStatement(setLayoutStatement);
950         }
951     }
952
953     /** This method is called from readLayoutCode to read the layout manager
954      * bean code (i.e. code for constructor and properties).
955      * @param layoutExp CodeExpressin of the layout manager
956      * @param initLayoutCode CodeGroup to be filled with relevant
957      * initialization code
958      */

959     protected void readInitLayoutCode(CodeExpression layoutExp,
960                                       CodeGroup initLayoutCode)
961     {
962         if (metaLayout == null)
963             return;
964
965         layoutBeanCode = new BeanCodeManager(
966             getSupportedClass(),
967             getAllProperties(),
968             CreationDescriptor.PLACE_ALL | CreationDescriptor.CHANGED_ONLY,
969             false, // don't force empty constructor
970
false, // disable changes firing when properties are restored
971
layoutExp,
972             initLayoutCode);
973     }
974
975     /** Creates code structures for a new layout manager (opposite to
976      * readInitLayoutCode).
977      * @param initLayoutCode CodeGroup to be filled with relevant
978      * initialization code
979      * @return created CodeExpression representing the layout manager
980      */

981     protected CodeExpression createInitLayoutCode(CodeGroup initLayoutCode) {
982         if (metaLayout == null)
983             return null;
984
985         layoutBeanCode = new BeanCodeManager(
986             getSupportedClass(),
987             getAllProperties(),
988             CreationDescriptor.PLACE_ALL | CreationDescriptor.CHANGED_ONLY,
989             false,
990             layoutContext.getCodeStructure(),
991             CodeVariable.LOCAL,
992             initLayoutCode);
993
994         return layoutBeanCode.getCodeExpression();
995     }
996
997     /** This method is used for scanning code structures and recognizing
998      * components added to containers and their constraints. It's called from
999      * initialize method. When a relevant code statement is found, then the
1000     * CodeExpression of component is get and added to component, and also the
1001     * layout constraints information is read (using separate
1002     * readConstraintsCode method).
1003     * @param statement CodeStatement to be tested if it contains relevant code
1004     * @param componentCode CodeGroup to be filled with all component code
1005     * @return CodeExpression representing found component; null if the
1006     * statement is not relevant
1007     */

1008    protected CodeExpression readComponentCode(CodeStatement statement,
1009                                               CodeGroup componentCode)
1010    {
1011        CodeExpression compExp;
1012        CodeGroup constrCode;
1013        LayoutConstraints constr;
1014
1015        // look for Container.add(Component) or Container.add(Component, Object)
1016
if (getSimpleAddMethod().equals(statement.getMetaObject())) {
1017            compExp = statement.getStatementParameters()[0];
1018            constrCode = null;
1019            constr = null;
1020        }
1021        else if (getAddWithConstraintsMethod().equals(
1022                                 statement.getMetaObject()))
1023        {
1024            CodeExpression[] params = statement.getStatementParameters();
1025
1026            compExp = params[0];
1027            constrCode = getCodeStructure().createCodeGroup();
1028            constr = readConstraintsCode(params[1], constrCode, compExp);
1029        }
1030        else return null;
1031
1032        componentConstraints.add(constr);
1033        if (constrCode != null)
1034            componentCode.addGroup(constrCode);
1035        componentCode.addStatement(statement);
1036
1037        return compExp;
1038    }
1039
1040    /** This method is called from readComponentCode method to read layout
1041     * constraints of a component from code.
1042     * @param constrExp CodeExpression object of the constraints (taken from
1043     * add method in the code)
1044     * @param constrCode CodeGroup to be filled with the relevant constraints
1045     * initialization code
1046     * @param compExp CodeExpression of the component for which the constraints
1047     * are read
1048     * @return LayoutConstraints based on information read form code
1049     */

1050    protected LayoutConstraints readConstraintsCode(CodeExpression constrExp,
1051                                                    CodeGroup constrCode,
1052                                                    CodeExpression compExp)
1053    {
1054        return null; // no default implementation possible
1055
}
1056
1057    /** Creates code for a component added to the layout (opposite to
1058     * readComponentCode method).
1059     * @param componentCode CodeGroup to be filled with complete component code
1060     * (code for initializing the layout constraints and adding the
1061     * component to the layout)
1062     * @param compExp CodeExpression object representing component
1063     * @param index position of the component in the layout
1064     */

1065    protected void createComponentCode(CodeGroup componentCode,
1066                                       CodeExpression compExp,
1067                                       int index)
1068    {
1069        CodeGroup constrCode = getCodeStructure().createCodeGroup();
1070        LayoutConstraints constr = getConstraints(index);
1071
1072        // first create init code for the constraints object
1073
CodeExpression constrExp = createConstraintsCode(
1074                                       constrCode, constr, compExp, index);
1075
1076        // create "add" code for the component
1077
CodeStatement compAddStatement;
1078        if (constrExp != null) { // add with constraints
1079
compAddStatement = CodeStructure.createStatement(
1080                    getActiveContainerCodeExpression(),
1081                    getAddWithConstraintsMethod(),
1082                    new CodeExpression[] { compExp, constrExp });
1083        }
1084        else { // add without constraints
1085
compAddStatement = CodeStructure.createStatement(
1086                    getActiveContainerCodeExpression(),
1087                    getSimpleAddMethod(),
1088                    new CodeExpression[] { compExp });
1089        }
1090
1091        componentCode.addGroup(constrCode);
1092        componentCode.addStatement(compAddStatement);
1093    }
1094
1095    /** Called from createComponentCode method, creates code for a component
1096     * layout constraints (opposite to readConstraintsCode).
1097     * @param constrCode CodeGroup to be filled with constraints code
1098     * @param constr layout constraints metaobject representing the constraints
1099     * @param compExp CodeExpression object representing the component
1100     * @return created CodeExpression representing the layout constraints
1101     */

1102    protected CodeExpression createConstraintsCode(CodeGroup constrCode,
1103                                                   LayoutConstraints constr,
1104                                                   CodeExpression compExp,
1105                                                   int index)
1106    {
1107        return null; // no default implementation possible
1108
}
1109
1110    /** This method is called to get a default component layout constraints
1111     * metaobject in case it is not provided (e.g. in addComponents method).
1112     * @return the default LayoutConstraints object for the supported layout;
1113     * null if no component constraints are used
1114     */

1115    protected LayoutConstraints createDefaultConstraints() {
1116        return null; // no default implementation possible
1117
}
1118
1119    /** Method to obtain just one propetry of given name.
1120     * @return layout property of given name
1121     */

1122    protected Node.Property getProperty(String JavaDoc propName) {
1123        return metaLayout == null ? null :
1124                                    metaLayout.getPropertyByName(propName);
1125    }
1126
1127    /** This method can be overridden to provide other layout properties than
1128     * the standard ones of LayoutManager handled automatically as a bean.
1129     * This method is called from getPropertySets() implementation to obtain
1130     * the default property set for the layout (assuming there's only one
1131     * property set). So it is also possible to override (more generally)
1132     * getPropertySets() instead.
1133     * @return array of alternative properties of the layout
1134     */

1135    protected FormProperty[] getProperties() {
1136        return null; // use default "bean" properties
1137
}
1138
1139    // ---------------
1140
// useful methods for subclasses
1141

1142    /** Gets the LayoutSupportContext instance set in initialize method.
1143     * @return the attached LayoutSupportContext object providing necessary
1144     * context information
1145     */

1146    protected final LayoutSupportContext getLayoutContext() {
1147        return layoutContext;
1148    }
1149
1150    /** Gets the main CodeStructure object (holding all code structure data)
1151     * for creating/reading the code. Obtained from the layout context.
1152     * @return main CodeStructure object (for working with code structure data)
1153     */

1154    protected final CodeStructure getCodeStructure() {
1155        return layoutContext.getCodeStructure();
1156    }
1157
1158    /** Gets the internal list of layout constraints of components in the
1159     * layout. (The list contains instances of LayoutConstraints).
1160     * @return list of internally stored layout constraints of components
1161     */

1162    protected final java.util.List JavaDoc getConstraintsList() {
1163        return componentConstraints;
1164    }
1165
1166    /** This methods collects properties from all property sets to one array.
1167     * @return all properties of the layout in an array
1168     */

1169    protected final FormProperty[] getAllProperties() {
1170        if (allProperties == null)
1171            getPropertySets();
1172
1173        return allProperties;
1174    }
1175
1176    /** This method should be used by subclasses if they need to re-create
1177     * the reference layout manager instance (see BoxLayoutSupport for example).
1178     */

1179    protected final void updateLayoutInstance() {
1180        Container cont = layoutContext.getPrimaryContainer();
1181        Container contDel = layoutContext.getPrimaryContainerDelegate();
1182
1183        LayoutManager lm = null;
1184        try {
1185            lm = cloneLayoutInstance(cont, contDel);
1186        }
1187        catch (Exception JavaDoc ex) { // should not happen
1188
ex.printStackTrace();
1189        }
1190
1191        if (lm != null && metaLayout != null)
1192            metaLayout.updateInstance(lm);
1193    
1194        layoutContext.updatePrimaryContainer();
1195    }
1196
1197    /** This method finds the CodeStatement object representing setLayout
1198     * method call on the container.
1199     * @return CodeStatement of setLayout method call on the container
1200     */

1201    protected final CodeStatement getSetLayoutStatement() {
1202        Iterator it = CodeStructure.getDefinedStatementsIterator(
1203                                        getActiveContainerCodeExpression());
1204        CodeStatement[] found = CodeStructure.filterStatements(
1205                                                  it, getSetLayoutMethod());
1206        return found != null && found.length > 0 ? found[0] : null;
1207    }
1208
1209    // ---------
1210
// utility methods
1211

1212    /** Used only internally.
1213     */

1214    protected static ResourceBundle getBundle() {
1215        return org.openide.util.NbBundle.getBundle(AbstractLayoutSupport.class);
1216    }
1217
1218    /** Gets java.lang.reflect.Method object representing the simple
1219     * Container.add(Component) method. This is needed when working with
1220     * code structures.
1221     * @return java.lang.reflect.Method representing Container.add(Component)
1222     */

1223    protected static Method JavaDoc getSimpleAddMethod() {
1224        if (simpleAddMethod == null) {
1225            try {
1226                simpleAddMethod = Container.class.getMethod(
1227                                      "add", // NOI18N
1228
new Class JavaDoc[] { Component.class });
1229            }
1230            catch (NoSuchMethodException JavaDoc ex) { // should not happen
1231
ex.printStackTrace();
1232            }
1233        }
1234        return simpleAddMethod;
1235    }
1236
1237    /** Gets java.lang.reflect.Method object representing the method for adding
1238     * component with layout constraints - Container.add(Component, Object).
1239     * This is needed when working with code structures.
1240     * @return java.lang.reflect.Method object representing
1241     * Container.add(Component, Object) method
1242     */

1243    protected static Method JavaDoc getAddWithConstraintsMethod() {
1244        if (addWithConstraintsMethod == null) {
1245            try {
1246                addWithConstraintsMethod = Container.class.getMethod(
1247                                               "add", // NOI18N
1248
new Class JavaDoc[] { Component.class,
1249                                                             Object JavaDoc.class });
1250            }
1251            catch (NoSuchMethodException JavaDoc ex) { // should not happen
1252
ex.printStackTrace();
1253            }
1254        }
1255        return addWithConstraintsMethod;
1256    }
1257
1258    /** Gets java.lang.reflect.Method object representing
1259     * Container.setLayout(LayoutManager) method. This is needed when working
1260     * with code structures.
1261     * @return java.lang.reflect.Method object representing
1262     * Container.setLayout(LayoutManager) method
1263     */

1264    protected static Method JavaDoc getSetLayoutMethod() {
1265        if (setLayoutMethod == null) {
1266            try {
1267                setLayoutMethod = Container.class.getMethod(
1268                                    "setLayout", // NOI18N
1269
new Class JavaDoc[] { LayoutManager.class });
1270            }
1271            catch (NoSuchMethodException JavaDoc ex) { // should not happen
1272
ex.printStackTrace();
1273            }
1274        }
1275        return setLayoutMethod;
1276    }
1277}
1278
Popular Tags