001: /*
002: * @(#)BasicJideOptionPaneUI.java 3/27/2006
003: *
004: * Copyright 2002 - 2006 JIDE Software Inc. All rights reserved.
005: */
006:
007: package com.jidesoft.plaf.basic;
008:
009: import com.jidesoft.dialog.ButtonNames;
010: import com.jidesoft.dialog.ButtonPanel;
011: import com.jidesoft.dialog.ButtonResources;
012: import com.jidesoft.dialog.JideOptionPane;
013: import com.jidesoft.plaf.UIDefaultsLookup;
014: import com.jidesoft.swing.JideBoxLayout;
015: import com.jidesoft.swing.NullPanel;
016: import com.jidesoft.swing.PaintPanel;
017:
018: import javax.swing.*;
019: import javax.swing.border.Border;
020: import javax.swing.event.AncestorEvent;
021: import javax.swing.event.AncestorListener;
022: import javax.swing.plaf.ComponentUI;
023: import javax.swing.plaf.basic.BasicOptionPaneUI;
024: import java.awt.*;
025: import java.awt.event.ActionEvent;
026: import java.awt.event.ActionListener;
027: import java.beans.PropertyChangeEvent;
028: import java.beans.PropertyChangeListener;
029: import java.util.ArrayList;
030: import java.util.Arrays;
031: import java.util.Locale;
032: import java.util.ResourceBundle;
033:
034: public class BasicJideOptionPaneUI extends BasicOptionPaneUI {
035: private Container _detailsArea;
036: private Container _buttonArea;
037: private Container _bannerArea;
038: private Component _titleComponent;
039:
040: private ThemePainter _painter;
041:
042: // keep track of detail component width.
043: private int _detailsPreferredWidth = -1;
044:
045: /**
046: * Creates a new BasicOptionPaneUI instance.
047: */
048: public static ComponentUI createUI(JComponent x) {
049: return new BasicJideOptionPaneUI();
050: }
051:
052: @Override
053: protected LayoutManager createLayoutManager() {
054: return new JideBoxLayout(optionPane, JideBoxLayout.Y_AXIS);
055: }
056:
057: // use a static to keep track of detail area visibility during the session
058: private static boolean _detailsVisible = false;
059:
060: /**
061: * Is details area visible initially.
062: *
063: * @return true if details area is visible.
064: */
065: public static boolean isDetailsVisible() {
066: return _detailsVisible;
067: }
068:
069: /**
070: * Sets if details area is visible initially.
071: *
072: * @param detailsVisible
073: */
074: public static void setDetailsVisible(boolean detailsVisible) {
075: _detailsVisible = detailsVisible;
076: }
077:
078: @Override
079: protected void installComponents() {
080: if (UIDefaultsLookup.get("OptionPane.showBanner") == null
081: || UIDefaultsLookup.getBoolean("OptionPane.showBanner")) {
082: optionPane.add(_bannerArea = createBannerArea(),
083: JideBoxLayout.FIX);
084: }
085:
086: Container messageArea = createMessageArea();
087: LookAndFeel.installBorder((JComponent) messageArea,
088: "OptionPane.border");
089: optionPane.add(messageArea);
090:
091: Container separator = createSeparator();
092: if (separator != null) {
093: optionPane.add(separator);
094: }
095:
096: optionPane.add(_buttonArea = createButtonArea(),
097: JideBoxLayout.FIX);
098: optionPane.applyComponentOrientation(optionPane
099: .getComponentOrientation());
100:
101: if (shouldDetailsButtonVisible()) {
102: updateDetailsComponent();
103: }
104:
105: optionPane
106: .addPropertyChangeListener(new PropertyChangeListener() {
107: public void propertyChange(PropertyChangeEvent evt) {
108: if (JideOptionPane.DETAILS_PROPERTY.equals(evt
109: .getPropertyName())) {
110: updateDetailsComponent();
111: if (_buttonArea instanceof ButtonPanel) {
112: Component detailsButton = ((ButtonPanel) _buttonArea)
113: .getButtonByName(ButtonNames.DETAILS);
114: if (detailsButton != null) {
115: detailsButton.setVisible(evt
116: .getNewValue() != null);
117: }
118: }
119: } else if (JideOptionPane.TITLE_PROPERTY
120: .equals(evt.getPropertyName())) {
121: updateTitleComponent(_bannerArea);
122: }
123: }
124: });
125: }
126:
127: protected void updateDetailsComponent() {
128: if (_detailsArea != null) {
129: optionPane.remove(_detailsArea);
130: _detailsArea = null;
131: }
132: _detailsArea = createDetailsComponent();
133: optionPane.add(_detailsArea, JideBoxLayout.VARY);
134: _detailsArea.setVisible(isDetailsVisible());
135: }
136:
137: @Override
138: protected Container createMessageArea() {
139: JPanel top = new JPanel();
140: Border topBorder = (Border) UIDefaultsLookup
141: .get("OptionPane.messageAreaBorder");
142: if (topBorder != null) {
143: top.setBorder(topBorder);
144: }
145: top.setLayout(new BorderLayout());
146:
147: /* Fill the body. */
148: Container body = new JPanel(new GridBagLayout());
149: Container realBody = new JPanel(new BorderLayout());
150:
151: body.setName("OptionPane.body");
152: realBody.setName("OptionPane.realBody");
153:
154: if (getIcon() != null) {
155: JPanel sep = new JPanel();
156: sep.setName("OptionPane.separator");
157: sep.setPreferredSize(new Dimension(15, 1));
158: realBody.add(sep, BorderLayout.BEFORE_LINE_BEGINS);
159: }
160: realBody.add(body, BorderLayout.CENTER);
161:
162: GridBagConstraints cons = new GridBagConstraints();
163: cons.gridx = cons.gridy = 0;
164: cons.gridwidth = GridBagConstraints.REMAINDER;
165: cons.gridheight = 1;
166: int anchor = UIDefaultsLookup
167: .getInt("OptionPane.messageAnchor");
168: cons.anchor = anchor == 0 ? GridBagConstraints.CENTER : anchor;
169: cons.insets = new Insets(0, 0, 3, 0);
170:
171: Object message = getMessage();
172: // if (message instanceof String
173: // && !((String) message).toLowerCase().startsWith("<html>")) {
174: // addMessageComponents(body, cons, null, getMaxCharactersPerLineCount(), false);
175: // }
176: // else {
177: addMessageComponents(body, cons, message,
178: getMaxCharactersPerLineCount(), false);
179: // }
180: top.add(realBody, BorderLayout.CENTER);
181:
182: return top;
183: }
184:
185: @Override
186: protected Container createSeparator() {
187: return new JSeparator();
188: }
189:
190: @Override
191: protected void installDefaults() {
192: super .installDefaults();
193: optionPane.setBorder(BorderFactory.createEmptyBorder());
194: _painter = (ThemePainter) UIDefaultsLookup.get("Theme.painter");
195: }
196:
197: @Override
198: protected void uninstallDefaults() {
199: super .uninstallDefaults();
200: _painter = null;
201: }
202:
203: protected Container createDetailsComponent() {
204: if (!(optionPane instanceof JideOptionPane)) {
205: return null;
206: }
207: JideOptionPane jideOptionPane = (JideOptionPane) optionPane;
208: Object details = jideOptionPane.getDetails();
209: if (details instanceof Container) {
210: _detailsPreferredWidth = ((Container) details)
211: .getPreferredSize().width;
212: return (Container) details;
213: } else if (details instanceof Component) {
214: JPanel panel = new JPanel(new BorderLayout());
215: panel.add((Component) details);
216: _detailsPreferredWidth = panel.getPreferredSize().width;
217: return panel;
218: } else if (details instanceof String) {
219: JTextArea area = new JTextArea((String) details);
220: area.setEditable(false);
221: area.setRows(20);
222: area.setColumns(60);
223: JPanel panel = new JPanel(new BorderLayout());
224: panel.add(new JScrollPane(area));
225: panel.setBorder(BorderFactory.createEmptyBorder(10, 6, 10,
226: 6));
227: _detailsPreferredWidth = panel.getPreferredSize().width;
228: return panel;
229: } else {
230: return null;
231: }
232: }
233:
234: @Override
235: protected Container createButtonArea() {
236: int orientation = UIDefaultsLookup
237: .getInt("OptionPane.buttonOrientation");
238: orientation = orientation == 0 ? SwingConstants.CENTER
239: : orientation;
240: ButtonPanel buttonPanel = new ButtonPanel(orientation);
241: Border border = (Border) UIDefaultsLookup
242: .get("OptionPane.buttonAreaBorder");
243: buttonPanel.setName("OptionPane.buttonArea");
244: if (border != null) {
245: buttonPanel.setBorder(border);
246: }
247: boolean sameSize = UIDefaultsLookup
248: .getBoolean("OptionPane.sameSizeButtons");
249: buttonPanel.setSizeContraint(sameSize ? ButtonPanel.SAME_SIZE
250: : ButtonPanel.NO_LESS_THAN);
251: int padding = UIDefaultsLookup
252: .getInt("OptionPane.buttonPadding");
253: padding = padding == 0 ? 6 : padding;
254: buttonPanel.setButtonGap(padding);
255: addButtonComponents(buttonPanel, getButtons(),
256: getInitialValueIndex());
257: return buttonPanel;
258: }
259:
260: @Override
261: protected void addButtonComponents(Container container,
262: Object[] buttons, int initialIndex) {
263: if (buttons != null && buttons.length > 0) {
264: int numButtons = buttons.length;
265: for (int counter = 0; counter < numButtons; counter++) {
266: Object button = buttons[counter];
267: Component newComponent;
268:
269: if (button instanceof Component) {
270: newComponent = (Component) button;
271: container.add(newComponent,
272: ButtonPanel.OTHER_BUTTON);
273: hasCustomComponents = true;
274: } else {
275: JButton aButton;
276:
277: if (button instanceof ButtonFactory) {
278: aButton = ((ButtonFactory) button)
279: .createButton();
280: } else if (button instanceof Icon)
281: aButton = new JButton((Icon) button);
282: else
283: aButton = new JButton(button.toString());
284:
285: aButton
286: .setMultiClickThreshhold(UIDefaultsLookup
287: .getInt("OptionPane.buttonClickThreshhold"));
288: configureButton(aButton);
289:
290: if (ButtonNames.YES.equals(aButton.getName())
291: || ButtonNames.OK.equals(aButton.getName())
292: || ButtonNames.CLOSE.equals(aButton
293: .getName())
294: || ButtonNames.FINISH.equals(aButton
295: .getName())) {
296: container.add(aButton,
297: ButtonPanel.AFFIRMATIVE_BUTTON);
298: } else if (ButtonNames.NO.equals(aButton.getName())
299: || ButtonNames.CANCEL.equals(aButton
300: .getName())) {
301: container.add(aButton,
302: ButtonPanel.CANCEL_BUTTON);
303: } else if (ButtonNames.HELP.equals(aButton
304: .getName())) {
305: container.add(aButton, ButtonPanel.HELP_BUTTON);
306: } else {
307: container
308: .add(aButton, ButtonPanel.OTHER_BUTTON);
309: }
310:
311: if (ButtonNames.DETAILS.equals(aButton.getName())) {
312: aButton.addActionListener(new AbstractAction() {
313: public void actionPerformed(ActionEvent e) {
314: JButton defaultButton = (JButton) e
315: .getSource();
316: Container top = defaultButton
317: .getTopLevelAncestor();
318: final ResourceBundle resourceBundle = ButtonResources
319: .getResourceBundle(Locale
320: .getDefault());
321: if (_detailsArea.isVisible()) {
322: setDetailsVisible(false);
323: _detailsArea.setVisible(false);
324: defaultButton
325: .setText(resourceBundle
326: .getString("Button.showDetails"));
327: defaultButton
328: .setMnemonic(resourceBundle
329: .getString(
330: "Button.showDetails.mnemonic")
331: .charAt(0));
332: } else {
333: setDetailsVisible(true);
334: _detailsArea.setVisible(true);
335: defaultButton
336: .setText(resourceBundle
337: .getString("Button.hideDetails"));
338: defaultButton
339: .setMnemonic(resourceBundle
340: .getString(
341: "Button.hideDetails.mnemonic")
342: .charAt(0));
343: }
344: if (top instanceof Window) {
345: ((Window) top).pack();
346: }
347: }
348: });
349: aButton
350: .setVisible(shouldDetailsButtonVisible());
351: } else {
352: ActionListener buttonListener = createButtonActionListener(counter);
353: if (buttonListener != null) {
354: aButton.addActionListener(buttonListener);
355: }
356: }
357: newComponent = aButton;
358: }
359:
360: if (counter == initialIndex) {
361: initialFocusComponent = newComponent;
362: if (initialFocusComponent instanceof JButton) {
363: JButton defaultB = (JButton) initialFocusComponent;
364: defaultB
365: .addAncestorListener(new AncestorListener() {
366: public void ancestorAdded(
367: AncestorEvent e) {
368: JButton defaultButton = (JButton) e
369: .getComponent();
370: JRootPane root = SwingUtilities
371: .getRootPane(defaultButton);
372: if (root != null) {
373: root
374: .setDefaultButton(defaultButton);
375: }
376: }
377:
378: public void ancestorRemoved(
379: AncestorEvent event) {
380: }
381:
382: public void ancestorMoved(
383: AncestorEvent event) {
384: }
385: });
386: }
387: }
388: }
389: }
390: }
391:
392: /**
393: * Returns the buttons to display from the JOptionPane the receiver is
394: * providing the look and feel for. If the JOptionPane has options
395: * set, they will be provided, otherwise if the optionType is
396: * YES_NO_OPTION, yesNoOptions is returned, if the type is
397: * YES_NO_CANCEL_OPTION yesNoCancelOptions is returned, otherwise
398: * defaultButtons are returned.
399: */
400: @Override
401: protected Object[] getButtons() {
402: if (optionPane != null) {
403: Object[] suppliedOptions = optionPane.getOptions();
404:
405: if (suppliedOptions == null) {
406: Object[] defaultOptions;
407: int type = optionPane.getOptionType();
408: Locale l = optionPane.getLocale();
409: if (type == JOptionPane.YES_NO_OPTION) {
410: defaultOptions = new ButtonFactory[2];
411: defaultOptions[0] = new ButtonFactory(
412: ButtonNames.YES, UIDefaultsLookup
413: .getString(
414: "OptionPane.yesButtonText",
415: l), getMnemonic(
416: "OptionPane.yesButtonMnemonic", l),
417: (Icon) UIDefaultsLookup
418: .get("OptionPane.yesIcon"));
419: defaultOptions[1] = new ButtonFactory(
420: ButtonNames.NO, UIDefaultsLookup.getString(
421: "OptionPane.noButtonText", l),
422: getMnemonic("OptionPane.noButtonMnemonic",
423: l), (Icon) UIDefaultsLookup
424: .get("OptionPane.noIcon"));
425: } else if (type == JOptionPane.YES_NO_CANCEL_OPTION) {
426: defaultOptions = new ButtonFactory[3];
427: defaultOptions[0] = new ButtonFactory(
428: ButtonNames.YES, UIDefaultsLookup
429: .getString(
430: "OptionPane.yesButtonText",
431: l), getMnemonic(
432: "OptionPane.yesButtonMnemonic", l),
433: (Icon) UIDefaultsLookup
434: .get("OptionPane.yesIcon"));
435: defaultOptions[1] = new ButtonFactory(
436: ButtonNames.NO, UIDefaultsLookup.getString(
437: "OptionPane.noButtonText", l),
438: getMnemonic("OptionPane.noButtonMnemonic",
439: l), (Icon) UIDefaultsLookup
440: .get("OptionPane.noIcon"));
441: defaultOptions[2] = new ButtonFactory(
442: ButtonNames.CANCEL,
443: UIDefaultsLookup.getString(
444: "OptionPane.cancelButtonText", l),
445: getMnemonic(
446: "OptionPane.cancelButtonMnemonic",
447: l), (Icon) UIDefaultsLookup
448: .get("OptionPane.cancelIcon"));
449: } else if (type == JOptionPane.OK_CANCEL_OPTION) {
450: defaultOptions = new ButtonFactory[2];
451: defaultOptions[0] = new ButtonFactory(
452: ButtonNames.OK, UIDefaultsLookup.getString(
453: "OptionPane.okButtonText", l),
454: getMnemonic("OptionPane.okButtonMnemonic",
455: l), (Icon) UIDefaultsLookup
456: .get("OptionPane.okIcon"));
457: defaultOptions[1] = new ButtonFactory(
458: ButtonNames.CANCEL,
459: UIDefaultsLookup.getString(
460: "OptionPane.cancelButtonText", l),
461: getMnemonic(
462: "OptionPane.cancelButtonMnemonic",
463: l), (Icon) UIDefaultsLookup
464: .get("OptionPane.cancelIcon"));
465: } else if (type == JideOptionPane.CLOSE_OPTION) {
466: defaultOptions = new ButtonFactory[1];
467: final ResourceBundle resourceBundle = ButtonResources
468: .getResourceBundle(Locale.getDefault());
469: defaultOptions[0] = new ButtonFactory(
470: ButtonNames.CLOSE, resourceBundle
471: .getString("Button.close"),
472: resourceBundle.getString(
473: "Button.close.mnemonic").charAt(0),
474: null);
475: } else {
476: defaultOptions = new ButtonFactory[1];
477: defaultOptions[0] = new ButtonFactory(
478: ButtonNames.OK, UIDefaultsLookup.getString(
479: "OptionPane.okButtonText", l),
480: getMnemonic("OptionPane.okButtonMnemonic",
481: l), (Icon) UIDefaultsLookup
482: .get("OptionPane.okIcon"));
483: }
484:
485: return addDetailsButton(defaultOptions, true);
486:
487: }
488: return addDetailsButton(suppliedOptions, true);
489: }
490: return null;
491: }
492:
493: protected Object[] addDetailsButton(Object[] options,
494: boolean showDetails) {
495: if (showDetails) {
496: Object[] newOptions = new Object[options.length + 1];
497: for (int i = 0; i < options.length; i++) {
498: newOptions[i] = options[i];
499: }
500: final ResourceBundle resourceBundle = ButtonResources
501: .getResourceBundle(Locale.getDefault());
502: newOptions[newOptions.length - 1] = new ButtonFactory(
503: ButtonNames.DETAILS, resourceBundle
504: .getString("Button.showDetails"),
505: resourceBundle.getString(
506: "Button.showDetails.mnemonic").charAt(0),
507: null);
508: return newOptions;
509: } else {
510: return options;
511: }
512:
513: }
514:
515: private boolean shouldDetailsButtonVisible() {
516: return optionPane instanceof JideOptionPane
517: && ((JideOptionPane) optionPane).getDetails() != null;
518: }
519:
520: /**
521: * Configures any necessary colors/fonts for the specified button
522: * used representing the button portion of the optionpane.
523: */
524: protected void configureButton(JButton button) {
525: Font buttonFont = (Font) UIDefaultsLookup
526: .get("OptionPane.buttonFont");
527: if (buttonFont != null) {
528: button.setFont(buttonFont);
529: }
530: }
531:
532: protected int getMnemonic(String key, Locale l) {
533: String value = (String) UIDefaultsLookup.get(key, l);
534:
535: if (value == null) {
536: return 0;
537: }
538: try {
539: return Integer.parseInt(value);
540: } catch (NumberFormatException nfe) {
541: }
542: return 0;
543: }
544:
545: /**
546: * This class is used to create the default buttons. This indirection is
547: * used so that addButtonComponents can tell which Buttons were created
548: * by us vs subclassers or from the JOptionPane itself.
549: */
550: protected static class ButtonFactory {
551: private String name;
552: private String text;
553: private int mnemonic;
554: private Icon icon;
555:
556: ButtonFactory(String name, String text, int mnemonic, Icon icon) {
557: this .name = name;
558: this .text = text;
559: this .mnemonic = mnemonic;
560: this .icon = icon;
561: }
562:
563: JButton createButton() {
564: JButton button = new JButton(text);
565: if (name != null) {
566: button.setName(name);
567: }
568: if (icon != null) {
569: button.setIcon(icon);
570: }
571: if (mnemonic != 0) {
572: button.setMnemonic(mnemonic);
573: }
574: return button;
575: }
576: }
577:
578: @Override
579: protected void addIcon(Container top) {
580: Icon sideIcon = getIcon();
581: if (sideIcon != null) {
582: JLabel iconLabel = new JLabel(sideIcon);
583: iconLabel.setName("OptionPane.iconLabel");
584: top.add(iconLabel, BorderLayout.BEFORE_LINE_BEGINS);
585: }
586: }
587:
588: protected Container createBannerArea() {
589: PaintPanel bannerPanel = new PaintPanel() {
590: @Override
591: public Dimension getPreferredSize() {
592: Dimension preferredSize = super .getPreferredSize();
593: if (preferredSize.width < _detailsPreferredWidth) {
594: preferredSize.width = _detailsPreferredWidth;
595: }
596: return preferredSize;
597: }
598: };
599: customizeBannerArea(bannerPanel);
600: bannerPanel.setLayout(new BorderLayout(10, 10));
601: addIcon(bannerPanel);
602: updateTitleComponent(bannerPanel);
603: bannerPanel.add(new JLabel(UIDefaultsLookup
604: .getIcon("OptionPane.bannerIcon")),
605: BorderLayout.AFTER_LINE_ENDS);
606: return bannerPanel;
607: }
608:
609: protected void customizeBannerArea(PaintPanel bannerPanel) {
610: Paint paint = (Paint) UIDefaultsLookup
611: .get("OptionPane.bannerBackgroundPaint");
612:
613: if (paint != null) {
614: bannerPanel.setBackgroundPaint(paint);
615: } else {
616: Color dk = UIDefaultsLookup
617: .getColor("OptionPane.bannerBackgroundDk");
618: Color lt = UIDefaultsLookup
619: .getColor("OptionPane.bannerBackgroundLt");
620: boolean direction = UIDefaultsLookup
621: .get("OptionPane.bannerBackgroundDirection") == null
622: || UIDefaultsLookup
623: .getBoolean("OptionPane.bannerBackgroundDirection");
624: if (dk == null && lt != null) {
625: dk = lt;
626: bannerPanel.setGradientPaint(dk != null ? dk
627: : getPainter().getOptionPaneBannerLt(),
628: lt != null ? lt : getPainter()
629: .getOptionPaneBannerDk(), direction);
630: } else if (dk != null && lt == null) {
631: lt = dk;
632: bannerPanel.setGradientPaint(dk != null ? dk
633: : getPainter().getOptionPaneBannerLt(),
634: lt != null ? lt : getPainter()
635: .getOptionPaneBannerDk(), direction);
636: } else if (dk != null && lt != null) {
637: bannerPanel.setGradientPaint(dk != null ? dk
638: : getPainter().getOptionPaneBannerLt(),
639: lt != null ? lt : getPainter()
640: .getOptionPaneBannerDk(), direction);
641: }
642: }
643:
644: Border border = UIDefaultsLookup
645: .getBorder("OptionPane.bannerBorder");
646: bannerPanel.setBorder(border != null ? border : BorderFactory
647: .createEmptyBorder(0, 10, 0, 0));
648: }
649:
650: private void updateTitleComponent(Container bannerArea) {
651: if (bannerArea == null) {
652: return;
653: }
654:
655: if (_titleComponent != null) {
656: bannerArea.remove(_titleComponent);
657: _titleComponent = null;
658: }
659:
660: Object title = optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane)
661: .getTitle()
662: : null;
663: if (title instanceof String) {
664: if (((String) title).startsWith("<html>")
665: || ((String) title).startsWith("<HTML>")) {
666: JLabel titleLabel = new JLabel(((String) title));
667: _titleComponent = titleLabel;
668: } else {
669: String[] titles = fitInWidth(
670: (String) title,
671: UIDefaultsLookup
672: .getInt("OptionPane.bannerMaxCharsPerLine"));
673: JPanel titlePanel = new NullPanel();
674: titlePanel.setLayout(new BoxLayout(titlePanel,
675: BoxLayout.Y_AXIS));
676: titlePanel.setOpaque(false);
677: titlePanel.add(Box.createGlue());
678: for (int i = 0; i < titles.length; i++) {
679: String s = titles[i];
680: JLabel label = new JLabel(s);
681: label
682: .setFont(label
683: .getFont()
684: .deriveFont(
685: UIDefaultsLookup
686: .getInt("OptionPane.bannerFontStyle"),
687: UIDefaultsLookup
688: .getInt("OptionPane.bannerFontSize")));
689: Color color = UIDefaultsLookup
690: .getColor("OptionPane.bannerForeground");
691: label.setForeground(color != null ? color
692: : getPainter()
693: .getOptionPaneBannerForeground());
694: titlePanel.add(label);
695: }
696: titlePanel.add(Box.createGlue());
697: _titleComponent = titlePanel;
698: }
699: } else if (title instanceof Component) {
700: _titleComponent = (Component) title;
701: }
702: if (_titleComponent != null) {
703: bannerArea.add(_titleComponent, BorderLayout.CENTER);
704: }
705: }
706:
707: // static methods to split a string into multiple lines.
708:
709: /**
710: * 1. Do not break a word/number. If the character is letter/digit, break at the most recent non- one;
711: * 2. Expand "\n" to a blank line
712: * 3. Expand "\t" to four " "
713: * 4. Trim leading empty spaces
714: *
715: * @param str
716: * @param width
717: * @return An array of Strings with lengh of "width"
718: */
719: private static String[] fitInWidth(String str, int width) {
720: if (str == null)
721: str = "";
722:
723: String BLANK_STR = blankString(width, (byte) 32);
724: str = replaceOccurrences(str, "\n", BLANK_STR);
725: str = replaceOccurrences(str, "\t", " ");
726:
727: ArrayList strArray = new ArrayList();
728: str = str.trim();
729: while (str.length() > width) {
730: int breakPos = width;
731: if (Character.isLetterOrDigit(str.charAt(width))) {
732: breakPos--;
733: char breakChar = str.charAt(breakPos);
734: while (Character.isLetterOrDigit(breakChar)
735: && breakPos > 0) {
736: breakPos--;
737: breakChar = str.charAt(breakPos);
738: }
739: if (breakPos == 0
740: && Character.isLetterOrDigit(breakChar)) {
741: breakPos = width;
742: } else {
743: breakPos++;
744: }
745: }
746: String subStr = str.substring(0, breakPos);
747: if (subStr.length() < width) {
748: subStr = subStr
749: + blankString(width - subStr.length(),
750: (byte) 32);
751: }
752: strArray.add(subStr);
753: str = str.substring(breakPos).trim();
754: }
755: if (str.length() < width) {
756: str = str + blankString(width - str.length(), (byte) 32);
757: }
758: strArray.add(str);
759: return (String[]) strArray.toArray(new String[1]);
760: }
761:
762: private static String blankString(int width, byte b) {
763: byte[] bytes = new byte[width];
764: Arrays.fill(bytes, b);
765: return new String(bytes);
766: }
767:
768: /**
769: * Replaces all occurrences of <code>target</code> in <code>string</code>
770: * with <code>dest</code>.
771: *
772: * @param string string in which to target occurrences
773: * @param target string to target
774: * @param dest replacement string
775: * @return <code>string</code> with <code>dest</code> substituted
776: * for <code>target</code>
777: */
778: private static String replaceOccurrences(String string,
779: String target, String dest) {
780: StringBuffer b = new StringBuffer(string);
781: int lastIndex = 0;
782: while (true) {
783: int index = indexOf(b, target, lastIndex);
784: if (index < 0) {
785: break;
786: }
787: b.replace(index, index + target.length(), dest);
788: lastIndex = index + dest.length();
789: }
790: return b.toString();
791: }
792:
793: /**
794: * to do searches in character arrays. The source is the character array being
795: * searched, and the target is the string being searched for.
796: *
797: * @param source the characters being searched.
798: * @param sourceOffset offset of the source string.
799: * @param sourceCount count of the source string.
800: * @param target the characters being searched for.
801: * @param targetOffset offset of the target string.
802: * @param targetCount count of the target string.
803: * @param fromIndex the index to begin searching from.
804: * @return If the string argument occurs as a substring within this object, then
805: * the index of the first character of the first such substring is returned; if
806: * it does not occur as a substring, -1 is returned.
807: */
808: private static int indexOf(char[] source, int sourceOffset,
809: int sourceCount, char[] target, int targetOffset,
810: int targetCount, int fromIndex) {
811: if (fromIndex >= sourceCount) {
812: return (targetCount == 0 ? sourceCount : -1);
813: }
814: if (fromIndex < 0) {
815: fromIndex = 0;
816: }
817: if (targetCount == 0) {
818: return fromIndex;
819: }
820:
821: char first = target[targetOffset];
822: int pos = sourceOffset + fromIndex;
823: int max = sourceOffset + (sourceCount - targetCount);
824:
825: searchForNextChar: while (true) {
826: // find first character
827:
828: // not first char increment position
829: while (pos <= max && source[pos] != first) {
830: pos++;
831: }
832:
833: // at end of char buffer didnt find
834: if (pos > max) {
835: return -1;
836: }
837:
838: // found first character - see if the rest of matches up
839: int secondPos = pos + 1;
840: int end = secondPos + targetCount - 1;
841: int targetPos = targetOffset + 1;
842: while (secondPos < end) {
843: if (source[secondPos++] != target[targetPos++]) {
844: pos++;
845: // string doesnt match exit out of this loop and go back and
846: // continue looking at the next char
847: continue searchForNextChar;
848: }
849: }
850: // Found an entire whole string.
851: return pos - sourceOffset;
852: }
853: }
854:
855: /**
856: * Returns the index within this string of the first occurrence of the
857: * specified substring, starting at the specified index. If the string
858: * argument occurs as a substring within this object, then the index of
859: * the first character of the first such substring is returned; if it does
860: * not occur as a substring, -1 is returned. This replaces the functionality
861: * for java 1.4 StringBuffer.indexOf.
862: *
863: * @param buf - buffer to search for str
864: * @param findStr - string to located
865: * @param fromIndex - index to search
866: * @return If the string argument occurs as a substring within this object, then
867: * the index of the first character of the first such substring is returned; if
868: * it does not occur as a substring, -1 is returned.
869: */
870: private static int indexOf(StringBuffer buf, String findStr,
871: int fromIndex) {
872: // function in java's StringBuffer version 1.4 is synchronized
873: // get character buffer from string buffer
874: synchronized (buf) {
875: int bufLen = buf.length();
876: char[] charArray = new char[bufLen];
877: buf.getChars(0, bufLen, charArray, 0);
878:
879: // send into char indexof function
880: return indexOf(charArray, 0, bufLen, findStr.toCharArray(),
881: 0, findStr.length(), fromIndex);
882: }
883: }
884:
885: public ThemePainter getPainter() {
886: return _painter;
887: }
888: }
|