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.beaninfo.editors;
043:
044: import java.awt.*;
045: import java.awt.event.*;
046: import java.beans.*;
047:
048: import javax.swing.*;
049: import javax.swing.border.*;
050: import javax.swing.event.*;
051: import org.openide.DialogDisplayer;
052:
053: import org.openide.NotifyDescriptor;
054: import org.openide.awt.Mnemonics;
055: import org.openide.explorer.propertysheet.editors.XMLPropertyEditor;
056: import org.openide.util.Exceptions;
057: import org.openide.util.NbBundle;
058: import org.openide.util.Utilities;
059:
060: /**
061: * A property editor for Font class.
062: *
063: * @author Ian Formanek
064: */
065: public class FontEditor implements PropertyEditor, XMLPropertyEditor {
066:
067: // static .....................................................................................
068:
069: static final Integer[] sizes = new Integer[] { Integer.valueOf(3),
070: Integer.valueOf(5), Integer.valueOf(8),
071: Integer.valueOf(10), Integer.valueOf(12),
072: Integer.valueOf(14), Integer.valueOf(18),
073: Integer.valueOf(24), Integer.valueOf(36),
074: Integer.valueOf(48) };
075:
076: static final String[] styles = new String[] {
077: NbBundle.getMessage(FontEditor.class, "CTL_Plain"),
078: NbBundle.getMessage(FontEditor.class, "CTL_Bold"),
079: NbBundle.getMessage(FontEditor.class, "CTL_Italic"),
080: NbBundle.getMessage(FontEditor.class, "CTL_BoldItalic") };
081:
082: // variables ..................................................................................
083:
084: private Font font;
085: private String fontName;
086: private PropertyChangeSupport support;
087:
088: // init .......................................................................................
089:
090: public FontEditor() {
091: support = new PropertyChangeSupport(this );
092: }
093:
094: // main methods .......................................................................................
095:
096: public Object getValue() {
097: return font;
098: }
099:
100: public void setValue(Object object) {
101: if (font != null && font.equals(object)) {
102: return;
103: } else if (font == null && object == null) {
104: return;
105: }
106:
107: if (object instanceof Font) {
108: font = (Font) object;
109: } else if (object == null) {
110: font = null;
111: } else {
112: assert false : "Object " + object
113: + " is instanceof Font or null";
114: }
115:
116: if (font != null) {
117: fontName = font.getName() + " " + font.getSize() + " "
118: + getStyleName(font.getStyle()); // NOI18N
119: } else {
120: fontName = null;
121: }
122:
123: support.firePropertyChange("", null, null); // NOI18N
124: }
125:
126: public String getAsText() {
127: return fontName;
128: }
129:
130: public void setAsText(String string) {
131: return;
132: }
133:
134: public String getJavaInitializationString() {
135: return "new java.awt.Font(\"" + font.getName() + "\", "
136: + font.getStyle() + // NOI18N
137: ", " + font.getSize() + ")"; // NOI18N
138: }
139:
140: public String[] getTags() {
141: return null;
142: }
143:
144: public boolean isPaintable() {
145: return true;
146: }
147:
148: public void paintValue(Graphics g, Rectangle rectangle) {
149: Font originalFont = g.getFont();
150:
151: // Fix of 21713, set default value
152: if (font == null)
153: setValue(null);
154:
155: Font paintFont = font == null ? originalFont : font; // NOI18N
156: assert paintFont != null : "paintFont must exist.";
157:
158: FontMetrics fm = g.getFontMetrics(paintFont);
159: if (fm.getHeight() > rectangle.height) {
160: if (Utilities.isMac()) {
161: // don't use deriveFont() - see #49973 for details
162: paintFont = new Font(paintFont.getName(), paintFont
163: .getStyle(), 12);
164: } else {
165: paintFont = paintFont.deriveFont(12f);
166: }
167: fm = g.getFontMetrics(paintFont);
168: }
169: g.setFont(paintFont);
170: g.drawString(fontName == null ? "null" : fontName, // NOI18N
171: rectangle.x, rectangle.y
172: + (rectangle.height - fm.getHeight()) / 2
173: + fm.getAscent());
174: g.setFont(originalFont);
175: }
176:
177: public boolean supportsCustomEditor() {
178: return true;
179: }
180:
181: public Component getCustomEditor() {
182: return new FontPanel();
183: }
184:
185: public void addPropertyChangeListener(
186: PropertyChangeListener propertyChangeListener) {
187: support.addPropertyChangeListener(propertyChangeListener);
188: }
189:
190: public void removePropertyChangeListener(
191: PropertyChangeListener propertyChangeListener) {
192: support.removePropertyChangeListener(propertyChangeListener);
193: }
194:
195: // helper methods .......................................................................................
196:
197: String getStyleName(int i) {
198: if ((i & Font.BOLD) > 0)
199: if ((i & Font.ITALIC) > 0)
200: return NbBundle.getMessage(FontEditor.class,
201: "CTL_BoldItalic");
202: else
203: return NbBundle
204: .getMessage(FontEditor.class, "CTL_Bold");
205: else if ((i & Font.ITALIC) > 0)
206: return NbBundle.getMessage(FontEditor.class, "CTL_Italic");
207: else
208: return NbBundle.getMessage(FontEditor.class, "CTL_Plain");
209: }
210:
211: static private String[] fonts;
212:
213: static private String[] getFonts() {
214: if (fonts == null) {
215: try {
216: fonts = GraphicsEnvironment
217: .getLocalGraphicsEnvironment()
218: .getAvailableFontFamilyNames();
219: } catch (RuntimeException e) {
220: fonts = new String[0]; //NOI18N
221: if (org.openide.util.Utilities.isMac()) {
222: String msg = NbBundle.getMessage(FontEditor.class,
223: "MSG_AppleBug"); //NOI18N
224: DialogDisplayer.getDefault().notify(
225: new NotifyDescriptor.Message(msg));
226: } else {
227: throw e;
228: }
229: }
230: }
231: return fonts;
232: }
233:
234: // innerclasses ............................................................................................
235:
236: class FontPanel extends JPanel {
237:
238: JTextField tfFont, tfStyle, tfSize;
239: JList lFont, lStyle, lSize;
240:
241: static final long serialVersionUID = 8377025140456676594L;
242:
243: FontPanel() {
244: setLayout(new BorderLayout());
245: setBorder(new EmptyBorder(12, 12, 0, 11));
246:
247: Font font = (Font) getValue();
248: if (font == null) {
249: if (getFonts().length > 0) {
250: font = new Font(fonts[0], Font.PLAIN, 10);
251: } else {
252: font = UIManager.getFont("Label.font"); // NOI18N
253: }
254: }
255:
256: lFont = new JList(getFonts());
257: lFont.getAccessibleContext().setAccessibleDescription(
258: NbBundle.getMessage(FontEditor.class,
259: "ACSD_CTL_Font"));
260: lStyle = new JList(styles);
261: lStyle.getAccessibleContext().setAccessibleDescription(
262: NbBundle.getMessage(FontEditor.class,
263: "ACSD_CTL_FontStyle"));
264: lSize = new JList(sizes);
265: lSize.getAccessibleContext().setAccessibleDescription(
266: NbBundle.getMessage(FontEditor.class,
267: "ACSD_CTL_Size"));
268: tfSize = new JTextField(String.valueOf(font.getSize()));
269: tfSize.getAccessibleContext().setAccessibleDescription(
270: lSize.getAccessibleContext()
271: .getAccessibleDescription());
272: getAccessibleContext().setAccessibleDescription(
273: NbBundle.getMessage(FontEditor.class,
274: "ACSD_FontCustomEditor"));
275:
276: GridBagLayout la = new GridBagLayout();
277: GridBagConstraints c = new GridBagConstraints();
278: setLayout(la);
279:
280: c.gridwidth = 1;
281: c.weightx = 1.0;
282: c.insets = new Insets(0, 0, 0, 0);
283: c.anchor = GridBagConstraints.WEST;
284: JLabel l = new JLabel();
285: Mnemonics.setLocalizedText(l, NbBundle.getMessage(
286: FontEditor.class, "CTL_Font")); //NoI18N
287: l.setLabelFor(lFont);
288: la.setConstraints(l, c);
289: add(l);
290:
291: c.insets = new Insets(0, 5, 0, 0);
292: l = new JLabel(); //NoI18N
293: Mnemonics.setLocalizedText(l, NbBundle.getMessage(
294: FontEditor.class, "CTL_FontStyle")); //NoI18N
295: l.setLabelFor(lStyle);
296: la.setConstraints(l, c);
297: add(l);
298:
299: c.insets = new Insets(0, 5, 0, 0);
300: c.gridwidth = GridBagConstraints.REMAINDER;
301: l = new JLabel();
302: Mnemonics.setLocalizedText(l, NbBundle.getMessage(
303: FontEditor.class, "CTL_Size")); //NoI18N
304: l.setLabelFor(tfSize);
305: la.setConstraints(l, c);
306: add(l);
307:
308: c.insets = new Insets(5, 0, 0, 0);
309: c.gridwidth = 1;
310: c.fill = GridBagConstraints.HORIZONTAL;
311: tfFont = new JTextField(font.getName());
312: tfFont.setEnabled(false);
313: la.setConstraints(tfFont, c);
314: add(tfFont);
315:
316: c.insets = new Insets(5, 5, 0, 0);
317: tfStyle = new JTextField(getStyleName(font.getStyle()));
318: tfStyle.setEnabled(false);
319: la.setConstraints(tfStyle, c);
320: add(tfStyle);
321:
322: c.insets = new Insets(5, 5, 0, 0);
323: c.gridwidth = GridBagConstraints.REMAINDER;
324:
325: tfSize.addKeyListener(new KeyAdapter() {
326: public void keyPressed(KeyEvent e) {
327: if (e.getKeyCode() == KeyEvent.VK_ENTER)
328: setValue();
329: }
330: });
331:
332: tfSize.addFocusListener(new FocusAdapter() {
333: public void focusLost(FocusEvent evt) {
334: setValue();
335: }
336: });
337: la.setConstraints(tfSize, c);
338: add(tfSize);
339:
340: c.gridwidth = 1;
341: c.insets = new Insets(5, 0, 0, 0);
342: c.fill = GridBagConstraints.BOTH;
343: c.weightx = 1.0;
344: c.weighty = 1.0;
345: lFont.setVisibleRowCount(5);
346: lFont.setSelectedValue(font.getName(), true);
347: lFont.addListSelectionListener(new ListSelectionListener() {
348: public void valueChanged(ListSelectionEvent e) {
349: if (!lFont.isSelectionEmpty()) {
350: if (getFonts().length > 0) { //Mac bug workaround
351: int i = lFont.getSelectedIndex();
352: tfFont.setText(getFonts()[i]);
353: setValue();
354: }
355: }
356: }
357: });
358: JScrollPane sp = new JScrollPane(lFont);
359: sp
360: .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
361: la.setConstraints(sp, c);
362: add(sp);
363:
364: lStyle.setVisibleRowCount(5);
365: lStyle
366: .setSelectedValue(getStyleName(font.getStyle()),
367: true);
368: lStyle
369: .addListSelectionListener(new ListSelectionListener() {
370: public void valueChanged(ListSelectionEvent e) {
371: if (!lStyle.isSelectionEmpty()) {
372: int i = lStyle.getSelectedIndex();
373: tfStyle.setText(styles[i]);
374: setValue();
375: }
376: }
377: });
378: sp = new JScrollPane(lStyle);
379: sp
380: .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
381: c.insets = new Insets(5, 5, 0, 0);
382: la.setConstraints(sp, c);
383: add(sp);
384:
385: c.gridwidth = GridBagConstraints.REMAINDER;
386: lSize.getAccessibleContext().setAccessibleName(
387: tfSize.getAccessibleContext().getAccessibleName());
388: lSize.setVisibleRowCount(5);
389: updateSizeList(font.getSize());
390: lSize.addListSelectionListener(new ListSelectionListener() {
391: public void valueChanged(ListSelectionEvent e) {
392: if (!lSize.isSelectionEmpty()) {
393: int i = lSize.getSelectedIndex();
394: tfSize.setText(String.valueOf(sizes[i]));
395: setValue();
396: }
397: }
398: });
399: sp = new JScrollPane(lSize);
400: sp
401: .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
402: c.insets = new Insets(5, 5, 0, 0);
403: la.setConstraints(sp, c);
404: add(sp);
405:
406: c.gridwidth = GridBagConstraints.REMAINDER;
407: c.weighty = 2.0;
408: JPanel p = new JPanel(new BorderLayout());
409: p.setBorder(new TitledBorder(" "
410: + NbBundle.getMessage(FontEditor.class,
411: "CTL_Preview") + " "));
412:
413: JPanel pp = new JPanel() {
414: public Dimension getPreferredSize() {
415: return new Dimension(150, 60);
416: }
417:
418: public void paint(Graphics g) {
419: // super.paint (g);
420: FontEditor.this .paintValue(g, new Rectangle(0, 0,
421: this .getSize().width - 1,
422: this .getSize().height - 1));
423: }
424: };
425: p.add("Center", pp); // NOI18N
426: c.insets = new Insets(12, 0, 0, 0);
427: la.setConstraints(p, c);
428: add(p);
429: }
430:
431: public Dimension getPreferredSize() {
432: return new Dimension(400, 250);
433: }
434:
435: private void updateSizeList(int size) {
436: if (java.util.Arrays.asList(sizes).contains(
437: Integer.valueOf(size)))
438: lSize.setSelectedValue(Integer.valueOf(size), true);
439: else
440: lSize.clearSelection();
441: }
442:
443: void setValue() {
444: int size = 12;
445: try {
446: size = Integer.parseInt(tfSize.getText());
447: updateSizeList(size);
448: } catch (NumberFormatException e) {
449: return;
450: }
451: int i = lStyle.getSelectedIndex(), ii = Font.PLAIN;
452: switch (i) {
453: case 0:
454: ii = Font.PLAIN;
455: break;
456: case 1:
457: ii = Font.BOLD;
458: break;
459: case 2:
460: ii = Font.ITALIC;
461: break;
462: case 3:
463: ii = Font.BOLD | Font.ITALIC;
464: break;
465: }
466: FontEditor.this .setValue(new Font(tfFont.getText(), ii,
467: size));
468: invalidate();
469: java.awt.Component p = getParent();
470: if (p != null) {
471: p.validate();
472: }
473: repaint();
474: }
475: }
476:
477: //--------------------------------------------------------------------------
478: // XMLPropertyEditor implementation
479:
480: public static final String XML_FONT = "Font"; // NOI18N
481:
482: public static final String ATTR_NAME = "name"; // NOI18N
483: public static final String ATTR_STYLE = "style"; // NOI18N
484: public static final String ATTR_SIZE = "size"; // NOI18N
485:
486: /** Called to load property value from specified XML subtree. If succesfully loaded,
487: * the value should be available via the getValue method.
488: * An IOException should be thrown when the value cannot be restored from the specified XML element
489: * @param element the XML DOM element representing a subtree of XML from which the value should be loaded
490: * @exception IOException thrown when the value cannot be restored from the specified XML element
491: */
492: public void readFromXML(org.w3c.dom.Node element)
493: throws java.io.IOException {
494: if (!XML_FONT.equals(element.getNodeName())) {
495: throw new java.io.IOException();
496: }
497: org.w3c.dom.NamedNodeMap attributes = element.getAttributes();
498: try {
499: String name = attributes.getNamedItem(ATTR_NAME)
500: .getNodeValue();
501: String style = attributes.getNamedItem(ATTR_STYLE)
502: .getNodeValue(); // [PENDING - style names]
503: String size = attributes.getNamedItem(ATTR_SIZE)
504: .getNodeValue();
505: setValue(new Font(name, Integer.parseInt(style), Integer
506: .parseInt(size)));
507: } catch (NullPointerException e) {
508: throw new java.io.IOException();
509: }
510: }
511:
512: /** Called to store current property value into XML subtree. The property value should be set using the
513: * setValue method prior to calling this method.
514: * @param doc The XML document to store the XML in - should be used for creating nodes only
515: * @return the XML DOM element representing a subtree of XML from which the value should be loaded
516: */
517: public org.w3c.dom.Node storeToXML(org.w3c.dom.Document doc) {
518: if (font == null) {
519: IllegalArgumentException iae = new IllegalArgumentException();
520: Exceptions.attachLocalizedMessage(iae, NbBundle.getMessage(
521: FontEditor.class, "MSG_FontIsNotInitialized")); // NOI18N
522: Exceptions.printStackTrace(iae);
523: return null;
524: }
525:
526: org.w3c.dom.Element el = doc.createElement(XML_FONT);
527: el.setAttribute(ATTR_NAME, font.getName());
528: el.setAttribute(ATTR_STYLE, Integer.toString(font.getStyle()));
529: el.setAttribute(ATTR_SIZE, Integer.toString(font.getSize()));
530: return el;
531: }
532:
533: }
|