/* * @(#)BasicJideOptionPaneUI.java 3/27/2006 * * Copyright 2002 - 2006 JIDE Software Inc. All rights reserved. */ package com.jidesoft.plaf.basic; import com.jidesoft.dialog.ButtonNames; import com.jidesoft.dialog.ButtonPanel; import com.jidesoft.dialog.ButtonResources; import com.jidesoft.dialog.JideOptionPane; import com.jidesoft.plaf.UIDefaultsLookup; import com.jidesoft.swing.JideBoxLayout; import com.jidesoft.swing.JideSwingUtilities; import com.jidesoft.swing.NullPanel; import com.jidesoft.swing.PaintPanel; import javax.swing.*; import javax.swing.border.Border; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicOptionPaneUI; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; import java.util.ResourceBundle; public class BasicJideOptionPaneUI extends BasicOptionPaneUI { private Container _detailsArea; private JButton _detailsButton; private Container _buttonArea; private Container _bannerArea; private Component _titleComponent; private ThemePainter _painter; private PropertyChangeListener _propertyListener; // keep track of detail component width. private int _detailsPreferredWidth = -1; /** * Creates a new BasicOptionPaneUI instance. * * @param x the component to create UI * @return the UI instance. */ public static ComponentUI createUI(JComponent x) { return new BasicJideOptionPaneUI(); } @Override protected LayoutManager createLayoutManager() { return new JideBoxLayout(optionPane, JideBoxLayout.Y_AXIS); } // use a static to keep track of detail area visibility during the session private boolean _detailsVisible = false; /** * Is details area visible initially. * * @return true if details area is visible. */ public boolean isDetailsVisible() { return _detailsVisible; } /** * Sets if details area is visible initially. * * @param detailsVisible the flag */ public void setDetailsVisible(boolean detailsVisible) { if (_detailsVisible != detailsVisible) { _detailsVisible = detailsVisible; toggleDetailsArea(); } } @Override protected void installComponents() { boolean showBanner = UIDefaultsLookup.get("OptionPane.showBanner") == null || UIDefaultsLookup.getBoolean("OptionPane.showBanner"); if (showBanner) { optionPane.add(_bannerArea = createBannerArea(), JideBoxLayout.FIX); } Container messageArea = createMessageArea(); if (!showBanner) { addIcon(messageArea); } LookAndFeel.installBorder((JComponent) messageArea, "OptionPane.border"); optionPane.add(messageArea); Container separator = createSeparator(); if (separator != null) { optionPane.add(separator); } optionPane.add(_buttonArea = createButtonArea(), JideBoxLayout.FIX); optionPane.applyComponentOrientation(optionPane.getComponentOrientation()); if (shouldDetailsButtonVisible()) { updateDetailsComponent(); } } @Override protected void installListeners() { super.installListeners(); _propertyListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if (JideOptionPane.DETAILS_PROPERTY.equals(evt.getPropertyName())) { updateDetailsComponent(); if (_buttonArea instanceof ButtonPanel) { Component detailsButton = ((ButtonPanel) _buttonArea).getButtonByName(ButtonNames.DETAILS); if (detailsButton != null) { detailsButton.setVisible(evt.getNewValue() != null); } } } else if (JideOptionPane.TITLE_PROPERTY.equals(evt.getPropertyName())) { updateTitleComponent(_bannerArea); } } }; optionPane.addPropertyChangeListener(_propertyListener); } @Override protected void uninstallListeners() { super.uninstallListeners(); optionPane.removePropertyChangeListener(_propertyListener); } protected void updateDetailsComponent() { if (_detailsArea != null) { optionPane.remove(_detailsArea); _detailsArea = null; } _detailsArea = createDetailsComponent(); if (_detailsArea != null) { optionPane.add(_detailsArea, JideBoxLayout.VARY); _detailsArea.setVisible(isDetailsVisible()); } } @Override protected Container createMessageArea() { JPanel top = new JPanel(); Border topBorder = (Border) UIDefaultsLookup.get("OptionPane.messageAreaBorder"); if (topBorder != null) { top.setBorder(topBorder); } top.setLayout(new BorderLayout()); /* Fill the body. */ Container body = new JPanel(new GridBagLayout()); Container realBody = new JPanel(new BorderLayout()); body.setName("OptionPane.body"); realBody.setName("OptionPane.realBody"); if (getIcon() != null) { JPanel sep = new JPanel(); sep.setName("OptionPane.separator"); sep.setPreferredSize(new Dimension(15, 1)); realBody.add(sep, BorderLayout.BEFORE_LINE_BEGINS); } realBody.add(body, BorderLayout.CENTER); GridBagConstraints cons = new GridBagConstraints(); cons.gridx = cons.gridy = 0; cons.gridwidth = GridBagConstraints.REMAINDER; cons.gridheight = 1; int anchor = UIDefaultsLookup.getInt("OptionPane.messageAnchor"); cons.anchor = anchor == 0 ? GridBagConstraints.CENTER : anchor; cons.insets = new Insets(0, 0, 3, 0); Object message = getMessage(); // if (message instanceof String // && !((String) message).toLowerCase().startsWith("<html>")) { // addMessageComponents(body, cons, null, getMaxCharactersPerLineCount(), false); // } // else { addMessageComponents(body, cons, message, getMaxCharactersPerLineCount(), false); // } top.add(realBody, BorderLayout.CENTER); return top; } @Override protected Container createSeparator() { return new JSeparator(); } @Override protected void installDefaults() { super.installDefaults(); optionPane.setBorder(BorderFactory.createEmptyBorder()); _painter = (ThemePainter) UIDefaultsLookup.get("Theme.painter"); } @Override protected void uninstallDefaults() { super.uninstallDefaults(); _painter = null; } protected Container createDetailsComponent() { if (!(optionPane instanceof JideOptionPane)) { return null; } JideOptionPane jideOptionPane = (JideOptionPane) optionPane; Object details = jideOptionPane.getDetails(); if (details instanceof Container) { _detailsPreferredWidth = ((Container) details).getPreferredSize().width; return (Container) details; } else if (details instanceof Component) { JPanel panel = new JPanel(new BorderLayout()); panel.add((Component) details); _detailsPreferredWidth = panel.getPreferredSize().width; return panel; } else if (details instanceof String) { JTextArea area = new JTextArea((String) details); area.setEditable(false); area.setRows(20); area.setColumns(60); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JScrollPane(area)); panel.setBorder(BorderFactory.createEmptyBorder(10, 6, 10, 6)); _detailsPreferredWidth = panel.getPreferredSize().width; return panel; } else { return null; } } @Override protected Container createButtonArea() { int orientation = UIDefaultsLookup.getInt("OptionPane.buttonOrientation"); orientation = orientation == 0 ? SwingConstants.CENTER : orientation; ButtonPanel buttonPanel = new ButtonPanel(orientation); Border border = (Border) UIDefaultsLookup.get("OptionPane.buttonAreaBorder"); buttonPanel.setName("OptionPane.buttonArea"); if (border != null) { buttonPanel.setBorder(border); } boolean sameSize = UIDefaultsLookup.getBoolean("OptionPane.sameSizeButtons"); buttonPanel.setSizeConstraint(sameSize ? ButtonPanel.SAME_SIZE : ButtonPanel.NO_LESS_THAN); int padding = UIDefaultsLookup.getInt("OptionPane.buttonPadding"); padding = padding == 0 ? 6 : padding; buttonPanel.setButtonGap(padding); addButtonComponents(buttonPanel, getButtons(), getInitialValueIndex()); return buttonPanel; } @Override protected void addButtonComponents(Container container, Object[] buttons, int initialIndex) { if (buttons != null && buttons.length > 0) { int numButtons = buttons.length; for (int counter = 0; counter < numButtons; counter++) { Object button = buttons[counter]; Component newComponent; if (button instanceof Component) { newComponent = (Component) button; container.add(newComponent, ButtonPanel.OTHER_BUTTON); hasCustomComponents = true; } else { JButton aButton; if (button instanceof ButtonFactory) { aButton = ((ButtonFactory) button).createButton(); } else if (button instanceof Icon) aButton = new JButton((Icon) button); else aButton = new JButton(button.toString()); aButton.setMultiClickThreshhold(UIDefaultsLookup.getInt("OptionPane.buttonClickThreshhold")); configureButton(aButton); if (ButtonNames.YES.equals(aButton.getName()) || ButtonNames.NO.equals(aButton.getName()) || ButtonNames.OK.equals(aButton.getName()) || ButtonNames.CLOSE.equals(aButton.getName()) || ButtonNames.FINISH.equals(aButton.getName())) { container.add(aButton, ButtonPanel.AFFIRMATIVE_BUTTON); } else if (ButtonNames.CANCEL.equals(aButton.getName())) { container.add(aButton, ButtonPanel.CANCEL_BUTTON); } else if (ButtonNames.HELP.equals(aButton.getName())) { container.add(aButton, ButtonPanel.HELP_BUTTON); } else { container.add(aButton, ButtonPanel.OTHER_BUTTON); } if (ButtonNames.DETAILS.equals(aButton.getName())) { aButton.addActionListener(new AbstractAction() { private static final long serialVersionUID = -6121325145433592319L; public void actionPerformed(ActionEvent e) { JButton defaultButton = (JButton) e.getSource(); toggleDetailsArea(); Container top = defaultButton.getTopLevelAncestor(); if (top instanceof Window) { ((Window) top).pack(); } } }); aButton.setVisible(shouldDetailsButtonVisible()); _detailsButton = aButton; } else { ActionListener buttonListener = createButtonActionListener(counter); if (buttonListener != null) { aButton.addActionListener(buttonListener); } } newComponent = aButton; } if (counter == initialIndex) { initialFocusComponent = newComponent; if (initialFocusComponent instanceof JButton) { JButton defaultB = (JButton) initialFocusComponent; defaultB.addAncestorListener(new AncestorListener() { public void ancestorAdded(AncestorEvent e) { JButton defaultButton = (JButton) e.getComponent(); JRootPane root = SwingUtilities.getRootPane(defaultButton); if (root != null) { root.setDefaultButton(defaultButton); } } public void ancestorRemoved(AncestorEvent event) { } public void ancestorMoved(AncestorEvent event) { } }); } } } } } private void toggleDetailsArea() { final ResourceBundle resourceBundle = ButtonResources.getResourceBundle(optionPane.getLocale()); if (_detailsArea.isVisible()) { setDetailsVisible(false); _detailsArea.setVisible(false); _detailsButton.setText(optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.showDetails") : resourceBundle.getString("Button.showDetails")); _detailsButton.setMnemonic(optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.showDetails.mnemonic").charAt(0) : resourceBundle.getString("Button.showDetails.mnemonic").charAt(0)); } else { setDetailsVisible(true); _detailsArea.setVisible(true); _detailsButton.setText(optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.hideDetails") : resourceBundle.getString("Button.hideDetails")); _detailsButton.setMnemonic(optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.hideDetails.mnemonic").charAt(0) : resourceBundle.getString("Button.hideDetails.mnemonic").charAt(0)); } } /** * Returns the buttons to display from the JOptionPane the receiver is providing the look and feel for. If the * JOptionPane has options set, they will be provided, otherwise if the optionType is YES_NO_OPTION, yesNoOptions is * returned, if the type is YES_NO_CANCEL_OPTION yesNoCancelOptions is returned, otherwise defaultButtons are * returned. */ @Override protected Object[] getButtons() { if (optionPane != null) { Object[] suppliedOptions = optionPane.getOptions(); if (suppliedOptions == null) { Object[] defaultOptions; int type = optionPane.getOptionType(); Locale l = optionPane.getLocale(); if (type == JOptionPane.YES_NO_OPTION) { defaultOptions = new ButtonFactory[2]; defaultOptions[0] = new ButtonFactory( ButtonNames.YES, UIDefaultsLookup.getString("OptionPane.yesButtonText", l), getMnemonic("OptionPane.yesButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.yesIcon")); defaultOptions[1] = new ButtonFactory( ButtonNames.NO, UIDefaultsLookup.getString("OptionPane.noButtonText", l), getMnemonic("OptionPane.noButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.noIcon")); } else if (type == JOptionPane.YES_NO_CANCEL_OPTION) { defaultOptions = new ButtonFactory[3]; defaultOptions[0] = new ButtonFactory( ButtonNames.YES, UIDefaultsLookup.getString("OptionPane.yesButtonText", l), getMnemonic("OptionPane.yesButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.yesIcon")); defaultOptions[1] = new ButtonFactory( ButtonNames.NO, UIDefaultsLookup.getString("OptionPane.noButtonText", l), getMnemonic("OptionPane.noButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.noIcon")); defaultOptions[2] = new ButtonFactory( ButtonNames.CANCEL, UIDefaultsLookup.getString("OptionPane.cancelButtonText", l), getMnemonic("OptionPane.cancelButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.cancelIcon")); } else if (type == JOptionPane.OK_CANCEL_OPTION) { defaultOptions = new ButtonFactory[2]; defaultOptions[0] = new ButtonFactory( ButtonNames.OK, JideSwingUtilities.getOKString(l), getMnemonic("OptionPane.okButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.okIcon")); defaultOptions[1] = new ButtonFactory( ButtonNames.CANCEL, JideSwingUtilities.getCancelString(l), getMnemonic("OptionPane.cancelButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.cancelIcon")); } else if (type == JideOptionPane.CLOSE_OPTION) { defaultOptions = new ButtonFactory[1]; final ResourceBundle resourceBundle = ButtonResources.getResourceBundle(optionPane.getLocale()); defaultOptions[0] = new ButtonFactory( ButtonNames.CLOSE, optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.close") : resourceBundle.getString("Button.close"), optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.close.mnemonic").charAt(0) : resourceBundle.getString("Button.close.mnemonic").charAt(0), null); } else { defaultOptions = new ButtonFactory[1]; defaultOptions[0] = new ButtonFactory( ButtonNames.OK, JideSwingUtilities.getOKString(l), getMnemonic("OptionPane.okButtonMnemonic", l), (Icon) UIDefaultsLookup.get("OptionPane.okIcon")); } return addDetailsButton(defaultOptions, true); } return addDetailsButton(suppliedOptions, true); } return null; } protected Object[] addDetailsButton(Object[] options, boolean showDetails) { if (showDetails) { Object[] newOptions = new Object[options.length + 1]; System.arraycopy(options, 0, newOptions, 0, options.length); final ResourceBundle resourceBundle = ButtonResources.getResourceBundle(optionPane.getLocale()); if (isDetailsVisible()) { newOptions[newOptions.length - 1] = new ButtonFactory( ButtonNames.DETAILS, optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.hideDetails") : resourceBundle.getString("Button.hideDetails"), optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.hideDetails.mnemonic").charAt(0) : resourceBundle.getString("Button.hideDetails.mnemonic").charAt(0), null); } else { newOptions[newOptions.length - 1] = new ButtonFactory( ButtonNames.DETAILS, optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.showDetails") : resourceBundle.getString("Button.showDetails"), optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getResourceString("Button.showDetails.mnemonic").charAt(0) : resourceBundle.getString("Button.showDetails.mnemonic").charAt(0), null); } return newOptions; } else { return options; } } private boolean shouldDetailsButtonVisible() { return optionPane instanceof JideOptionPane && ((JideOptionPane) optionPane).getDetails() != null; } /** * Configures any necessary colors/fonts for the specified button used representing the button portion of the * OptionPane. * * @param button the button to configure */ protected void configureButton(JButton button) { Font buttonFont = (Font) UIDefaultsLookup.get("OptionPane.buttonFont"); if (buttonFont != null) { button.setFont(buttonFont); } } protected int getMnemonic(String key, Locale l) { String value = (String) UIDefaultsLookup.get(key, l); if (value == null) { return 0; } try { return Integer.parseInt(value); } catch (NumberFormatException nfe) { // null } return 0; } /** * This class is used to create the default buttons. This indirection is used so that addButtonComponents can tell * which Buttons were created by us vs subclasses or from the JOptionPane itself. */ protected static class ButtonFactory { private String name; private String text; private int mnemonic; private Icon icon; ButtonFactory(String name, String text, int mnemonic, Icon icon) { this.name = name; this.text = text; this.mnemonic = mnemonic; this.icon = icon; } JButton createButton() { JButton button = new JButton(text); if (name != null) { button.setName(name); } if (icon != null) { button.setIcon(icon); } if (mnemonic != 0) { button.setMnemonic(mnemonic); } return button; } } @Override protected void addIcon(Container top) { Icon sideIcon = getIcon(); if (sideIcon != null) { JLabel iconLabel = new JLabel(sideIcon); iconLabel.setName("OptionPane.iconLabel"); top.add(iconLabel, BorderLayout.BEFORE_LINE_BEGINS); } } protected Container createBannerArea() { PaintPanel bannerPanel = new PaintPanel() { @Override public Dimension getPreferredSize() { Dimension preferredSize = super.getPreferredSize(); if (preferredSize.width < _detailsPreferredWidth) { preferredSize.width = _detailsPreferredWidth; } return preferredSize; } }; customizeBannerArea(bannerPanel); bannerPanel.setLayout(new BorderLayout(10, 10)); addIcon(bannerPanel); updateTitleComponent(bannerPanel); bannerPanel.add(new JLabel(UIDefaultsLookup.getIcon("OptionPane.bannerIcon")), BorderLayout.AFTER_LINE_ENDS); return bannerPanel; } protected void customizeBannerArea(PaintPanel bannerPanel) { Paint paint = (Paint) UIDefaultsLookup.get("OptionPane.bannerBackgroundPaint"); if (paint != null) { bannerPanel.setBackgroundPaint(paint); } else { Color dk = UIDefaultsLookup.getColor("OptionPane.bannerBackgroundDk"); Color lt = UIDefaultsLookup.getColor("OptionPane.bannerBackgroundLt"); boolean direction = UIDefaultsLookup.get("OptionPane.bannerBackgroundDirection") == null || UIDefaultsLookup.getBoolean("OptionPane.bannerBackgroundDirection"); if (dk == null && lt != null) { dk = lt; bannerPanel.setGradientPaint( dk != null ? dk : getPainter().getOptionPaneBannerLt(), lt != null ? lt : getPainter().getOptionPaneBannerDk(), direction); } else if (dk != null && lt == null) { lt = dk; bannerPanel.setGradientPaint( dk != null ? dk : getPainter().getOptionPaneBannerLt(), lt != null ? lt : getPainter().getOptionPaneBannerDk(), direction); } else if (dk != null && lt != null) { bannerPanel.setGradientPaint( dk != null ? dk : getPainter().getOptionPaneBannerLt(), lt != null ? lt : getPainter().getOptionPaneBannerDk(), direction); } } Border border = UIDefaultsLookup.getBorder("OptionPane.bannerBorder"); bannerPanel.setBorder(border != null ? border : BorderFactory.createEmptyBorder(0, 10, 0, 0)); } private void updateTitleComponent(Container bannerArea) { if (bannerArea == null) { return; } if (_titleComponent != null) { bannerArea.remove(_titleComponent); _titleComponent = null; } Object title = optionPane instanceof JideOptionPane ? ((JideOptionPane) optionPane).getTitle() : null; if (title instanceof String) { if (((String) title).startsWith("<html>") || ((String) title).startsWith("<HTML>")) { _titleComponent = new JLabel(((String) title)); } else { String[] titles = fitInWidth((String) title, UIDefaultsLookup.getInt("OptionPane.bannerMaxCharsPerLine")); JPanel titlePanel = new NullPanel(); titlePanel.setLayout(new BoxLayout(titlePanel, BoxLayout.Y_AXIS)); titlePanel.setOpaque(false); titlePanel.add(Box.createGlue()); for (String s : titles) { JLabel label = new JLabel(s); label.setFont(label.getFont().deriveFont(UIDefaultsLookup.getInt("OptionPane.bannerFontStyle"), UIDefaultsLookup.getInt("OptionPane.bannerFontSize"))); Color color = UIDefaultsLookup.getColor("OptionPane.bannerForeground"); label.setForeground(color != null ? color : getPainter().getOptionPaneBannerForeground()); titlePanel.add(label); } titlePanel.add(Box.createGlue()); _titleComponent = titlePanel; } } else if (title instanceof Component) { _titleComponent = (Component) title; } if (_titleComponent != null) { bannerArea.add(_titleComponent, BorderLayout.CENTER); } } // static methods to split a string into multiple lines. /** * 1. Do not break a word/number. If the character is letter/digit, break at the most recent non- one; 2. Expand * "\n" to a blank line 3. Expand "\t" to four " " 4. Trim leading empty spaces * * @param str the string * @param width the target width * @return An array of Strings with length of "width" */ private static String[] fitInWidth(String str, int width) { if (str == null) str = ""; String BLANK_STR = blankString(width, (byte) 32); str = replaceOccurrences(str, "\n", BLANK_STR); str = replaceOccurrences(str, "\t", " "); ArrayList<String> strArray = new ArrayList<String>(); str = str.trim(); while (str.length() > width) { int breakPos = width; if (Character.isLetterOrDigit(str.charAt(width))) { breakPos--; char breakChar = str.charAt(breakPos); while (Character.isLetterOrDigit(breakChar) && breakPos > 0) { breakPos--; breakChar = str.charAt(breakPos); } if (breakPos == 0 && Character.isLetterOrDigit(breakChar)) { breakPos = width; } else { breakPos++; } } String subStr = str.substring(0, breakPos); if (subStr.length() < width) { subStr = subStr + blankString(width - subStr.length(), (byte) 32); } strArray.add(subStr); str = str.substring(breakPos).trim(); } if (str.length() < width) { str = str + blankString(width - str.length(), (byte) 32); } strArray.add(str); if (strArray.size() == 1) { return new String[]{strArray.get(0).trim()}; } return strArray.toArray(new String[strArray.size()]); } private static String blankString(int width, byte b) { byte[] bytes = new byte[width]; Arrays.fill(bytes, b); return new String(bytes); } /** * Replaces all occurrences of <code>target</code> in <code>string</code> with <code>dest</code>. * * @param string string in which to target occurrences * @param target string to target * @param dest replacement string * @return <code>string</code> with <code>dest</code> substituted for <code>target</code> */ private static String replaceOccurrences(String string, String target, String dest) { StringBuffer b = new StringBuffer(string); int lastIndex = 0; while (true) { int index = indexOf(b, target, lastIndex); if (index < 0) { break; } b.replace(index, index + target.length(), dest); lastIndex = index + dest.length(); } return b.toString(); } /** * to do searches in character arrays. The source is the character array being searched, and the target is the * string being searched for. * * @param source the characters being searched. * @param sourceOffset offset of the source string. * @param sourceCount count of the source string. * @param target the characters being searched for. * @param targetOffset offset of the target string. * @param targetCount count of the target string. * @param fromIndex the index to begin searching from. * @return If the string argument occurs as a substring within this object, then the index of the first character of * the first such substring is returned; if it does not occur as a substring, -1 is returned. */ private static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { if (fromIndex >= sourceCount) { return (targetCount == 0 ? sourceCount : -1); } if (fromIndex < 0) { fromIndex = 0; } if (targetCount == 0) { return fromIndex; } char first = target[targetOffset]; int pos = sourceOffset + fromIndex; int max = sourceOffset + (sourceCount - targetCount); searchForNextChar: while (true) { // find first character // not first char increment position while (pos <= max && source[pos] != first) { pos++; } // at end of char buffer didn't find if (pos > max) { return -1; } // found first character - see if the rest of matches up int secondPos = pos + 1; int end = secondPos + targetCount - 1; int targetPos = targetOffset + 1; while (secondPos < end) { if (source[secondPos++] != target[targetPos++]) { pos++; // string doesn't match exit out of this loop and go back and // continue looking at the next char continue searchForNextChar; } } // Found an entire whole string. return pos - sourceOffset; } } /** * Returns the index within this string of the first occurrence of the specified substring, starting at the * specified index. If the string argument occurs as a substring within this object, then the index of the first * character of the first such substring is returned; if it does not occur as a substring, -1 is returned. This * replaces the functionality for java 1.4 StringBuffer.indexOf. * * @param buf - buffer to search for str * @param findStr - string to located * @param fromIndex - index to search * @return If the string argument occurs as a substring within this object, then the index of the first character of * the first such substring is returned; if it does not occur as a substring, -1 is returned. */ private static int indexOf(StringBuffer buf, String findStr, int fromIndex) { // function in Java's StringBuffer version 1.4 is synchronized // get character buffer from string buffer synchronized (buf) { int bufLen = buf.length(); char[] charArray = new char[bufLen]; buf.getChars(0, bufLen, charArray, 0); // send into char indexOf function return indexOf(charArray, 0, bufLen, findStr.toCharArray(), 0, findStr.length(), fromIndex); } } public ThemePainter getPainter() { return _painter; } }