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;
48
import java.lang.reflect.Method;
50
import org.openide.nodes.Node;
52
import org.netbeans.modules.form.layoutsupport.*;
53
import org.netbeans.modules.form.codestructure.*;
54
import org.netbeans.modules.form.*;
57
* Dedicated layout support class for JTabbedPane.
62
public class JTabbedPaneSupport extends AbstractLayoutSupport {
64
private int selectedTab = -1;
66
private static Method addTabMethod1;
67
private static Method addTabMethod2;
68
private static Method addTabMethod3;
70
/** Gets the supported layout manager class - JTabbedPane.
71
* @return the class supported by this delegate
73
public Class getSupportedClass() {
74
return JTabbedPane.class;
77
/** Removes one component from the layout (at metadata level).
78
* The code structures describing the layout is updated immediately.
79
* @param index index of the component in the layout
82
public void removeComponent(int index) {
83
super.removeComponent(index);
84
if (selectedTab >= getComponentCount())
85
selectedTab = getComponentCount() - 1;
88
/** This method is called when user clicks on the container in form
89
* designer. For JTabbedPane, we it switch the selected TAB.
90
* @param p Point of click in the container
91
* @param real instance of the container when the click occurred
92
* @param containerDelegate effective container delegate of the container
95
public void processMouseClick(Point p,
97
Container containerDelegate)
99
if (!(container instanceof JTabbedPane))
102
JTabbedPane tabbedPane = (JTabbedPane)container;
103
int n = tabbedPane.getTabCount();
104
for (int i=0; i < n; i++) {
105
if (tabbedPane.getBoundsAt(i).contains(p)) {
107
tabbedPane.setSelectedIndex(i);
113
/** This method is called when a component is selected in Component
115
* @param index position (index) of the selected component in container
118
public void selectComponent(int index) {
119
selectedTab = index; // remember as selected tab
122
/** In this method, the layout delegate has a chance to "arrange" real
123
* container instance additionally - some other way that cannot be
124
* done through layout properties and added components.
125
* @param container instance of a real container to be arranged
126
* @param containerDelegate effective container delegate of the container
129
public void arrangeContainer(Container container,
130
Container containerDelegate)
132
if (!(container instanceof JTabbedPane))
135
JTabbedPane tabbedPane = (JTabbedPane) container;
136
if (selectedTab >= 0) {
137
if (tabbedPane.getTabCount() > selectedTab) {
139
tabbedPane.setSelectedIndex(selectedTab);
141
// workaround for JTabbedPane bug 4190719
142
Component comp = tabbedPane.getSelectedComponent();
144
comp.setVisible(true);
145
tabbedPane.repaint();
148
else if (tabbedPane.getTabCount() > 0) {
149
// workaround for JTabbedPane bug 4190719
150
tabbedPane.getComponentAt(0).setVisible(true);
154
/** This method should calculate position (index) for a component dragged
155
* over a container (or just for mouse cursor being moved over container,
156
* without any component).
157
* @param container instance of a real container over/in which the
158
* component is dragged
159
* @param containerDelegate effective container delegate of the container
160
* @param component the real component being dragged; not needed here
161
* @param index position (index) of the component in its current container;
163
* @param posInCont position of mouse in the container delegate; not needed
164
* @param posInComp position of mouse in the dragged component; not needed
165
* @return index corresponding to the position of the component in the
169
public int getNewIndex(Container container,
170
Container containerDelegate,
176
if (!(container instanceof JTabbedPane))
178
return ((JTabbedPane)container).getTabCount();
182
public String getAssistantContext() {
183
return "tabbedPaneLayout"; // NOI18N
186
/** This method paints a dragging feedback for a component dragged over
187
* a container (or just for mouse cursor being moved over container,
188
* without any component).
189
* @param container instance of a real container over/in which the
190
* component is dragged
191
* @param containerDelegate effective container delegate of the container
192
* @param component the real component being dragged; not needed here
193
* @param newConstraints component layout constraints to be presented;
194
* not used for JTabbedPane
195
* @param newIndex component's index position to be presented; not needed
196
* @param g Graphics object for painting (with color and line style set)
197
* @return whether any feedback was painted (true in this case)
200
public boolean paintDragFeedback(Container container,
201
Container containerDelegate,
203
LayoutConstraints newConstraints,
207
if (!(container instanceof JTabbedPane))
210
JTabbedPane tabbedPane = (JTabbedPane) container;
211
if ((tabbedPane.getTabCount() == 0) || (component == tabbedPane.getComponentAt(0))) {
212
Dimension sz = container.getSize();
213
Insets insets = container.getInsets();
214
sz.width -= insets.left + insets.right;
215
sz.height -= insets.top + insets.bottom;
216
g.drawRect(0, 0, sz.width, sz.height);
219
Rectangle rect = tabbedPane.getComponentAt(0).getBounds();
220
g.drawRect(rect.x, rect.y, rect.width, rect.height);
225
/** Adds real components to given container (according to layout
226
* constraints stored for the components).
227
* @param container instance of a real container to be added to
228
* @param containerDelegate effective container delegate of the container
229
* @param components components to be added
230
* @param index position at which to add the components to container
233
public void addComponentsToContainer(Container container,
234
Container containerDelegate,
235
Component[] components,
238
if (!(container instanceof JTabbedPane))
241
for (int i=0; i < components.length; i++) {
242
LayoutConstraints constraints = getConstraints(i + index);
243
if (constraints instanceof TabConstraints) {
244
JTabbedPane tabbedPane = (JTabbedPane) container;
247
((FormProperty)constraints.getProperties()[0])
250
((FormProperty)constraints.getProperties()[1])
253
((FormProperty)constraints.getProperties()[2])
257
title instanceof String ? (String) title : null,
258
icon instanceof Icon ? (Icon) icon : null,
260
tooltip instanceof String ? (String) tooltip : null);
262
catch (Exception ex) {
263
org.openide.ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex);
271
/** This method is used for scanning code structures and recognizing
272
* components added to containers and their constraints. It's called from
273
* initialize method. When a relevant code statement is found, then the
274
* CodeExpression of component is get and added to component, and also the
275
* layout constraints information is read.
276
* @param statement CodeStatement to be tested if it contains relevant code
277
* @param componentCode CodeGroup to be filled with all component code
278
* @return CodeExpression representing found component; null if the
279
* statement is not relevant
282
protected CodeExpression readComponentCode(CodeStatement statement,
283
CodeGroup componentCode)
285
CodeExpression compExp;
286
int[] constrPropsIndices;
287
CodeExpression[] params = statement.getStatementParameters();
289
Object connectingObject = statement.getMetaObject();
290
if (getAddTabMethod1().equals(connectingObject)) {
292
constrPropsIndices = new int[] { 0, 1, -1, 2 }; // tab, icon, tooltip
294
else if (getAddTabMethod2().equals(connectingObject)) {
296
constrPropsIndices = new int[] { 0, 1, -1 }; // tab, icon
298
else if (getAddTabMethod3().equals(connectingObject)) {
300
constrPropsIndices = new int[] { 0, -1 }; // tab
304
TabConstraints constr = new TabConstraints("tab"); // NOI18N
305
Node.Property[] props = constr.getProperties();
306
for (int i=0; i < params.length; i++) {
307
if (params[i] != compExp)
308
FormCodeSupport.readPropertyExpression(
310
props[constrPropsIndices[i]],
313
getConstraintsList().add(constr);
315
componentCode.addStatement(statement);
320
/** Creates code for a component added to the layout (opposite to
321
* readComponentCode method).
322
* @param componentCode CodeGroup to be filled with complete component code
323
* (code for initializing the layout constraints and adding the
324
* component to the layout)
325
* @param compExp CodeExpression object representing component
326
* @param index position of the component in the layout
329
protected void createComponentCode(CodeGroup componentCode,
330
CodeExpression componentExpression,
333
LayoutConstraints constr = getConstraints(index);
334
if (!(constr instanceof TabConstraints))
335
return; // should not happen
337
((TabConstraints)constr).createComponentCode(
339
getLayoutContext().getContainerCodeExpression(),
340
componentExpression);
343
/** This method is called to get a default component layout constraints
344
* metaobject in case it is not provided (e.g. in addComponents method).
345
* @return the default LayoutConstraints object for the supported layout;
346
* null if no component constraints are used
349
protected LayoutConstraints createDefaultConstraints() {
350
return new TabConstraints("tab"+(getComponentCount())); // NOI18N
355
// tab, icon, component, tooltip
356
private static Method getAddTabMethod1() {
357
if (addTabMethod1 == null) {
359
addTabMethod1 = JTabbedPane.class.getMethod(
361
new Class[] { String.class, Icon.class,
362
Component.class, String.class });
364
catch (NoSuchMethodException ex) { // should not happen
365
ex.printStackTrace();
368
return addTabMethod1;
371
// tab, icon, component
372
private static Method getAddTabMethod2() {
373
if (addTabMethod2 == null) {
375
addTabMethod2 = JTabbedPane.class.getMethod(
377
new Class[] { String.class, Icon.class,
380
catch (NoSuchMethodException ex) { // should not happen
381
ex.printStackTrace();
384
return addTabMethod2;
388
private static Method getAddTabMethod3() {
389
if (addTabMethod3 == null) {
391
addTabMethod3 = JTabbedPane.class.getMethod(
393
new Class[] { String.class, Component.class });
395
catch (NoSuchMethodException ex) { // should not happen
396
ex.printStackTrace();
399
return addTabMethod3;
404
/** LayoutConstraints implementation for managing JTabbedPane tab
407
public static class TabConstraints implements LayoutConstraints {
408
private String title;
410
private String toolTip;
412
private FormProperty[] properties;
414
private CodeExpression containerExpression;
415
private CodeExpression componentExpression;
416
private CodeGroup componentCode;
417
private CodeExpression[] propertyExpressions;
419
public TabConstraints(String title) {
423
public TabConstraints(String title, Icon icon, String toolTip) {
426
this.toolTip = toolTip;
429
public String getTitle() {
433
public Icon getIcon() {
437
public String getToolTip() {
443
public Node.Property[] getProperties() {
444
if (properties == null) {
445
properties = new FormProperty[] {
446
new FormProperty("TabConstraints.tabTitle", // NOI18N
448
getBundle().getString("PROP_tabTitle"), // NOI18N
449
getBundle().getString("HINT_tabTitle")) { // NOI18N
451
public Object getTargetValue() {
455
public void setTargetValue(Object value) {
456
title = (String)value;
460
protected Object getRealValue(Object value) {
461
Object realValue = super.getRealValue(value);
462
if (realValue == FormDesignValue.IGNORED_VALUE)
463
realValue = ((FormDesignValue)value).getDescription();
468
protected void propertyValueChanged(Object old, Object current) {
469
if (isChangeFiring())
471
super.propertyValueChanged(old, current);
475
new FormProperty("TabConstraints.tabIcon", // NOI18N
477
getBundle().getString("PROP_tabIcon"), // NOI18N
478
getBundle().getString("HINT_tabIcon")) { // NOI18N
480
public Object getTargetValue() {
484
public void setTargetValue(Object value) {
489
public boolean supportsDefaultValue() {
494
public Object getDefaultValue() {
499
protected void propertyValueChanged(Object old, Object current) {
500
if (isChangeFiring())
502
super.propertyValueChanged(old, current);
506
new FormProperty("TabConstraints.tabToolTip", // NOI18N
508
getBundle().getString("PROP_tabToolTip"), // NOI18N
509
getBundle().getString("HINT_tabToolTip")) { // NOI18N
511
public Object getTargetValue() {
515
public void setTargetValue(Object value) {
516
toolTip = (String)value;
520
protected Object getRealValue(Object value) {
521
Object realValue = super.getRealValue(value);
522
if (realValue == FormDesignValue.IGNORED_VALUE)
523
realValue = ((FormDesignValue)value).getDescription();
528
public boolean supportsDefaultValue() {
533
public Object getDefaultValue() {
538
protected void propertyValueChanged(Object old, Object current) {
539
if (isChangeFiring())
541
super.propertyValueChanged(old, current);
546
properties[0].setChanged(true);
552
public Object getConstraintsObject() {
556
public LayoutConstraints cloneConstraints() {
557
LayoutConstraints constr = new TabConstraints(title);
558
org.netbeans.modules.form.FormUtils.copyProperties(
560
constr.getProperties(),
561
FormUtils.CHANGED_ONLY | FormUtils.DISABLE_CHANGE_FIRING);
567
private void createComponentCode(CodeGroup compCode,
568
CodeExpression contExp,
569
CodeExpression compExp)
571
this.componentCode = compCode;
572
this.containerExpression = contExp;
573
this.componentExpression = compExp;
574
this.propertyExpressions = null;
578
private void updateCode() {
579
if (componentCode == null)
582
CodeStructure.removeStatements(
583
componentCode.getStatementsIterator());
584
componentCode.removeAll();
589
CodeExpression[] params;
591
if (properties[2].isChanged()) {
592
addTabMethod = getAddTabMethod1();
593
params = new CodeExpression[] { getPropertyExpression(0), // tab
594
getPropertyExpression(1), // icon
596
getPropertyExpression(2) }; // tooltip
598
else if (properties[1].isChanged()) {
599
addTabMethod = getAddTabMethod2();
600
params = new CodeExpression[] { getPropertyExpression(0), // tab
601
getPropertyExpression(1), // icon
602
componentExpression };
605
addTabMethod = getAddTabMethod3();
606
params = new CodeExpression[] { getPropertyExpression(0), // tab
607
componentExpression };
610
CodeStatement addTabStatement = CodeStructure.createStatement(
614
componentCode.addStatement(addTabStatement);
617
private CodeExpression getPropertyExpression(int index) {
618
if (propertyExpressions == null) {
619
propertyExpressions = new CodeExpression[properties.length];
620
for (int i=0; i < properties.length; i++) {
621
propertyExpressions[i] =
622
componentExpression.getCodeStructure().createExpression(
623
FormCodeSupport.createOrigin(properties[i]));
626
return propertyExpressions[index];