001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.form.editors;
043:
044: import java.awt.event.*;
045: import java.beans.PropertyChangeListener;
046: import java.beans.PropertyChangeEvent;
047: import java.lang.reflect.Modifier;
048:
049: import javax.swing.*;
050: import org.openide.awt.Mnemonics;
051:
052: import org.openide.util.NbBundle;
053: import org.openide.util.WeakListeners;
054:
055: /** JPanel extension containing components which allows visual
056: * editing Modifier object.
057: * This class has two main properties: mask (possible values mask)
058: * and modifier (current value).
059: *
060: * @author Petr Hamernik
061: */
062: final class ModifierPanel {
063:
064: // ------------------------- Statics -------------------------------
065:
066: /** Name of 'mask' property */
067: public static final String PROP_MASK = "mask"; // NOI18N
068:
069: /** Name of 'modifier' property (current value) */
070: public static final String PROP_MODIFIER = "modifier"; // NOI18N
071:
072: private static final int CHECK_ABSTRACT = 0;
073: private static final int CHECK_FINAL = 1;
074: private static final int CHECK_STATIC = 2;
075: private static final int CHECK_SYNCHRONIZED = 3;
076: private static final int CHECK_TRANSIENT = 4;
077: private static final int CHECK_VOLATILE = 5;
078: private static final int CHECK_NATIVE = 6;
079:
080: /** Names of modifiers */
081: static final String MODIFIER_NAMES[] = { "a&bstract", "&final",
082: "&static", "synch&ronized", "&transient", "&volatile",
083: "nat&ive" // NOI18N
084: };
085:
086: private static final String[] MODIFIER_DESCRIPTION_KEYS = {
087: "ACSD_ModifierPanel_Modifier_Abstract", // NOI18N
088: "ACSD_ModifierPanel_Modifier_Final", // NOI18N
089: "ACSD_ModifierPanel_Modifier_Static", // NOI18N
090: "ACSD_ModifierPanel_Modifier_Synchronized", // NOI18N
091: "ACSD_ModifierPanel_Modifier_Transient", // NOI18N
092: "ACSD_ModifierPanel_Modifier_Volatile", // NOI18N
093: "ACSD_ModifierPanel_Modifier_Native" // NOI18N
094: };
095:
096: /** Values of modifiers */
097: static final int MODIFIER_VALUES[] = { Modifier.ABSTRACT,
098: Modifier.FINAL, Modifier.STATIC, Modifier.SYNCHRONIZED,
099: Modifier.TRANSIENT, Modifier.VOLATILE, Modifier.NATIVE };
100:
101: /** Count of the modifiers */
102: static final int MODIFIER_COUNT = MODIFIER_VALUES.length;
103:
104: /** Names of accessibility */
105: static final String ACCESS_NAMES[] = { "<default>", "private",
106: "protected", "public" // NOI18N
107: };
108:
109: /** Values of accessibility */
110: static final int ACCESS_VALUES[] = { 0, Modifier.PRIVATE,
111: Modifier.PROTECTED, Modifier.PUBLIC };
112:
113: /** Mask of access modifiers */
114: static final int ACCESS_MASK = Modifier.PRIVATE
115: | Modifier.PROTECTED | Modifier.PUBLIC;
116:
117: /** Mask of non-access modifiers */
118: private static final int OTHERS_MASK = Modifier.ABSTRACT
119: | Modifier.FINAL | Modifier.STATIC | Modifier.SYNCHRONIZED
120: | Modifier.TRANSIENT | Modifier.VOLATILE | Modifier.NATIVE
121: | Modifier.STRICT;
122:
123: /** Mask of all possible modifiers. */
124: static final int EDITABLE_MASK = ACCESS_MASK | OTHERS_MASK;
125:
126: // ------------------ Instance Fields --------------------------
127:
128: /** Reference back to the editor that created this panel. */
129: private ModifierEditor myEditor;
130:
131: /** Current access values shown in the combo box */
132: private int currentAccessValues[];
133:
134: /** Current access names shown in the combo box */
135: private String currentAccessNames[];
136:
137: /** JCheckBox array */
138: private JCheckBox[] checks;
139:
140: /** listener for visual changes */
141: private ActionListener listener;
142:
143: /** Ignored flag - used during firing change events */
144: private boolean ignored = false;
145:
146: /** listener for ModifierEditor changes */
147: private PropertyChangeListener editorListener;
148:
149: /** Creates new form ModifiersPanel */
150: public ModifierPanel(ModifierEditor ed) {
151: myEditor = ed;
152: currentAccessValues = ACCESS_VALUES;
153: currentAccessNames = ACCESS_NAMES;
154:
155: editorListener = new PropertyChangeListener() {
156: public void propertyChange(PropertyChangeEvent evt) {
157: if (PROP_MODIFIER.equals(evt.getPropertyName())
158: || PROP_MASK.equals(evt.getPropertyName())) {
159: updateAccess();
160: ignored = true;
161: updateComponents();
162: ignored = false;
163: }
164: }
165: };
166:
167: myEditor.addPropertyChangeListener(WeakListeners
168: .propertyChange(editorListener, myEditor));
169:
170: listener = new ActionListener() {
171:
172: public void actionPerformed(ActionEvent evt) {
173: // remove abstract, if private access is being selected.
174:
175: int selIndex = accessCombo.getSelectedIndex();
176: // disallow abstract, if private access is selected.
177: if (evt.getSource() == accessCombo && selIndex < 0) {
178: // revert the combo to the previous value.
179: return;
180: }
181: if (checks[CHECK_ABSTRACT].isSelected()
182: && ((myEditor.getModifier() & MODIFIER_VALUES[CHECK_ABSTRACT]) == 0)
183: && ((myEditor.getModifier() & Modifier.PRIVATE) > 0)) {
184: checks[CHECK_ABSTRACT].setSelected(false);
185: }
186: if (selIndex >= 0
187: && (currentAccessValues[accessCombo
188: .getSelectedIndex()] & Modifier.PRIVATE) > 0
189: && (myEditor.getModifier() & Modifier.PRIVATE) == 0) {
190: checks[CHECK_ABSTRACT].setSelected(false);
191: }
192:
193: excludeChecks(CHECK_ABSTRACT, CHECK_FINAL);
194: excludeChecks(CHECK_ABSTRACT, CHECK_NATIVE);
195: excludeChecks(CHECK_ABSTRACT, CHECK_STATIC);
196: excludeChecks(CHECK_ABSTRACT, CHECK_SYNCHRONIZED);
197: excludeChecks(CHECK_VOLATILE, CHECK_FINAL);
198:
199: if (!ignored)
200: updateValue();
201:
202: }
203: };
204:
205: ignored = true;
206: initBasicComponents();
207:
208: updateAccess();
209: updateModifiers();
210: updateComponents();
211: ignored = false;
212: }
213:
214: /** Makes sure that the specified two checkboxes are mutually exclusive by
215: * unselecting one if the other one becomes selected.
216: */
217: private void excludeChecks(int check1, int check2) {
218: if (checks[check1].isSelected()
219: && ((myEditor.getModifier() & MODIFIER_VALUES[check1]) == 0))
220: checks[check2].setSelected(false);
221: else if (checks[check2].isSelected()
222: && ((myEditor.getModifier() & MODIFIER_VALUES[check2]) == 0))
223: checks[check1].setSelected(false);
224: }
225:
226: private void initBasicComponents() {
227: accessCombo = new JComboBox();
228: accessCombo.addActionListener(listener);
229: accessCombo.getAccessibleContext().setAccessibleName(
230: "ACS_AccessRights"); // NOI18N
231: accessCombo.getAccessibleContext().setAccessibleDescription(
232: "ACSD_AccessRights"); // NOI18N
233:
234: modifPanel = new JPanel();
235: modifPanel.setLayout(new java.awt.GridLayout(4, 2, 4, 4));
236: modifPanel.getAccessibleContext().setAccessibleName(
237: "ACSN_OtherModifiers"); // NOI18N
238: modifPanel.getAccessibleContext().setAccessibleDescription(
239: "ACSD_OtherModifiers"); // NOI18N
240:
241: checks = new JCheckBox[MODIFIER_COUNT];
242: for (int i = 0; i < MODIFIER_COUNT; i++) {
243: checks[i] = new JCheckBox();
244: Mnemonics.setLocalizedText(checks[i], MODIFIER_NAMES[i]);
245: checks[i].getAccessibleContext().setAccessibleDescription(
246: getModifierDescription(i));
247: modifPanel.add(checks[i]);
248: checks[i]
249: .setEnabled((myEditor.getMask() & MODIFIER_VALUES[i]) != 0);
250: checks[i].addActionListener(listener);
251: }
252: }
253:
254: private void initComponents() {
255: jLabel1 = new JLabel();
256: jLabel1.setLabelFor(accessCombo);
257: Mnemonics.setLocalizedText(jLabel1,
258: getString("LAB_AccessRights")); // NOI18N
259:
260: jPanel2 = new JPanel();
261: jPanel2.setLayout(new java.awt.BorderLayout(8, 8));
262: jPanel2.setBorder(new javax.swing.border.EmptyBorder(
263: new java.awt.Insets(5, 5, 5, 5)));
264: jPanel2.add(jLabel1, java.awt.BorderLayout.WEST);
265: jPanel2.add(accessCombo, java.awt.BorderLayout.CENTER);
266: modifPanel.setBorder(new javax.swing.border.CompoundBorder(
267: new javax.swing.border.TitledBorder(
268: getString("LAB_Modifiers")), // NOI18N
269: new javax.swing.border.EmptyBorder(new java.awt.Insets(
270: 3, 3, 3, 3))));
271:
272: commpactP = new JPanel();
273: commpactP.setLayout(new java.awt.BorderLayout());
274: commpactP.setBorder(new javax.swing.border.EmptyBorder(
275: new java.awt.Insets(6, 7, 6, 7)));
276: commpactP.add(modifPanel, java.awt.BorderLayout.CENTER);
277: commpactP.add(jPanel2, java.awt.BorderLayout.NORTH);
278: commpactP.getAccessibleContext().setAccessibleName(
279: "ACSN_ModifierPanel"); // NOI18N
280: commpactP.getAccessibleContext().setAccessibleDescription(
281: getString("ACSD_ModifierPanel")); // NOI18N
282: }
283:
284: private JComboBox accessCombo;
285: private JLabel jLabel1;
286: private JPanel jPanel2;
287: private JPanel modifPanel;
288: private JPanel commpactP;
289: private boolean isCompact = false;
290: private boolean isPartial = false;
291:
292: public JComboBox getAccessComponent() {
293: if (isCompact)
294: throw new IllegalStateException(
295: "cannot use both getAccessComponent/getCompactComponent"); // NOI18N
296: isPartial = true;
297: return accessCombo;
298: }
299:
300: public JComponent getModifiersComponent() {
301: if (isCompact)
302: throw new IllegalStateException(
303: "cannot use both getModifiersComponent/getCompactComponent"); // NOI18N
304: isPartial = true;
305: return modifPanel;
306: }
307:
308: public JPanel getCompactComponent() {
309: if (isPartial)
310: throw new IllegalStateException(
311: "cannot use getAccessComponent/getModifiersComponent/getCompactComponent together"); // NOI18N
312: isCompact = true;
313: if (commpactP == null) {
314: initComponents();
315: }
316: return commpactP;
317: }
318:
319: /** Update access ComboBox values depending on new 'mask' property
320: */
321: private void updateAccess() {
322: int selValue = myEditor.getModifier() & ACCESS_MASK;
323: int selIndex = -1;
324:
325: int counter = 1;
326: for (int i = 1; i < ACCESS_VALUES.length; i++) {
327: if ((ACCESS_VALUES[i] & myEditor.getMask()) != 0)
328: counter++;
329: }
330: currentAccessValues = new int[counter];
331: currentAccessNames = new String[counter];
332:
333: currentAccessValues[0] = ACCESS_VALUES[0];
334: currentAccessNames[0] = ACCESS_NAMES[0];
335: counter = 1;
336:
337: for (int i = 1; i < ACCESS_VALUES.length; i++) {
338: if ((ACCESS_VALUES[i] & myEditor.getMask()) != 0) {
339: currentAccessValues[counter] = ACCESS_VALUES[i];
340: currentAccessNames[counter] = ACCESS_NAMES[i];
341: if (ACCESS_VALUES[i] == selValue) {
342: selIndex = counter;
343: }
344: counter++;
345: }
346: }
347: if (selIndex == -1 && selValue == 0)
348: selIndex = 0;
349:
350: ignored = true;
351: accessCombo.setModel(new DefaultComboBoxModel(
352: currentAccessNames));
353: accessCombo.setSelectedIndex(selIndex);
354: ignored = false;
355: }
356:
357: /** Update enable status of all modifiers check boxes
358: */
359: private void updateModifiers() {
360: for (int i = 0; i < MODIFIER_COUNT; i++) {
361: checks[i]
362: .setEnabled((myEditor.getMask() & MODIFIER_VALUES[i]) != 0);
363: }
364: }
365:
366: /** Update the components inside the ModifierPanel depending on new value
367: * of 'modifier' property.
368: */
369: private void updateComponents() {
370: updateAccessCombo();
371: updateModifiers();
372: for (int i = 0; i < MODIFIER_COUNT; i++) {
373: checks[i]
374: .setSelected((myEditor.getModifier() & MODIFIER_VALUES[i]) != 0);
375: }
376: }
377:
378: private void updateAccessCombo() {
379: int selIndex = -1;
380: if (myEditor.getModifier() == 0) {
381: selIndex = 0;
382: } else {
383: for (int i = 1; i < currentAccessValues.length; i++) {
384: if ((currentAccessValues[i] & myEditor.getModifier()) != 0) {
385: if (selIndex != -1) {
386: selIndex = -1;
387: break;
388: }
389: selIndex = i;
390: }
391: }
392: }
393: if (accessCombo.getSelectedIndex() != selIndex) {
394: accessCombo.setSelectedIndex(selIndex);
395: }
396: }
397:
398: /** Updates the value depending on the status of the components. */
399: private void updateValue() {
400: int newValue = 0;
401: int comboIndex = accessCombo.getSelectedIndex();
402: Object type = myEditor.getType();
403: int mask = 0;
404: if (ModifierEditor.FULL_CUSTOM_EDITOR == type
405: || ModifierEditor.ACCESS_MODIFIERS_CUSTOM_EDITOR == type) {
406: mask |= ACCESS_MASK;
407: if (comboIndex == -1) {
408: newValue = myEditor.getModifier() & ACCESS_MASK;
409: } else {
410: newValue |= currentAccessValues[comboIndex];
411: }
412: }
413: if (ModifierEditor.FULL_CUSTOM_EDITOR == type
414: || ModifierEditor.OTHERS_MODIFIERS_CUSTOM_EDITOR == type) {
415: mask |= OTHERS_MASK;
416: for (int i = 0; i < MODIFIER_COUNT; i++) {
417: if (checks[i].isSelected() & checks[i].isEnabled())
418: newValue |= MODIFIER_VALUES[i];
419: }
420: }
421:
422: int oldValue = myEditor.getModifier();
423: if ((oldValue & mask) != newValue) {
424: if (ModifierEditor.ACCESS_MODIFIERS_CUSTOM_EDITOR == type) {
425: newValue |= (oldValue & ~ACCESS_MASK);
426: } else if (ModifierEditor.OTHERS_MODIFIERS_CUSTOM_EDITOR == type) {
427: newValue |= (oldValue & ~OTHERS_MASK);
428: }
429: myEditor.setModifier(newValue);
430: }
431: }
432:
433: private static String getString(String key) {
434: return NbBundle.getMessage(ModifierPanel.class, key);
435: }
436:
437: static String getModifierDescription(int i) {
438: return getString(MODIFIER_DESCRIPTION_KEYS[i]);
439: }
440:
441: }
|