2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.form.layoutsupport.delegates;
47
import java.lang.reflect.Constructor;
49
import org.openide.nodes.Node;
50
import org.openide.util.Utilities;
52
import org.netbeans.lib.awtextra.AbsoluteLayout;
53
import org.netbeans.lib.awtextra.AbsoluteConstraints;
55
import org.netbeans.modules.form.layoutsupport.*;
56
import org.netbeans.modules.form.codestructure.*;
57
import org.netbeans.modules.form.FormProperty;
58
import org.netbeans.modules.form.FormLoaderSettings;
61
* Support class for AbsoluteLayout - for absolute positioning and sizing of
62
* components using AbsoluteConstraints. This is an example of support for
63
* layout manager using component constraints as complex objects initialized
64
* by constructor with parameters mapped to properties. AbsoluteLayoutSupport
65
* is also the superclass of NullLayoutSupport and JLayeredPane support, so it
66
* is a bit more complicated than would be necessary for simple implementation.
71
public class AbsoluteLayoutSupport extends AbstractLayoutSupport {
73
/** The icon for AbsoluteLayout. */
74
private static String iconURL =
75
"org/netbeans/modules/form/layoutsupport/resources/AbsoluteLayout.gif"; // NOI18N
76
/** The icon for AbsoluteLayout. */
77
private static String icon32URL =
78
"org/netbeans/modules/form/layoutsupport/resources/AbsoluteLayout32.gif"; // NOI18N
80
private static Constructor constrConstructor;
82
private static FormLoaderSettings formSettings = FormLoaderSettings.getInstance();
84
/** Gets the supported layout manager class - AbsoluteLayout.
85
* @return the class supported by this delegate
87
public Class getSupportedClass() {
88
return AbsoluteLayout.class;
91
/** Provides an icon to be used for the layout node in Component
92
* Inspector. Only 16x16 color icon is required.
93
* @param type is one of BeanInfo constants: ICON_COLOR_16x16,
94
* ICON_COLOR_32x32, ICON_MONO_16x16, ICON_MONO_32x32
95
* @return icon to be displayed for node in Component Inspector
98
public Image getIcon(int type) {
100
case BeanInfo.ICON_COLOR_16x16:
101
case BeanInfo.ICON_MONO_16x16:
102
return Utilities.loadImage(iconURL);
104
return Utilities.loadImage(icon32URL);
108
/** This method is called when switching layout - giving an opportunity to
109
* convert the previous constrainst of components to constraints of the new
110
* layout (this layout). For AbsoluteLayout, we can simply create new
111
* constraints from positions and sizes of real components.
112
* @param previousConstraints [input] layout constraints of components in
113
* the previous layout
114
* @param currentConstraints [output] array of converted constraints for
115
* the new layout - to be filled
116
* @param components [input] real components in a real container having the
120
public void convertConstraints(LayoutConstraints[] previousConstraints,
121
LayoutConstraints[] currentConstraints,
122
Component[] components)
124
if (currentConstraints == null || components == null)
127
for (int i=0; i < currentConstraints.length; i++)
128
if (currentConstraints[i] == null) {
129
Rectangle bounds = components[i].getBounds();
130
Dimension prefSize = components[i].getPreferredSize();
133
int w = computeConstraintSize(bounds.width, -1, prefSize.width);
134
int h = computeConstraintSize(bounds.height, -1, prefSize.height);
136
currentConstraints[i] = new AbsoluteLayoutConstraints(x, y, w, h);
140
/** This method calculates layout constraints for a component dragged
141
* over a container (or just for mouse cursor being moved over container,
142
* without any component).
143
* @param container instance of a real container over/in which the
144
* component is dragged
145
* @param containerDelegate effective container delegate of the container
146
* (for layout managers we always use container delegate instead of
148
* @param component the real component being dragged, can be null
149
* @param index position (index) of the component in its container;
150
* -1 if there's no dragged component
151
* @param posInCont position of mouse in the container delegate
152
* @param posInComp position of mouse in the dragged component; null if
153
* there's no dragged component
154
* @return new LayoutConstraints object corresponding to the position of
155
* the component in the container
158
public LayoutConstraints getNewConstraints(Container container,
159
Container containerDelegate,
170
LayoutConstraints constr = getConstraints(index);
172
if (component != null) {
176
if (constr instanceof AbsoluteLayoutConstraints) {
177
currentW = ((AbsoluteLayoutConstraints)constr).w;
178
currentH = ((AbsoluteLayoutConstraints)constr).h;
185
Dimension size = component.getSize();
186
Dimension prefSize = component.getPreferredSize();
188
w = computeConstraintSize(size.width, currentW, prefSize.width);
189
h = computeConstraintSize(size.height, currentH, prefSize.height);
192
if (posInComp != null) {
197
if (formSettings.getApplyGridToPosition()) {
198
x = computeGridSize(x, formSettings.getGridX());
199
y = computeGridSize(y, formSettings.getGridY());
202
assistantParams = new Object[] {Integer.valueOf(x), Integer.valueOf(y)};
203
return createNewConstraints(constr, x, y, w, h);
206
private Object[] assistantParams;
208
public String getAssistantContext() {
209
return "absoluteLayout"; // NOI18N
213
public Object[] getAssistantParams() {
214
return assistantParams;
217
/** This method paints a dragging feedback for a component dragged over
218
* a container (or just for mouse cursor being moved over container,
219
* without any component). For AbsoluteLayout, it simply paints a rectangle
220
* corresponding to the component position and size.
221
* @param container instance of a real container over/in which the
222
* component is dragged
223
* @param containerDelegate effective container delegate of the container
224
* (for layout managers we always use container delegate instead of
226
* @param component the real component being dragged, can be null
227
* @param newConstraints component layout constraints to be presented
228
* @param newIndex component's index position to be presented; not used
230
* @param g Graphics object for painting (with color and line style set)
231
* @return whether any feedback was painted (true in this case)
234
public boolean paintDragFeedback(Container container,
235
Container containerDelegate,
237
LayoutConstraints newConstraints,
241
Rectangle r = ((AbsoluteLayoutConstraints)newConstraints).getBounds();
245
if (w == -1 || h == -1) {
246
// JInternalFrame.getPreferredSize() behaves suspiciously
247
Dimension pref = component instanceof javax.swing.JInternalFrame ?
248
component.getSize() : component.getPreferredSize();
249
if (w == -1) w = pref.width;
250
if (h == -1) h = pref.height;
256
g.drawRect(r.x, r.y, w, h);
261
/** Provides resizing options for given component. It can combine the
262
* bit-flag constants RESIZE_UP, RESIZE_DOWN, RESIZE_LEFT, RESIZE_RIGHT.
263
* @param container instance of a real container in which the
264
* component is to be resized
265
* @param containerDelegate effective container delegate of the container
266
* (e.g. like content pane of JFrame)
267
* @param component real component to be resized
268
* @param index position of the component in its container
269
* @return resizing options for the component; 0 if no resizing is possible
272
public int getResizableDirections(Container container,
273
Container containerDelegate,
277
return RESIZE_UP | RESIZE_DOWN | RESIZE_LEFT | RESIZE_RIGHT;
280
/** This method should calculate layout constraints for a component being
282
* @param container instance of a real container in which the
283
* component is resized
284
* @param containerDelegate effective container delegate of the container
285
* (e.g. like content pane of JFrame)
286
* @param component real component being resized
287
* @param index position of the component in its container
288
* @param sizeChanges Insets object with size differences
289
* @param posInCont position of mouse in the container delegate
290
* @return component layout constraints for resized component; null if
291
* resizing is not possible or not implemented
294
public LayoutConstraints getResizedConstraints(Container container,
295
Container containerDelegate,
298
Rectangle originalBounds,
303
x = originalBounds.x;
304
y = originalBounds.y;
305
w = originalBounds.width;
306
h = originalBounds.height;
308
Dimension prefSize = component.getPreferredSize();
309
int currentW, currentH;
311
LayoutConstraints constr = getConstraints(index);
312
if (constr instanceof AbsoluteLayoutConstraints) {
313
Rectangle r = ((AbsoluteLayoutConstraints)constr).getBounds();
318
currentW = computeConstraintSize(w, -1, prefSize.width);
319
currentH = computeConstraintSize(h, -1, prefSize.height);
325
if (sizeChanges.left + sizeChanges.right == 0)
326
w = currentW; // no change
327
else { // compute resized width and x coordinate
328
w += sizeChanges.left + sizeChanges.right;
329
w = w <= 0 ? -1 : computeConstraintSize(w, currentW, prefSize.width);
332
if (formSettings.getApplyGridToSize()) {
333
int gridW = computeGridSize(w, formSettings.getGridX());
334
x -= sizeChanges.left +
335
(gridW - w) * sizeChanges.left
336
/ (sizeChanges.left + sizeChanges.right);
340
else if (sizeChanges.left != 0)
341
x = x2 - prefSize.width;
344
if (sizeChanges.top + sizeChanges.bottom == 0)
345
h = currentH; // no change
346
else { // compute resized height and y coordinate
347
h += sizeChanges.top + sizeChanges.bottom;
348
h = h <= 0 ? -1 : computeConstraintSize(h, currentH, prefSize.height);
351
if (formSettings.getApplyGridToSize()) {
352
int gridH = computeGridSize(h, formSettings.getGridY());
353
y -= sizeChanges.top +
354
(gridH - h) * sizeChanges.top
355
/ (sizeChanges.top + sizeChanges.bottom);
359
else if (sizeChanges.top != 0)
360
y = y2 - prefSize.height;
363
return createNewConstraints(constr, x, y, w, h);
368
/** This method is called from readComponentCode method to read layout
369
* constraints of a component from code (AbsoluteConstraints in this case).
370
* @param constrExp CodeExpression object of the constraints (taken from
371
* add method in the code)
372
* @param constrCode CodeGroup to be filled with the relevant constraints
373
* initialization code; not needed here because AbsoluteConstraints
374
* object is represented only by a single code expression (based on
375
* constructor) and no statements
376
* @param compExp CodeExpression of the component for which the constraints
377
* are read (not needed here)
378
* @return LayoutConstraints based on information read form code
381
protected LayoutConstraints readConstraintsCode(CodeExpression constrExp,
382
CodeGroup constrCode,
383
CodeExpression compExp)
385
AbsoluteLayoutConstraints constr =
386
new AbsoluteLayoutConstraints(0, 0, -1, -1);
388
CodeExpression[] params = constrExp.getOrigin().getCreationParameters();
389
if (params.length == 4) {
390
// reading is done in AbsoluteLayoutConstraints
391
constr.readPropertyExpressions(params, 0);
397
/** Called from createComponentCode method, creates code for a component
398
* layout constraints (opposite to readConstraintsCode).
399
* @param constrCode CodeGroup to be filled with constraints code; not
400
* needed here because AbsoluteConstraints object is represented
401
* only by a single constructor code expression and no statements
402
* @param constr layout constraints metaobject representing the constraints
403
* @param compExp CodeExpression object representing the component; not
405
* @return created CodeExpression representing the layout constraints
408
protected CodeExpression createConstraintsCode(CodeGroup constrCode,
409
LayoutConstraints constr,
410
CodeExpression compExp,
413
if (!(constr instanceof AbsoluteLayoutConstraints))
416
AbsoluteLayoutConstraints absConstr = (AbsoluteLayoutConstraints)constr;
417
// code expressions for constructor parameters are created in
418
// AbsoluteLayoutConstraints
419
CodeExpression[] params = absConstr.createPropertyExpressions(
420
getCodeStructure(), 0);
421
return getCodeStructure().createExpression(getConstraintsConstructor(),
425
/** This method is called to get a default component layout constraints
426
* metaobject in case it is not provided (e.g. in addComponents method).
427
* @return the default LayoutConstraints object for the supported layout
430
protected LayoutConstraints createDefaultConstraints() {
431
return new AbsoluteLayoutConstraints(0, 0, -1, -1);
436
protected LayoutConstraints createNewConstraints(
437
LayoutConstraints currentConstr,
438
int x, int y, int w, int h)
440
return new AbsoluteLayoutConstraints(x, y, w, h);
443
private static int computeConstraintSize(int newSize,
446
return newSize != -1 && (newSize != prefSize
447
|| (currSize != -1 && currSize == prefSize)) ?
451
private static int computeGridSize(int size, int step) {
452
if (step <= 0) return size;
453
int mod = size % step;
454
return mod >= step/2 ? size + step - mod : size - mod;
457
private static Constructor getConstraintsConstructor() {
458
if (constrConstructor == null) {
460
constrConstructor = AbsoluteConstraints.class.getConstructor(
461
new Class[] { Integer.TYPE, Integer.TYPE,
462
Integer.TYPE, Integer.TYPE });
464
catch (NoSuchMethodException ex) { // should not happen
465
ex.printStackTrace();
468
return constrConstructor;
473
/** LayoutConstraints implementation class for AbsoluteConstraints.
475
public static class AbsoluteLayoutConstraints implements LayoutConstraints {
476
int x, y, w, h; // position and size
478
private Node.Property[] properties;
480
Component refComponent;
482
public AbsoluteLayoutConstraints(int x, int y, int w, int h)
490
public Node.Property[] getProperties() {
491
if (properties == null) {
492
properties = createProperties();
493
reinstateProperties();
498
public Object getConstraintsObject() {
499
return new AbsoluteConstraints(x, y, w, h);
502
public LayoutConstraints cloneConstraints() {
503
return new AbsoluteLayoutConstraints(x, y, w, h);
508
public Rectangle getBounds() {
509
return new Rectangle(x, y, w, h);
512
protected Node.Property[] createProperties() {
513
return new Node.Property[] {
514
new FormProperty("AbsoluteLayoutConstraints posx", // NOI18N
516
getBundle().getString("PROP_posx"), // NOI18N
517
getBundle().getString("HINT_posx")) { // NOI18N
519
public Object getTargetValue() {
520
return new Integer(x);
522
public void setTargetValue(Object value) {
523
x = ((Integer)value).intValue();
526
public void setPropertyContext(
527
org.netbeans.modules.form.FormPropertyContext ctx)
528
{ // disabling this method due to limited persistence
529
} // capabilities (compatibility with previous versions)
532
new FormProperty("AbsoluteLayoutConstraints posy", // NOI18N
534
getBundle().getString("PROP_posy"), // NOI18N
535
getBundle().getString("HINT_posy")) { // NOI18N
537
public Object getTargetValue() {
538
return new Integer(y);
540
public void setTargetValue(Object value) {
541
y = ((Integer)value).intValue();
544
public void setPropertyContext(
545
org.netbeans.modules.form.FormPropertyContext ctx)
546
{ // disabling this method due to limited persistence
547
} // capabilities (compatibility with previous versions)
550
new FormProperty("AbsoluteLayoutConstraints width", // NOI18N
552
getBundle().getString("PROP_width"), // NOI18N
553
getBundle().getString("HINT_width")) { // NOI18N
555
public Object getTargetValue() {
556
return new Integer(w);
558
public void setTargetValue(Object value) {
559
w = ((Integer)value).intValue();
562
public boolean supportsDefaultValue () {
566
public Object getDefaultValue() {
567
return new Integer(-1);
570
public PropertyEditor getExpliciteEditor() {
571
return new SizeEditor();
574
public Object getValue(String key) {
575
if ("canEditAsText".equals(key)) // NOI18N
577
return super.getValue(key);
580
public String getJavaInitializationString() {
581
if (nullMode && refComponent != null && !isChanged())
582
return Integer.toString(
583
refComponent.getPreferredSize().width);
584
return super.getJavaInitializationString();
587
public void setPropertyContext(
588
org.netbeans.modules.form.FormPropertyContext ctx)
589
{ // disabling this method due to limited persistence
590
} // capabilities (compatibility with previous versions)
593
new FormProperty("AbsoluteLayoutConstraints height", // NOI18N
595
getBundle().getString("PROP_height"), // NOI18N
596
getBundle().getString("HINT_height")) { // NOI18N
598
public Object getTargetValue() {
599
return new Integer(h);
601
public void setTargetValue(Object value) {
602
h = ((Integer)value).intValue();
605
public boolean supportsDefaultValue () {
609
public Object getDefaultValue() {
610
return new Integer(-1);
613
public PropertyEditor getExpliciteEditor() {
614
return new SizeEditor();
617
public Object getValue(String key) {
618
if ("canEditAsText".equals(key)) // NOI18N
620
return super.getValue(key);
623
public String getJavaInitializationString() {
624
if (nullMode && refComponent != null && !isChanged())
625
return Integer.toString(
626
refComponent.getPreferredSize().height);
627
return super.getJavaInitializationString();
630
public void setPropertyContext(
631
org.netbeans.modules.form.FormPropertyContext ctx)
632
{ // disabling this method due to limited persistence
633
} // capabilities (compatibility with previous versions)
638
private void reinstateProperties() {
640
for (int i=0; i < properties.length; i++) {
641
FormProperty prop = (FormProperty) properties[i];
642
prop.reinstateProperty();
645
catch(IllegalAccessException e1) {} // should not happen
646
catch(java.lang.reflect.InvocationTargetException e2) {} // should not happen
649
/** This method creates CodeExpression objects for properties of
650
* AbsoluteConstraints - this is used by the layout delegate's method
651
* createConstraintsCode which uses the expressions as parameters
652
* in AbsoluteConstraints constructor.
653
* @param codeStructure main CodeStructure object in which the code
654
* expressions are created
655
* @param shift this parameter is used only by subclasses of
656
* AbsoluteLayoutConstraints (which may insert another
657
* constructor parameters before x, y, w and h)
658
* @return array of created code expressions
660
protected final CodeExpression[] createPropertyExpressions(
661
CodeStructure codeStructure,
664
// first make sure properties are created...
667
// ...then create code expressions based on the properties
668
CodeExpression xEl = codeStructure.createExpression(
669
FormCodeSupport.createOrigin(properties[shift++]));
670
CodeExpression yEl = codeStructure.createExpression(
671
FormCodeSupport.createOrigin(properties[shift++]));
672
CodeExpression wEl = codeStructure.createExpression(
673
FormCodeSupport.createOrigin(properties[shift++]));
674
CodeExpression hEl = codeStructure.createExpression(
675
FormCodeSupport.createOrigin(properties[shift]));
676
return new CodeExpression[] { xEl, yEl, wEl, hEl };
679
/** This method reads CodeExpression objects for properties (used as
680
* AbsoluteConstraints constructor parameters). Called by layout
681
* delegate's readConstraintsCode method.
682
* @param exps array of code expressions to read to properties
683
* @param shift this parameter is used only by subclasses of
684
* AbsoluteLayoutConstraints (which may insert another
685
* constructor parameters before x, y, w and h)
687
protected final void readPropertyExpressions(CodeExpression[] exps,
690
// first make sure properties are created...
693
// ...then map the properties to the code expressions
694
for (int i=0; i < exps.length; i++)
695
FormCodeSupport.readPropertyExpression(exps[i],
703
/** PropertyEditor for width and height properties of
704
* AbsoluteLayoutConstraints.
706
public static final class SizeEditor extends PropertyEditorSupport {
708
final Integer prefValue = new Integer(-1);
709
final String prefTag = getBundle().getString("VALUE_preferred"); // NOI18N
712
public String[] getTags() {
713
return new String[] { prefTag };
717
public String getAsText() {
718
Object value = getValue();
719
return prefValue.equals(value) ?
720
prefTag : value.toString();
724
public void setAsText(String str) {
725
if (prefTag.equals(str))
729
setValue(new Integer(Integer.parseInt(str)));
731
catch (NumberFormatException e) {} // ignore
735
public String getJavaInitializationString() {
736
Object value = getValue();
737
return value != null ? value.toString() : null;