0001: /*
0002: * GUIUtilities.java - Various GUI utility functions
0003: * :tabSize=8:indentSize=8:noTabs=false:
0004: * :folding=explicit:collapseFolds=1:
0005: *
0006: * Copyright (C) 1999, 2004 Slava Pestov
0007: *
0008: * This program is free software; you can redistribute it and/or
0009: * modify it under the terms of the GNU General Public License
0010: * as published by the Free Software Foundation; either version 2
0011: * of the License, or any later version.
0012: *
0013: * This program is distributed in the hope that it will be useful,
0014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0016: * GNU General Public License for more details.
0017: *
0018: * You should have received a copy of the GNU General Public License
0019: * along with this program; if not, write to the Free Software
0020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0021: */
0022:
0023: package org.gjt.sp.jedit;
0024:
0025: //{{{ Imports
0026:
0027: import org.gjt.sp.jedit.browser.VFSFileChooserDialog;
0028: import org.gjt.sp.jedit.gui.EnhancedButton;
0029: import org.gjt.sp.jedit.gui.FloatingWindowContainer;
0030: import org.gjt.sp.jedit.gui.SplashScreen;
0031: import org.gjt.sp.jedit.gui.VariableGridLayout;
0032: import org.gjt.sp.jedit.menu.EnhancedCheckBoxMenuItem;
0033: import org.gjt.sp.jedit.menu.EnhancedMenu;
0034: import org.gjt.sp.jedit.menu.EnhancedMenuItem;
0035: import org.gjt.sp.jedit.syntax.SyntaxStyle;
0036: import org.gjt.sp.jedit.syntax.Token;
0037: import org.gjt.sp.jedit.textarea.TextAreaMouseHandler;
0038: import org.gjt.sp.util.Log;
0039:
0040: import javax.swing.*;
0041: import java.awt.*;
0042: import java.awt.event.*;
0043: import java.net.URL;
0044: import java.util.*;
0045: import java.util.List;
0046:
0047: //}}}
0048:
0049: /**
0050: * Various GUI functions.<p>
0051: *
0052: * The most frequently used members of this class are:
0053: *
0054: * <ul>
0055: * <li>{@link #loadIcon(String)}</li>
0056: * <li>{@link #confirm(Component,String,Object[],int,int)}</li>
0057: * <li>{@link #error(Component,String,Object[])}</li>
0058: * <li>{@link #message(Component,String,Object[])}</li>
0059:
0060: * <li>{@link #showVFSFileDialog(View,String,int,boolean)}</li>
0061: * <li>{@link #loadGeometry(Window,String)}</li>
0062: * <li>{@link #saveGeometry(Window,String)}</li>
0063: * <li>{@link #showPopupMenu(JPopupMenu,Component,int,int)}</li>
0064: * </ul>
0065: *
0066: * @author Slava Pestov
0067: * @version $Id: GUIUtilities.java 11177 2007-12-01 09:50:50Z k_satoda $
0068: */
0069: public class GUIUtilities {
0070: //{{{ Some predefined icons
0071: /**
0072: * @deprecated Use <code>GUIUtilities.loadIcon("new.gif");</code>
0073: * instead.
0074: */
0075: public static Icon NEW_BUFFER_ICON;
0076:
0077: /**
0078: * @deprecated Use <code>GUIUtilities.loadIcon("dirty.gif");</code>
0079: * instead.
0080: */
0081: public static Icon DIRTY_BUFFER_ICON;
0082:
0083: /**
0084: * @deprecated Use <code>GUIUtilities.loadIcon("readonly.gif");</code>
0085: * instead.
0086: */
0087: public static Icon READ_ONLY_BUFFER_ICON;
0088:
0089: /**
0090: * @deprecated Use <code>GUIUtilities.loadIcon("normal.gif");</code>
0091: * instead.
0092: */
0093: public static Icon NORMAL_BUFFER_ICON;
0094:
0095: /**
0096: * @deprecated Use <code>GUIUtilities.loadIcon("jedit-icon.gif");</code>
0097: * instead.
0098: */
0099: public static Icon WINDOW_ICON;
0100:
0101: //}}}
0102:
0103: //{{{ Icon methods
0104:
0105: //{{{ setIconPath() method
0106: /**
0107: * Sets the path where jEdit looks for icons.
0108: * @since jEdit 4.2pre5
0109: */
0110: public static void setIconPath(String iconPath) {
0111: GUIUtilities.iconPath = iconPath;
0112: if (icons != null)
0113: icons.clear();
0114: } //}}}
0115:
0116: //{{{ loadIcon() method
0117: /**
0118: * Loads an icon.
0119: * @param iconName The icon name
0120: * @since jEdit 2.6pre7
0121: */
0122: public static Icon loadIcon(String iconName) {
0123: if (icons == null)
0124: icons = new Hashtable<String, Icon>();
0125:
0126: // check if there is a cached version first
0127: Icon icon = icons.get(iconName);
0128: if (icon != null)
0129: return icon;
0130:
0131: URL url;
0132:
0133: try {
0134: // get the icon
0135: if (MiscUtilities.isURL(iconName))
0136: url = new URL(iconName);
0137: else
0138: url = new URL(iconPath + iconName);
0139: } catch (Exception e) {
0140: try {
0141: url = new URL(defaultIconPath + iconName);
0142: } catch (Exception ex) {
0143: Log.log(Log.ERROR, GUIUtilities.class,
0144: "Icon not found: " + iconName);
0145: Log.log(Log.ERROR, GUIUtilities.class, ex);
0146: return null;
0147: }
0148: }
0149:
0150: icon = new ImageIcon(url);
0151:
0152: icons.put(iconName, icon);
0153: return icon;
0154: } //}}}
0155:
0156: //{{{ getEditorIcon() method
0157: /**
0158: * Returns the default editor window image.
0159: */
0160: public static Image getEditorIcon() {
0161: return ((ImageIcon) loadIcon("jedit-icon.gif")).getImage();
0162: } //}}}
0163:
0164: //{{{ getPluginIcon() method
0165: /**
0166: * Returns the default plugin window image.
0167: */
0168: public static Image getPluginIcon() {
0169: return getEditorIcon();
0170: } //}}}
0171:
0172: //}}}
0173:
0174: //{{{ Menus, tool bars
0175:
0176: //{{{ loadMenuBar() method
0177: /**
0178: * Creates a menubar. Plugins should not need to call this method.
0179: * @param name The menu bar name
0180: * @since jEdit 3.2pre5
0181: */
0182: public static JMenuBar loadMenuBar(String name) {
0183: return loadMenuBar(jEdit.getActionContext(), name);
0184: } //}}}
0185:
0186: //{{{ loadMenuBar() method
0187: /**
0188: * Creates a menubar. Plugins should not need to call this method.
0189: * @param context An action context
0190: * @param name The menu bar name
0191: * @since jEdit 4.2pre1
0192: */
0193: public static JMenuBar loadMenuBar(ActionContext context,
0194: String name) {
0195: String menus = jEdit.getProperty(name);
0196: StringTokenizer st = new StringTokenizer(menus);
0197:
0198: JMenuBar mbar = new JMenuBar();
0199:
0200: while (st.hasMoreTokens()) {
0201: String menuName = st.nextToken();
0202: mbar.add(loadMenu(context, menuName));
0203: }
0204:
0205: return mbar;
0206: } //}}}
0207:
0208: //{{{ loadMenu() method
0209: /**
0210: * Creates a menu. The menu label is set from the
0211: * <code><i>name</i>.label</code> property. The menu contents is taken
0212: * from the <code><i>name</i></code> property, which is a whitespace
0213: * separated list of action names. An action name of <code>-</code>
0214: * inserts a separator in the menu.
0215: * @param name The menu name
0216: * @see #loadMenuItem(String)
0217: * @since jEdit 2.6pre2
0218: */
0219: public static JMenu loadMenu(String name) {
0220: return loadMenu(jEdit.getActionContext(), name);
0221: } //}}}
0222:
0223: //{{{ loadMenu() method
0224: /**
0225: * Creates a menu. The menu label is set from the
0226: * <code><i>name</i>.label</code> property. The menu contents is taken
0227: * from the <code><i>name</i></code> property, which is a whitespace
0228: * separated list of action names. An action name of <code>-</code>
0229: * inserts a separator in the menu.
0230: * @param context An action context; either
0231: * <code>jEdit.getActionContext()</code> or
0232: * <code>VFSBrowser.getActionContext()</code>.
0233: * @param name The menu name
0234: * @see #loadMenuItem(String)
0235: * @since jEdit 4.2pre1
0236: */
0237: public static JMenu loadMenu(ActionContext context, String name) {
0238: return new EnhancedMenu(name, jEdit.getProperty(name
0239: .concat(".label")), context);
0240: } //}}}
0241:
0242: //{{{ loadPopupMenu() method
0243: /**
0244: * Creates a popup menu.
0245:
0246: * @param name The menu name
0247: * @since jEdit 2.6pre2
0248: */
0249: public static JPopupMenu loadPopupMenu(String name) {
0250: return loadPopupMenu(jEdit.getActionContext(), name);
0251: } //}}}
0252:
0253: //{{{ loadPopupMenu() method
0254: /**
0255: * Creates a popup menu.
0256:
0257: * @param context An action context; either
0258: * <code>jEdit.getActionContext()</code> or
0259: * <code>VFSBrowser.getActionContext()</code>.
0260: * @param name The menu name
0261: * @since jEdit 4.2pre1
0262: */
0263: public static JPopupMenu loadPopupMenu(ActionContext context,
0264: String name) {
0265: JPopupMenu menu = new JPopupMenu();
0266:
0267: String menuItems = jEdit.getProperty(name);
0268: if (menuItems != null) {
0269: StringTokenizer st = new StringTokenizer(menuItems);
0270: while (st.hasMoreTokens()) {
0271: String menuItemName = st.nextToken();
0272: if (menuItemName.equals("-"))
0273: menu.addSeparator();
0274: else
0275: menu
0276: .add(loadMenuItem(context, menuItemName,
0277: false));
0278: }
0279: }
0280:
0281: return menu;
0282: } //}}}
0283:
0284: //{{{ loadMenuItem() method
0285: /**
0286: * Creates a menu item. The menu item is bound to the action named by
0287: * <code>name</code> with label taken from the return value of the
0288: * {@link EditAction#getLabel()} method.
0289: *
0290: * @param name The menu item name
0291: * @see #loadMenu(String)
0292: * @since jEdit 2.6pre1
0293: */
0294: public static JMenuItem loadMenuItem(String name) {
0295: return loadMenuItem(jEdit.getActionContext(), name, true);
0296: } //}}}
0297:
0298: //{{{ loadMenuItem() method
0299: /**
0300: * Creates a menu item.
0301: * @param name The menu item name
0302: * @param setMnemonic True if the menu item should have a mnemonic
0303: * @since jEdit 3.1pre1
0304: */
0305: public static JMenuItem loadMenuItem(String name,
0306: boolean setMnemonic) {
0307: return loadMenuItem(jEdit.getActionContext(), name, setMnemonic);
0308: } //}}}
0309:
0310: //{{{ loadMenuItem() method
0311: /**
0312: * Creates a menu item.
0313: * @param context An action context; either
0314: * <code>jEdit.getActionContext()</code> or
0315: * <code>VFSBrowser.getActionContext()</code>.
0316: * @param name The menu item name
0317: * @param setMnemonic True if the menu item should have a mnemonic
0318: * @since jEdit 4.2pre1
0319: */
0320: public static JMenuItem loadMenuItem(ActionContext context,
0321: String name, boolean setMnemonic) {
0322: if (name.charAt(0) == '%')
0323: return loadMenu(context, name.substring(1));
0324:
0325: String label = jEdit.getProperty(name + ".label");
0326: if (label == null)
0327: label = name;
0328:
0329: char mnemonic;
0330: int index = label.indexOf('$');
0331: if (index != -1 && label.length() - index > 1) {
0332: mnemonic = Character.toLowerCase(label.charAt(index + 1));
0333: label = label.substring(0, index).concat(
0334: label.substring(++index));
0335: } else
0336: mnemonic = '\0';
0337:
0338: JMenuItem mi;
0339: if (jEdit.getBooleanProperty(name + ".toggle"))
0340: mi = new EnhancedCheckBoxMenuItem(label, name, context);
0341: else
0342: mi = new EnhancedMenuItem(label, name, context);
0343:
0344: if (!OperatingSystem.isMacOS() && setMnemonic
0345: && mnemonic != '\0')
0346: mi.setMnemonic(mnemonic);
0347:
0348: return mi;
0349: } //}}}
0350:
0351: //{{{ loadMenuItem(EditAction, boolean)
0352: public static JMenuItem loadMenuItem(EditAction editAction,
0353: boolean setMnemonic) {
0354: String name = editAction.getName();
0355: ActionContext context = jEdit.getActionContext();
0356:
0357: // String label = jEdit.getProperty(name + ".label");
0358: String label = editAction.getLabel();
0359: if (label == null)
0360: label = name;
0361:
0362: char mnemonic;
0363: int index = label.indexOf('$');
0364: if (index != -1 && label.length() - index > 1) {
0365: mnemonic = Character.toLowerCase(label.charAt(index + 1));
0366: label = label.substring(0, index).concat(
0367: label.substring(++index));
0368: } else
0369: mnemonic = '\0';
0370:
0371: JMenuItem mi;
0372: if (jEdit.getBooleanProperty(name + ".toggle"))
0373: mi = new EnhancedCheckBoxMenuItem(label, name, context);
0374: else
0375: mi = new EnhancedMenuItem(label, name, context);
0376:
0377: if (!OperatingSystem.isMacOS() && setMnemonic
0378: && mnemonic != '\0')
0379: mi.setMnemonic(mnemonic);
0380:
0381: return mi;
0382: } //}}}
0383:
0384: //{{{ loadToolBar() method
0385: /**
0386: * Creates a toolbar.
0387: * @param name The toolbar name
0388: * @since jEdit 4.2pre2
0389: */
0390: public static Box loadToolBar(String name) {
0391: return loadToolBar(jEdit.getActionContext(), name);
0392: } //}}}
0393:
0394: //{{{ loadToolBar() method
0395: /**
0396: * Creates a toolbar.
0397: * @param context An action context; either
0398: * <code>jEdit.getActionContext()</code> or
0399: * <code>VFSBrowser.getActionContext()</code>.
0400: * @param name The toolbar name
0401: * @since jEdit 4.2pre2
0402: */
0403: public static Box loadToolBar(ActionContext context, String name) {
0404: Box toolBar = new Box(BoxLayout.X_AXIS);
0405:
0406: String buttons = jEdit.getProperty(name);
0407: if (buttons != null) {
0408: StringTokenizer st = new StringTokenizer(buttons);
0409: while (st.hasMoreTokens()) {
0410: String button = st.nextToken();
0411: if (button.equals("-"))
0412: toolBar.add(Box.createHorizontalStrut(12));
0413: else {
0414: JButton b = loadToolButton(context, button);
0415: if (b != null)
0416: toolBar.add(b);
0417: }
0418: }
0419: }
0420:
0421: toolBar.add(Box.createGlue());
0422:
0423: return toolBar;
0424: } //}}}
0425:
0426: //{{{ loadToolButton() method
0427: /**
0428: * Loads a tool bar button. The tooltip is constructed from
0429: * the <code><i>name</i>.label</code> and
0430: * <code><i>name</i>.shortcut</code> properties and the icon is loaded
0431: * from the resource named '/org/gjt/sp/jedit/icons/' suffixed
0432: * with the value of the <code><i>name</i>.icon</code> property.
0433: * @param name The name of the button
0434: */
0435: public static EnhancedButton loadToolButton(String name) {
0436: return loadToolButton(jEdit.getActionContext(), name);
0437: } //}}}
0438:
0439: //{{{ loadToolButton() method
0440: /**
0441: * Loads a tool bar button. The tooltip is constructed from
0442: * the <code><i>name</i>.label</code> and
0443: * <code><i>name</i>.shortcut</code> properties and the icon is loaded
0444: * from the resource named '/org/gjt/sp/jedit/icons/' suffixed
0445: * with the value of the <code><i>name</i>.icon</code> property.
0446: * @param context An action context; either
0447: * <code>jEdit.getActionContext()</code> or
0448: * <code>VFSBrowser.getActionContext()</code>.
0449: * @param name The name of the button
0450: * @since jEdit 4.2pre1
0451: */
0452: public static EnhancedButton loadToolButton(ActionContext context,
0453: String name) {
0454: String label = jEdit.getProperty(name + ".label");
0455:
0456: if (label == null)
0457: label = name;
0458:
0459: Icon icon;
0460: String iconName = jEdit.getProperty(name + ".icon");
0461: if (iconName == null)
0462: icon = loadIcon("BrokenImage.png");
0463: else {
0464: icon = loadIcon(iconName);
0465: if (icon == null)
0466: icon = loadIcon("BrokenImage.png");
0467: }
0468:
0469: String toolTip = prettifyMenuLabel(label);
0470: String shortcutLabel = getShortcutLabel(name);
0471: if (shortcutLabel != null) {
0472: toolTip = toolTip + " (" + shortcutLabel + ')';
0473: }
0474:
0475: return new EnhancedButton(icon, toolTip, name, context);
0476: } //}}}
0477:
0478: //{{{ prettifyMenuLabel() method
0479: /**
0480: * `Prettifies' a menu item label by removing the `$' sign. This
0481: * can be used to process the contents of an <i>action</i>.label
0482: * property.
0483: */
0484: public static String prettifyMenuLabel(String label) {
0485: int index = label.indexOf('$');
0486: if (index != -1) {
0487: label = label.substring(0, index).concat(
0488: label.substring(index + 1));
0489: }
0490: return label;
0491: } //}}}
0492:
0493: //{{{ getShortcutLabel() method
0494: /**
0495: * Returns a label string to show users what shortcut are
0496: * assigned to the action.
0497: */
0498: public static String getShortcutLabel(String action) {
0499: if (action == null)
0500: return null;
0501: else {
0502: String shortcut1 = jEdit.getProperty(action + ".shortcut");
0503: String shortcut2 = jEdit.getProperty(action + ".shortcut2");
0504:
0505: if (shortcut1 == null || shortcut1.length() == 0) {
0506: if (shortcut2 == null || shortcut2.length() == 0)
0507: return null;
0508: else
0509: return shortcut2;
0510: } else {
0511: if (shortcut2 == null || shortcut2.length() == 0)
0512: return shortcut1;
0513: else
0514: return shortcut1 + " or " + shortcut2;
0515: }
0516: }
0517: } //}}}
0518:
0519: //}}}
0520:
0521: //{{{ Canned dialog boxes
0522:
0523: //{{{ message() method
0524: /**
0525: * Displays a dialog box.
0526: * The title of the dialog is fetched from
0527: * the <code><i>name</i>.title</code> property. The message is fetched
0528: * from the <code><i>name</i>.message</code> property. The message
0529: * is formatted by the property manager with <code>args</code> as
0530: * positional parameters.
0531: * @param comp The component to display the dialog for
0532: * @param name The name of the dialog
0533: * @param args Positional parameters to be substituted into the
0534: * message text
0535: */
0536: public static void message(Component comp, String name,
0537: Object[] args) {
0538: hideSplashScreen();
0539:
0540: JOptionPane.showMessageDialog(comp, jEdit.getProperty(name
0541: .concat(".message"), args), jEdit.getProperty(name
0542: .concat(".title"), args),
0543: JOptionPane.INFORMATION_MESSAGE);
0544: } //}}}
0545:
0546: //{{{ error() method
0547: /**
0548: * Displays an error dialog box.
0549: * The title of the dialog is fetched from
0550: * the <code><i>name</i>.title</code> property. The message is fetched
0551: * from the <code><i>name</i>.message</code> property. The message
0552: * is formatted by the property manager with <code>args</code> as
0553: * positional parameters.
0554: * @param comp The component to display the dialog for
0555: * @param name The name of the dialog
0556: * @param args Positional parameters to be substituted into the
0557: * message text
0558: */
0559: public static void error(Component comp, String name, Object[] args) {
0560: hideSplashScreen();
0561:
0562: JOptionPane.showMessageDialog(comp, jEdit.getProperty(name
0563: .concat(".message"), args), jEdit.getProperty(name
0564: .concat(".title"), args), JOptionPane.ERROR_MESSAGE);
0565: } //}}}
0566:
0567: //{{{ input() method
0568: /**
0569: * Displays an input dialog box and returns any text the user entered.
0570: * The title of the dialog is fetched from
0571: * the <code><i>name</i>.title</code> property. The message is fetched
0572: * from the <code><i>name</i>.message</code> property.
0573: * @param comp The component to display the dialog for
0574: * @param name The name of the dialog
0575: * @param def The text to display by default in the input field
0576: */
0577: public static String input(Component comp, String name, Object def) {
0578: return input(comp, name, null, def);
0579: } //}}}
0580:
0581: //{{{ inputProperty() method
0582: /**
0583: * Displays an input dialog box and returns any text the user entered.
0584: * The title of the dialog is fetched from
0585: * the <code><i>name</i>.title</code> property. The message is fetched
0586: * from the <code><i>name</i>.message</code> property.
0587: * @param comp The component to display the dialog for
0588: * @param name The name of the dialog
0589: * @param def The property whose text to display in the input field
0590: */
0591: public static String inputProperty(Component comp, String name,
0592: String def) {
0593: return inputProperty(comp, name, null, def);
0594: } //}}}
0595:
0596: //{{{ input() method
0597: /**
0598: * Displays an input dialog box and returns any text the user entered.
0599: * The title of the dialog is fetched from
0600: * the <code><i>name</i>.title</code> property. The message is fetched
0601: * from the <code><i>name</i>.message</code> property.
0602: * @param comp The component to display the dialog for
0603: * @param name The name of the dialog
0604: * @param def The text to display by default in the input field
0605: * @param args Positional parameters to be substituted into the
0606: * message text
0607: * @since jEdit 3.1pre3
0608: */
0609: public static String input(Component comp, String name,
0610: Object[] args, Object def) {
0611: hideSplashScreen();
0612:
0613: String retVal = (String) JOptionPane.showInputDialog(comp,
0614: jEdit.getProperty(name.concat(".message"), args), jEdit
0615: .getProperty(name.concat(".title")),
0616: JOptionPane.QUESTION_MESSAGE, null, null, def);
0617: return retVal;
0618: } //}}}
0619:
0620: //{{{ inputProperty() method
0621: /**
0622: * Displays an input dialog box and returns any text the user entered.
0623: * The title of the dialog is fetched from
0624: * the <code><i>name</i>.title</code> property. The message is fetched
0625: * from the <code><i>name</i>.message</code> property.
0626: * @param comp The component to display the dialog for
0627: * @param name The name of the dialog
0628: * @param args Positional parameters to be substituted into the
0629: * message text
0630: * @param def The property whose text to display in the input field
0631: * @since jEdit 3.1pre3
0632: */
0633: public static String inputProperty(Component comp, String name,
0634: Object[] args, String def) {
0635: hideSplashScreen();
0636:
0637: String retVal = (String) JOptionPane.showInputDialog(comp,
0638: jEdit.getProperty(name.concat(".message"), args), jEdit
0639: .getProperty(name.concat(".title")),
0640: JOptionPane.QUESTION_MESSAGE, null, null, jEdit
0641: .getProperty(def));
0642: if (retVal != null)
0643: jEdit.setProperty(def, retVal);
0644: return retVal;
0645: } //}}}
0646:
0647: //{{{ confirm() method
0648: /**
0649: * Displays a confirm dialog box and returns the button pushed by the
0650: * user. The title of the dialog is fetched from the
0651: * <code><i>name</i>.title</code> property. The message is fetched
0652: * from the <code><i>name</i>.message</code> property.
0653: * @param comp The component to display the dialog for
0654: * @param name The name of the dialog
0655: * @param args Positional parameters to be substituted into the
0656: * message text
0657: * @param buttons The buttons to display - for example,
0658: * JOptionPane.YES_NO_CANCEL_OPTION
0659: * @param type The dialog type - for example,
0660: * JOptionPane.WARNING_MESSAGE
0661: * @since jEdit 3.1pre3
0662: */
0663: public static int confirm(Component comp, String name,
0664: Object[] args, int buttons, int type) {
0665: hideSplashScreen();
0666:
0667: return JOptionPane.showConfirmDialog(comp, jEdit.getProperty(
0668: name + ".message", args), jEdit.getProperty(name
0669: + ".title"), buttons, type);
0670: } //}}}
0671:
0672: //{{{ listConfirm() method
0673: /**
0674: * Displays a confirm dialog box and returns the button pushed by the
0675: * user. The title of the dialog is fetched from the
0676: * <code><i>name</i>.title</code> property. The message is fetched
0677: * from the <code><i>name</i>.message</code> property. The dialog
0678: * also shows a list of entries given by the <code>listModel</code>
0679: * parameter.
0680: * @param comp the parent component
0681: * @param name the name of the confirm dialog
0682: * @param args the for the message
0683: * @param listModel the items in the list
0684: * @return an integer indicating the option selected by the user
0685: * @since jEdit 4.3pre1
0686: */
0687: public static int listConfirm(Component comp, String name,
0688: String[] args, Object[] listModel) {
0689: JList list = new JList(listModel);
0690: list.setVisibleRowCount(8);
0691:
0692: Object[] message = {
0693: jEdit.getProperty(name + ".message", args),
0694: new JScrollPane(list) };
0695:
0696: return JOptionPane
0697: .showConfirmDialog(comp, message, jEdit
0698: .getProperty(name + ".title"),
0699: JOptionPane.YES_NO_OPTION,
0700: JOptionPane.QUESTION_MESSAGE);
0701: } //}}}
0702:
0703: //{{{ listConfirm() method
0704: /**
0705: * Displays a confirm dialog box and returns the button pushed by the
0706: * user. The title of the dialog is fetched from the
0707: * <code><i>name</i>.title</code> property. The message is fetched
0708: * from the <code><i>name</i>.message</code> property. The dialog
0709: * also shows a list of entries given by the <code>listModel</code>
0710: * parameter.
0711: * @param comp the parent component
0712: * @param name the name of the confirm dialog
0713: * @param args the for the message
0714: * @param listModel the items in the list
0715: * @param selectedItems give an empty list, it will contains in return the selected items
0716: * @return an integer indicating the option selected by the user
0717: * @since jEdit 4.3pre12
0718: */
0719: public static int listConfirm(Component comp, String name,
0720: String[] args, Object[] listModel, List selectedItems) {
0721: JList list = new JList(listModel);
0722: list
0723: .setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
0724: list.setVisibleRowCount(8);
0725: list.addSelectionInterval(0, listModel.length - 1);
0726:
0727: Object[] message = {
0728: jEdit.getProperty(name + ".message", args),
0729: new JScrollPane(list) };
0730:
0731: int ret = JOptionPane
0732: .showConfirmDialog(comp, message, jEdit
0733: .getProperty(name + ".title"),
0734: JOptionPane.YES_NO_OPTION,
0735: JOptionPane.QUESTION_MESSAGE);
0736: Object[] selectedValues = list.getSelectedValues();
0737: for (Object selectedValue : selectedValues) {
0738: selectedItems.add(selectedValue);
0739: }
0740: return ret;
0741: } //}}}
0742:
0743: //{{{ showVFSFileDialog() methods
0744: /**
0745: * Displays a VFS file selection dialog box.
0746: * @param view The view, should be non-null
0747: * @param path The initial directory to display. May be null
0748: * @param type The dialog type. One of
0749: * {@link org.gjt.sp.jedit.browser.VFSBrowser#OPEN_DIALOG},
0750: * {@link org.gjt.sp.jedit.browser.VFSBrowser#SAVE_DIALOG}, or
0751: * {@link org.gjt.sp.jedit.browser.VFSBrowser#CHOOSE_DIRECTORY_DIALOG}.
0752: * @param multipleSelection True if multiple selection should be allowed
0753: * @return The selected file(s)
0754: * @since jEdit 2.6pre2
0755: */
0756: public static String[] showVFSFileDialog(View view, String path,
0757: int type, boolean multipleSelection) {
0758: // the view should not be null, but some plugins might do this
0759: if (view == null) {
0760: Log
0761: .log(Log.WARNING, GUIUtilities.class,
0762: "showVFSFileDialog(): given null view, assuming jEdit.getActiveView()");
0763: view = jEdit.getActiveView();
0764: }
0765:
0766: hideSplashScreen();
0767:
0768: VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
0769: view, path, type, multipleSelection);
0770: return fileChooser.getSelectedFiles();
0771: }
0772:
0773: /**
0774: * Displays a VFS file selection dialog box.
0775: * This version can specify a dialog as the parent instead
0776: * of the view.
0777: * @param view The view, should be non-null
0778: * @param path The initial directory to display. May be null
0779: * @param type The dialog type. One of
0780: * {@link org.gjt.sp.jedit.browser.VFSBrowser#OPEN_DIALOG},
0781: * {@link org.gjt.sp.jedit.browser.VFSBrowser#SAVE_DIALOG}, or
0782: * {@link org.gjt.sp.jedit.browser.VFSBrowser#CHOOSE_DIRECTORY_DIALOG}.
0783: * @param multipleSelection True if multiple selection should be allowed
0784: * @return The selected file(s)
0785: * @since jEdit 4.3pre10
0786: */
0787: public static String[] showVFSFileDialog(Dialog parent, View view,
0788: String path, int type, boolean multipleSelection) {
0789: hideSplashScreen();
0790:
0791: VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
0792: parent, view, path, type, multipleSelection, true);
0793: return fileChooser.getSelectedFiles();
0794: }
0795:
0796: /**
0797: * Displays a VFS file selection dialog box.
0798: * This version can specify a frame as the parent instead
0799: * of the view.
0800: * @param parent The parent frame
0801: * @param view The view, should be non-null
0802: * @param path The initial directory to display. May be null
0803: * @param type The dialog type. One of
0804: * {@link org.gjt.sp.jedit.browser.VFSBrowser#OPEN_DIALOG},
0805: * {@link org.gjt.sp.jedit.browser.VFSBrowser#SAVE_DIALOG}, or
0806: * {@link org.gjt.sp.jedit.browser.VFSBrowser#CHOOSE_DIRECTORY_DIALOG}.
0807: * @param multipleSelection True if multiple selection should be allowed
0808: * @return The selected file(s)
0809: * @since jEdit 4.3pre10
0810: */
0811: public static String[] showVFSFileDialog(Frame parent, View view,
0812: String path, int type, boolean multipleSelection) {
0813: hideSplashScreen();
0814: VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
0815: parent, view, path, type, multipleSelection, true);
0816: return fileChooser.getSelectedFiles();
0817: } //}}}
0818:
0819: //}}}
0820:
0821: //{{{ Colors and styles
0822:
0823: //{{{ parseColor() method
0824: /**
0825: * Converts a color name to a color object. The name must either be
0826: * a known string, such as `red', `green', etc (complete list is in
0827: * the <code>java.awt.Color</code> class) or a hex color value
0828: * prefixed with `#', for example `#ff0088'.
0829: * @param name The color name
0830: */
0831: public static Color parseColor(String name) {
0832: return parseColor(name, Color.black);
0833: } //}}}
0834:
0835: //{{{ parseColor() method
0836: public static Color parseColor(String name, Color defaultColor) {
0837: if (name == null || name.length() == 0)
0838: return defaultColor;
0839: else if (name.charAt(0) == '#') {
0840: try {
0841: return Color.decode(name);
0842: } catch (NumberFormatException nf) {
0843: return defaultColor;
0844: }
0845: } else if ("red".equals(name))
0846: return Color.red;
0847: else if ("green".equals(name))
0848: return Color.green;
0849: else if ("blue".equals(name))
0850: return Color.blue;
0851: else if ("yellow".equals(name))
0852: return Color.yellow;
0853: else if ("orange".equals(name))
0854: return Color.orange;
0855: else if ("white".equals(name))
0856: return Color.white;
0857: else if ("lightGray".equals(name))
0858: return Color.lightGray;
0859: else if ("gray".equals(name))
0860: return Color.gray;
0861: else if ("darkGray".equals(name))
0862: return Color.darkGray;
0863: else if ("black".equals(name))
0864: return Color.black;
0865: else if ("cyan".equals(name))
0866: return Color.cyan;
0867: else if ("magenta".equals(name))
0868: return Color.magenta;
0869: else if ("pink".equals(name))
0870: return Color.pink;
0871: else
0872: return defaultColor;
0873: } //}}}
0874:
0875: //{{{ getColorHexString() method
0876: /**
0877: * Converts a color object to its hex value. The hex value
0878: * prefixed is with `#', for example `#ff0088'.
0879: * @param c The color object
0880: */
0881: public static String getColorHexString(Color c) {
0882: String colString = Integer.toHexString(c.getRGB() & 0xffffff);
0883: return "#000000".substring(0, 7 - colString.length()).concat(
0884: colString);
0885: } //}}}
0886:
0887: //{{{ parseStyle() method
0888: /**
0889: * Converts a style string to a style object.
0890: * @param str The style string
0891: * @param family Style strings only specify font style, not font family
0892: * @param size Style strings only specify font style, not font family
0893: * @exception IllegalArgumentException if the style is invalid
0894: * @since jEdit 3.2pre6
0895: */
0896: public static SyntaxStyle parseStyle(String str, String family,
0897: int size) throws IllegalArgumentException {
0898: return parseStyle(str, family, size, true);
0899: } //}}}
0900:
0901: //{{{ parseStyle() method
0902: /**
0903: * Converts a style string to a style object.
0904: * @param str The style string
0905: * @param family Style strings only specify font style, not font family
0906: * @param size Style strings only specify font style, not font family
0907: * @param color If false, the styles will be monochrome
0908: * @exception IllegalArgumentException if the style is invalid
0909: * @since jEdit 4.0pre4
0910: */
0911: public static SyntaxStyle parseStyle(String str, String family,
0912: int size, boolean color) throws IllegalArgumentException {
0913: Color fgColor = Color.black;
0914: Color bgColor = null;
0915: boolean italic = false;
0916: boolean bold = false;
0917: StringTokenizer st = new StringTokenizer(str);
0918: while (st.hasMoreTokens()) {
0919: String s = st.nextToken();
0920: if (s.startsWith("color:")) {
0921: if (color)
0922: fgColor = GUIUtilities.parseColor(s.substring(6),
0923: Color.black);
0924: } else if (s.startsWith("bgColor:")) {
0925: if (color)
0926: bgColor = GUIUtilities.parseColor(s.substring(8),
0927: null);
0928: } else if (s.startsWith("style:")) {
0929: for (int i = 6; i < s.length(); i++) {
0930: if (s.charAt(i) == 'i')
0931: italic = true;
0932: else if (s.charAt(i) == 'b')
0933: bold = true;
0934: else
0935: throw new IllegalArgumentException(
0936: "Invalid style: " + s);
0937: }
0938: } else
0939: throw new IllegalArgumentException(
0940: "Invalid directive: " + s);
0941: }
0942: return new SyntaxStyle(fgColor, bgColor, new Font(family,
0943: (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0),
0944: size));
0945: } //}}}
0946:
0947: //{{{ getStyleString() method
0948: /**
0949: * Converts a style into it's string representation.
0950: * @param style The style
0951: */
0952: public static String getStyleString(SyntaxStyle style) {
0953: StringBuilder buf = new StringBuilder();
0954:
0955: if (style.getForegroundColor() != null) {
0956: buf.append("color:").append(
0957: getColorHexString(style.getForegroundColor()));
0958: }
0959:
0960: if (style.getBackgroundColor() != null) {
0961: buf.append(" bgColor:").append(
0962: getColorHexString(style.getBackgroundColor()));
0963: }
0964:
0965: Font font = style.getFont();
0966: if (!font.isPlain()) {
0967: buf.append(" style:");
0968: if (font.isItalic())
0969: buf.append('i');
0970: if (font.isBold())
0971: buf.append('b');
0972: }
0973:
0974: return buf.toString();
0975: } //}}}
0976:
0977: //{{{ loadStyles() method
0978: /**
0979: * Loads the syntax styles from the properties, giving them the specified
0980: * base font family and size.
0981: * @param family The font family
0982: * @param size The font size
0983: * @since jEdit 3.2pre6
0984: */
0985: public static SyntaxStyle[] loadStyles(String family, int size) {
0986: return loadStyles(family, size, true);
0987: } //}}}
0988:
0989: //{{{ loadStyles() method
0990: /**
0991: * Loads the syntax styles from the properties, giving them the specified
0992: * base font family and size.
0993: * @param family The font family
0994: * @param size The font size
0995: * @param color If false, the styles will be monochrome
0996: * @since jEdit 4.0pre4
0997: */
0998: public static SyntaxStyle[] loadStyles(String family, int size,
0999: boolean color) {
1000: SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
1001:
1002: // start at 1 not 0 to skip Token.NULL
1003: for (int i = 1; i < styles.length; i++) {
1004: try {
1005: String styleName = "view.style."
1006: + Token.tokenToString((byte) i).toLowerCase(
1007: Locale.ENGLISH);
1008: styles[i] = GUIUtilities.parseStyle(jEdit
1009: .getProperty(styleName), family, size, color);
1010: } catch (Exception e) {
1011: Log.log(Log.ERROR, GUIUtilities.class, e);
1012: }
1013: }
1014:
1015: return styles;
1016: } //}}}
1017:
1018: //}}}
1019:
1020: //{{{ Loading, saving window geometry
1021:
1022: //{{{ loadGeometry() method
1023: /**
1024: * Loads a windows's geometry from the properties.
1025: * The geometry is loaded from the <code><i>name</i>.x</code>,
1026: * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
1027: * <code><i>name</i>.height</code> properties.
1028: *
1029: * @param win The window to load geometry from
1030: * @param parent The parent frame to be relative to.
1031: * @param name The name of the window
1032: */
1033: public static void loadGeometry(Window win, Container parent,
1034: String name) {
1035: int x, y, width, height;
1036:
1037: Dimension size = win.getSize();
1038: width = jEdit.getIntegerProperty(name + ".width", size.width);
1039: height = jEdit
1040: .getIntegerProperty(name + ".height", size.height);
1041: x = jEdit.getIntegerProperty(name + ".x", 50);
1042: y = jEdit.getIntegerProperty(name + ".y", 50);
1043: if (parent != null) {
1044: Point location = parent.getLocation();
1045: x = location.x + x;
1046: y = location.y + y;
1047: }
1048:
1049: int extState = jEdit.getIntegerProperty(
1050: name + ".extendedState", Frame.NORMAL);
1051:
1052: Rectangle desired = new Rectangle(x, y, width, height);
1053: try {
1054: if (!Debug.DISABLE_MULTIHEAD)
1055: adjustForScreenBounds(desired);
1056: } catch (Exception e) {
1057: /* Workaround for OS X bug. */
1058: Log.log(Log.ERROR, GUIUtilities.class, e);
1059: }
1060:
1061: if (OperatingSystem.isX11() && Debug.GEOMETRY_WORKAROUND)
1062: new UnixWorkaround(win, name, desired, extState);
1063: else {
1064: win.setBounds(desired);
1065: if (win instanceof Frame)
1066: ((Frame) win).setExtendedState(extState);
1067: }
1068:
1069: } //}}}
1070:
1071: //{{{ loadGeometry() method
1072: /**
1073: * Loads a windows's geometry from the properties.
1074: * The geometry is loaded from the <code><i>name</i>.x</code>,
1075: * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
1076: * <code><i>name</i>.height</code> properties.
1077: *
1078: * @param win The window to load geometry from
1079: * @param name The name of the window
1080: */
1081: public static void loadGeometry(Window win, String name) {
1082: loadGeometry(win, win.getParent(), name);
1083: } //}}}
1084:
1085: //{{{ adjustForScreenBounds() method
1086: /**
1087: * Gives a rectangle the specified bounds, ensuring it is within the
1088: * screen bounds.
1089: * @since jEdit 4.2pre3
1090: */
1091: public static void adjustForScreenBounds(Rectangle desired) {
1092: // Make sure the window is displayed in visible region
1093: Rectangle osbounds = OperatingSystem.getScreenBounds(desired);
1094:
1095: if (desired.x < osbounds.x
1096: || desired.x + desired.width > desired.x
1097: + osbounds.width) {
1098: if (desired.width > osbounds.width)
1099: desired.width = osbounds.width;
1100: desired.x = (osbounds.width - desired.width) / 2;
1101: }
1102: if (desired.y < osbounds.y
1103: || desired.y + desired.height > osbounds.y
1104: + osbounds.height) {
1105: if (desired.height >= osbounds.height)
1106: desired.height = osbounds.height;
1107: desired.y = (osbounds.height - desired.height) / 2;
1108: }
1109: } //}}}
1110:
1111: //{{{ UnixWorkaround class
1112: static class UnixWorkaround {
1113: Window win;
1114: String name;
1115: Rectangle desired;
1116: Rectangle required;
1117: long start;
1118: boolean windowOpened;
1119:
1120: //{{{ UnixWorkaround constructor
1121: UnixWorkaround(Window win, String name, Rectangle desired,
1122: int extState) {
1123: this .win = win;
1124: this .name = name;
1125: this .desired = desired;
1126:
1127: int adjust_x, adjust_y, adjust_width, adjust_height;
1128: adjust_x = jEdit.getIntegerProperty(name + ".dx", 0);
1129: adjust_y = jEdit.getIntegerProperty(name + ".dy", 0);
1130: adjust_width = jEdit.getIntegerProperty(name + ".d-width",
1131: 0);
1132: adjust_height = jEdit.getIntegerProperty(
1133: name + ".d-height", 0);
1134:
1135: required = new Rectangle(desired.x - adjust_x, desired.y
1136: - adjust_y, desired.width - adjust_width,
1137: desired.height - adjust_height);
1138:
1139: Log.log(Log.DEBUG, GUIUtilities.class, "Window " + name
1140: + ": desired geometry is " + desired);
1141: Log.log(Log.DEBUG, GUIUtilities.class, "Window " + name
1142: + ": setting geometry to " + required);
1143:
1144: start = System.currentTimeMillis();
1145:
1146: win.setBounds(required);
1147: if (win instanceof Frame)
1148: ((Frame) win).setExtendedState(extState);
1149:
1150: win.addComponentListener(new ComponentHandler());
1151: win.addWindowListener(new WindowHandler());
1152: } //}}}
1153:
1154: //{{{ ComponentHandler class
1155: class ComponentHandler extends ComponentAdapter {
1156: //{{{ componentMoved() method
1157: public void componentMoved(ComponentEvent evt) {
1158: if (System.currentTimeMillis() - start < 1000L) {
1159: Rectangle r = win.getBounds();
1160: if (!windowOpened && r.equals(required))
1161: return;
1162:
1163: if (!r.equals(desired)) {
1164: Log.log(Log.DEBUG, GUIUtilities.class,
1165: "Window resize blocked: "
1166: + win.getBounds());
1167: win.setBounds(desired);
1168: }
1169: }
1170:
1171: win.removeComponentListener(this );
1172: } //}}}
1173:
1174: //{{{ componentResized() method
1175: public void componentResized(ComponentEvent evt) {
1176: if (System.currentTimeMillis() - start < 1000L) {
1177: Rectangle r = win.getBounds();
1178: if (!windowOpened && r.equals(required))
1179: return;
1180:
1181: if (!r.equals(desired)) {
1182: Log.log(Log.DEBUG, GUIUtilities.class,
1183: "Window resize blocked: "
1184: + win.getBounds());
1185: win.setBounds(desired);
1186: }
1187: }
1188:
1189: win.removeComponentListener(this );
1190: } //}}}
1191: } //}}}
1192:
1193: //{{{ WindowHandler class
1194: class WindowHandler extends WindowAdapter {
1195: //{{{ windowOpened() method
1196: public void windowOpened(WindowEvent evt) {
1197: windowOpened = true;
1198:
1199: Rectangle r = win.getBounds();
1200: Log.log(Log.DEBUG, GUIUtilities.class, "Window " + name
1201: + ": bounds after opening: " + r);
1202:
1203: jEdit
1204: .setIntegerProperty(name + ".dx", r.x
1205: - required.x);
1206: jEdit
1207: .setIntegerProperty(name + ".dy", r.y
1208: - required.y);
1209: jEdit.setIntegerProperty(name + ".d-width", r.width
1210: - required.width);
1211: jEdit.setIntegerProperty(name + ".d-height", r.height
1212: - required.height);
1213:
1214: win.removeWindowListener(this );
1215: } //}}}
1216: } //}}}
1217: } //}}}
1218:
1219: //{{{ saveGeometry() method
1220: /**
1221: * Saves a window's geometry to the properties.
1222: * The geometry is saved to the <code><i>name</i>.x</code>,
1223: * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
1224: * <code><i>name</i>.height</code> properties.<br />
1225: * For Frame's and descendents use {@link #addSizeSaver(Frame,String)} to save the sizes
1226: * correct even if the Frame is in maximized or iconified state.
1227: * @param win The window to load geometry from
1228: * @param name The name of the window
1229: * @see #addSizeSaver(Frame,String)
1230: */
1231: public static void saveGeometry(Window win, String name) {
1232: saveGeometry(win, win.getParent(), name);
1233: } //}}}
1234:
1235: //{{{ saveGeometry() method
1236: /**
1237: * Saves a window's geometry to the properties.
1238: * The geometry is saved to the <code><i>name</i>.x</code>,
1239: * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
1240: * <code><i>name</i>.height</code> properties.<br />
1241: * For Frame's and descendents use {@link #addSizeSaver(Frame,Container,String)} to save the sizes
1242: * correct even if the Frame is in maximized or iconified state.
1243: * @param win The window to load geometry from
1244: * @param parent The parent frame to be relative to.
1245: * @param name The name of the window
1246: * @see #addSizeSaver(Frame,Container,String)
1247: */
1248: public static void saveGeometry(Window win, Container parent,
1249: String name) {
1250: if (win instanceof Frame) {
1251: jEdit.setIntegerProperty(name + ".extendedState",
1252: ((Frame) win).getExtendedState());
1253: }
1254:
1255: Rectangle bounds = win.getBounds();
1256: int x = bounds.x;
1257: int y = bounds.y;
1258: if (parent != null) {
1259: Rectangle parentBounds = parent.getBounds();
1260: x = x - parentBounds.x;
1261: y = y - parentBounds.y;
1262: }
1263: jEdit.setIntegerProperty(name + ".x", x);
1264: jEdit.setIntegerProperty(name + ".y", y);
1265: jEdit.setIntegerProperty(name + ".width", bounds.width);
1266: jEdit.setIntegerProperty(name + ".height", bounds.height);
1267: } //}}}
1268:
1269: //{{{ centerOnScreen() method
1270: /**
1271: * Centers the given window on the screen. This method is needed because
1272: * JDK 1.3 does not have a <code>JWindow.setLocationRelativeTo()</code>
1273: * method.
1274: * @since jEdit 4.2pre3
1275: * @deprecated use {@link javax.swing.JWindow#setLocationRelativeTo(java.awt.Component)}
1276: */
1277: @Deprecated
1278: public static void centerOnScreen(Window win) {
1279: GraphicsDevice gd = GraphicsEnvironment
1280: .getLocalGraphicsEnvironment().getDefaultScreenDevice();
1281: Rectangle gcbounds = gd.getDefaultConfiguration().getBounds();
1282: int x = gcbounds.x + (gcbounds.width - win.getWidth()) / 2;
1283: int y = gcbounds.y + (gcbounds.height - win.getHeight()) / 2;
1284: win.setLocation(x, y);
1285: } //}}}
1286:
1287: //}}}
1288:
1289: //{{{ hideSplashScreen() method
1290: /**
1291: * Ensures that the splash screen is not visible. This should be
1292: * called before displaying any dialog boxes or windows at
1293: * startup.
1294: */
1295: public static void hideSplashScreen() {
1296: if (splash != null) {
1297: splash.dispose();
1298: splash = null;
1299: }
1300: } //}}}
1301:
1302: //{{{ createMultilineLabel() method
1303: /**
1304: * Creates a component that displays a multiple line message. This
1305: * is implemented by assembling a number of <code>JLabels</code> in
1306: * a <code>JPanel</code>.
1307: * @param str The string, with lines delimited by newline
1308: * (<code>\n</code>) characters.
1309: * @since jEdit 4.1pre3
1310: */
1311: public static JComponent createMultilineLabel(String str) {
1312: JPanel panel = new JPanel(new VariableGridLayout(
1313: VariableGridLayout.FIXED_NUM_COLUMNS, 1, 1, 1));
1314: int lastOffset = 0;
1315: while (true) {
1316: int index = str.indexOf('\n', lastOffset);
1317: if (index == -1)
1318: break;
1319: else {
1320: panel.add(new JLabel(str.substring(lastOffset, index)));
1321: lastOffset = index + 1;
1322: }
1323: }
1324:
1325: if (lastOffset != str.length())
1326: panel.add(new JLabel(str.substring(lastOffset)));
1327:
1328: return panel;
1329: } //}}}
1330:
1331: //{{{ requestFocus() method
1332: /**
1333: * Focuses on the specified component as soon as the window becomes
1334: * active.
1335: * @param win The window
1336: * @param comp The component
1337: */
1338: public static void requestFocus(final Window win,
1339: final Component comp) {
1340: win.addWindowFocusListener(new WindowAdapter() {
1341: public void windowGainedFocus(WindowEvent evt) {
1342: SwingUtilities.invokeLater(new Runnable() {
1343: public void run() {
1344: comp.requestFocusInWindow();
1345: }
1346: });
1347: win.removeWindowFocusListener(this );
1348: }
1349: });
1350: } //}}}
1351:
1352: //{{{ isPopupTrigger() method
1353: /**
1354: * Returns if the specified event is the popup trigger event.
1355: * This implements precisely defined behavior, as opposed to
1356: * MouseEvent.isPopupTrigger().
1357: * @param evt The event
1358: * @since jEdit 3.2pre8
1359: */
1360: public static boolean isPopupTrigger(MouseEvent evt) {
1361: return TextAreaMouseHandler.isRightButton(evt.getModifiers());
1362: } //}}}
1363:
1364: //{{{ isMiddleButton() method
1365: /**
1366: * @param modifiers The modifiers flag from a mouse event
1367: * @since jEdit 4.1pre9
1368: */
1369: public static boolean isMiddleButton(int modifiers) {
1370: return TextAreaMouseHandler.isMiddleButton(modifiers);
1371: } //}}}
1372:
1373: //{{{ isRightButton() method
1374: /**
1375: * @param modifiers The modifiers flag from a mouse event
1376: * @since jEdit 4.1pre9
1377: */
1378: public static boolean isRightButton(int modifiers) {
1379: return TextAreaMouseHandler.isRightButton(modifiers);
1380: } //}}}
1381:
1382: //{{{ showPopupMenu() method
1383: /**
1384: * Shows the specified popup menu, ensuring it is displayed within
1385: * the bounds of the screen.
1386: * @param popup The popup menu
1387: * @param comp The component to show it for
1388: * @param x The x co-ordinate
1389: * @param y The y co-ordinate
1390: * @since jEdit 4.0pre1
1391: * @see {@link javax.swing.JComponent#setComponentPopupMenu(javax.swing.JPopupMenu)},
1392: * which works better and is simpler to use: you don't have to write the code to
1393: * show/hide popups in response to mouse events anymore.
1394: */
1395: public static void showPopupMenu(JPopupMenu popup, Component comp,
1396: int x, int y) {
1397: showPopupMenu(popup, comp, x, y, true);
1398: } //}}}
1399:
1400: //{{{ showPopupMenu() method
1401: /**
1402: * Shows the specified popup menu, ensuring it is displayed within
1403: * the bounds of the screen.
1404: * @param popup The popup menu
1405: * @param comp The component to show it for
1406: * @param x The x co-ordinate
1407: * @param y The y co-ordinate
1408: * @param point If true, then the popup originates from a single point;
1409: * otherwise it will originate from the component itself. This affects
1410: * positioning in the case where the popup does not fit onscreen.
1411: *
1412: * @since jEdit 4.1pre1
1413: */
1414: public static void showPopupMenu(JPopupMenu popup, Component comp,
1415: int x, int y, boolean point) {
1416: int offsetX = 0;
1417: int offsetY = 0;
1418:
1419: int extraOffset = (point ? 1 : 0);
1420:
1421: Component win = comp;
1422: while (!(win instanceof Window || win == null)) {
1423: offsetX += win.getX();
1424: offsetY += win.getY();
1425: win = win.getParent();
1426: }
1427:
1428: if (win != null) {
1429: Dimension size = popup.getPreferredSize();
1430:
1431: Rectangle screenSize = new Rectangle();
1432:
1433: GraphicsEnvironment ge = GraphicsEnvironment
1434: .getLocalGraphicsEnvironment();
1435:
1436: GraphicsDevice[] devices = ge.getScreenDevices();
1437:
1438: for (int j = 0; j < devices.length; j++) {
1439: GraphicsDevice device = devices[j];
1440:
1441: GraphicsConfiguration[] gc = device.getConfigurations();
1442:
1443: for (int i = 0; i < gc.length; i++) {
1444: screenSize = screenSize.union(gc[i].getBounds());
1445: }
1446: }
1447:
1448: if (x + offsetX + size.width + win.getX() > screenSize.width
1449: && x + offsetX + win.getX() >= size.width) {
1450: //System.err.println("x overflow");
1451: if (point)
1452: x -= (size.width + extraOffset);
1453: else
1454: x = (win.getWidth() - size.width - offsetX + extraOffset);
1455: } else {
1456: x += extraOffset;
1457: }
1458:
1459: //System.err.println("y=" + y + ",offsetY=" + offsetY
1460: // + ",size.height=" + size.height
1461: // + ",win.height=" + win.getHeight());
1462: if (y + offsetY + size.height + win.getY() > screenSize.height
1463: && y + offsetY + win.getY() >= size.height) {
1464: if (point)
1465: y = (win.getHeight() - size.height - offsetY + extraOffset);
1466: else
1467: y = -size.height - 1;
1468: } else {
1469: y += extraOffset;
1470: }
1471:
1472: popup.show(comp, x, y);
1473: } else
1474: popup.show(comp, x + extraOffset, y + extraOffset);
1475:
1476: } //}}}
1477:
1478: //{{{ isAncestorOf() method
1479: /**
1480: * Returns if the first component is an ancestor of the
1481: * second by traversing up the component hierarchy.
1482: *
1483: * @param comp1 The ancestor
1484: * @param comp2 The component to check
1485: * @since jEdit 4.1pre5
1486: */
1487: public static boolean isAncestorOf(Component comp1, Component comp2) {
1488: while (comp2 != null) {
1489: if (comp1 == comp2)
1490: return true;
1491: else
1492: comp2 = comp2.getParent();
1493: }
1494:
1495: return false;
1496: } //}}}
1497:
1498: //{{{ getParentDialog() method
1499: /**
1500: * Traverses the given component's parent tree looking for an
1501: * instance of JDialog, and return it. If not found, return null.
1502: * @param c The component
1503: */
1504: public static JDialog getParentDialog(Component c) {
1505: return (JDialog) SwingUtilities.getAncestorOfClass(
1506: JDialog.class, c);
1507: } //}}}
1508:
1509: //{{{ getComponentParent() method
1510: /**
1511: * Finds a parent of the specified component.
1512: * @param comp The component
1513: * @param clazz Looks for a parent with this class (exact match, not
1514: * derived).
1515: * @since jEdit 4.2pre1
1516: */
1517: public static Component getComponentParent(Component comp,
1518: Class clazz) {
1519: while (true) {
1520: if (comp == null)
1521: break;
1522:
1523: if (comp instanceof JComponent) {
1524: Component real = (Component) ((JComponent) comp)
1525: .getClientProperty("KORTE_REAL_FRAME");
1526: if (real != null)
1527: comp = real;
1528: }
1529:
1530: if (comp.getClass().equals(clazz))
1531: return comp;
1532: else if (comp instanceof JPopupMenu)
1533: comp = ((JPopupMenu) comp).getInvoker();
1534: else if (comp instanceof FloatingWindowContainer) {
1535: comp = ((FloatingWindowContainer) comp)
1536: .getDockableWindowManager();
1537: } else
1538: comp = comp.getParent();
1539: }
1540: return null;
1541: } //}}}
1542:
1543: //{{{ getView() method
1544: /**
1545: * Finds the view parent of the specified component.
1546: * @since jEdit 4.0pre2
1547: */
1548: public static View getView(Component comp) {
1549: return (View) getComponentParent(comp, View.class);
1550: } //}}}
1551:
1552: //{{{ addSizeSaver() method
1553: /**
1554: * Adds a SizeSaver to the specified Frame. For non-Frame's use {@link #saveGeometry(Window,String)}
1555: *
1556: * @param frame The Frame for which to save the size
1557: * @param name The prefix for the settings
1558: * @since jEdit 4.3pre6
1559: * @see #saveGeometry(Window,String)
1560: */
1561: public static void addSizeSaver(Frame frame, String name) {
1562: addSizeSaver(frame, frame.getParent(), name);
1563: } //}}}
1564:
1565: //{{{ addSizeSaver() method
1566: /**
1567: * Adds a SizeSaver to the specified Frame. For non-Frame's use {@link #saveGeometry(Window,Container,String)}
1568: *
1569: * @param frame The Frame for which to save the size
1570: * @param parent The parent to be relative to
1571: * @param name The prefix for the settings
1572: * @since jEdit 4.3pre7
1573: * @see #saveGeometry(Window,Container,String)
1574: */
1575: public static void addSizeSaver(Frame frame, Container parent,
1576: String name) {
1577: SizeSaver ss = new SizeSaver(frame, parent, name);
1578: frame.addWindowStateListener(ss);
1579: frame.addComponentListener(ss);
1580: } //}}}
1581:
1582: //{{{ initContinuousLayout() method
1583: /**
1584: * Init the continuous layout flag using the jEdit's property
1585: * appearance.continuousLayout
1586: *
1587: * @param split the split. It must never be null
1588: * @since jEdit 4.3pre9
1589: */
1590: public static void initContinuousLayout(JSplitPane split) {
1591: boolean continuousLayout = split.isContinuousLayout();
1592: if (continuousLayout != jEdit
1593: .getBooleanProperty("appearance.continuousLayout"))
1594: split.setContinuousLayout(!continuousLayout);
1595: } //}}}
1596:
1597: //{{{ Package-private members
1598:
1599: //{{{ init() method
1600: static void init() {
1601: // don't do this in static{} since we need jEdit.initMisc()
1602: // run first so we have the jeditresource: protocol
1603: NEW_BUFFER_ICON = loadIcon("new.gif");
1604: DIRTY_BUFFER_ICON = loadIcon("dirty.gif");
1605: READ_ONLY_BUFFER_ICON = loadIcon("readonly.gif");
1606: NORMAL_BUFFER_ICON = loadIcon("normal.gif");
1607: WINDOW_ICON = loadIcon("jedit-icon.gif");
1608: } //}}}
1609:
1610: //{{{ showSplashScreen() method
1611: static void showSplashScreen() {
1612: splash = new SplashScreen();
1613: } //}}}
1614:
1615: //{{{ advanceSplashProgress() method
1616: static void advanceSplashProgress() {
1617: if (splash != null)
1618: splash.advance();
1619: } //}}}
1620:
1621: //{{{ advanceSplashProgress() method
1622: static void advanceSplashProgress(String label) {
1623: if (splash != null)
1624: splash.advance(label);
1625: } //}}}
1626:
1627: //}}}
1628:
1629: //{{{ Private members
1630: private static SplashScreen splash;
1631: private static Map<String, Icon> icons;
1632: private static String iconPath = "jeditresource:/org/gjt/sp/jedit/icons/";
1633: private static String defaultIconPath = "jeditresource:/org/gjt/sp/jedit/icons/";
1634:
1635: private GUIUtilities() {
1636: }
1637:
1638: //}}}
1639:
1640: //{{{ Inner classes
1641:
1642: //{{{ SizeSaver class
1643: /**
1644: * A combined ComponentListener and WindowStateListener to continually save a Frames size.<br />
1645: * For non-Frame's use {@link GUIUtilities#saveGeometry(Window,String)}
1646: *
1647: * @author Björn Kautler
1648: * @version $Id: GUIUtilities.java 11177 2007-12-01 09:50:50Z k_satoda $
1649: * @since jEdit 4.3pre6
1650: * @see GUIUtilities#saveGeometry(Window,Container,String)
1651: */
1652: static class SizeSaver extends ComponentAdapter implements
1653: WindowStateListener {
1654: private Frame frame;
1655: private Container parent;
1656: private String name;
1657:
1658: //{{{ SizeSaver constructor
1659: /**
1660: * Constructs a new SizeSaver.
1661: *
1662: * @param frame The Frame for which to save the size
1663: * @param name The prefix for the settings
1664: */
1665: SizeSaver(Frame frame, String name) {
1666: this .frame = frame;
1667: this .parent = frame.getParent();
1668: } //}}}
1669:
1670: //{{{ SizeSaver constructor
1671: /**
1672: * Constructs a new SizeSaver.
1673: *
1674: * @param frame The Frame for which to save the size
1675: * @param parent The parent to be relative to.
1676: * @param name The prefix for the settings
1677: */
1678: public SizeSaver(Frame frame, Container parent, String name) {
1679: if ((null == frame) || (null == name)) {
1680: throw new NullPointerException();
1681: }
1682: this .frame = frame;
1683: this .parent = parent;
1684: this .name = name;
1685: } //}}}
1686:
1687: //{{{ windowStateChanged() method
1688: public void windowStateChanged(WindowEvent wse) {
1689: int extendedState = wse.getNewState();
1690: jEdit.setIntegerProperty(name + ".extendedState",
1691: extendedState);
1692: Rectangle bounds = frame.getBounds();
1693: save(extendedState, bounds);
1694: } //}}}
1695:
1696: //{{{ save() method
1697: private void save(int extendedState, Rectangle bounds) {
1698: switch (extendedState) {
1699: case Frame.MAXIMIZED_VERT:
1700: jEdit.setIntegerProperty(name + ".x", bounds.x);
1701: jEdit.setIntegerProperty(name + ".width", bounds.width);
1702: break;
1703:
1704: case Frame.MAXIMIZED_HORIZ:
1705: jEdit.setIntegerProperty(name + ".y", bounds.y);
1706: jEdit.setIntegerProperty(name + ".height",
1707: bounds.height);
1708: break;
1709:
1710: case Frame.NORMAL:
1711: saveGeometry(frame, parent, name);
1712: break;
1713: }
1714: } //}}}
1715:
1716: //{{{ componentResized() method
1717: public void componentResized(ComponentEvent ce) {
1718: componentMoved(ce);
1719: } //}}}
1720:
1721: //{{{ componentMoved() method
1722: public void componentMoved(ComponentEvent ce) {
1723: final Rectangle bounds = frame.getBounds();
1724: final Runnable sizeSaver = new Runnable() {
1725: public void run() {
1726: int extendedState = frame.getExtendedState();
1727: save(extendedState, bounds);
1728: }
1729: };
1730: new Thread("Sizesavingdelay") {
1731: public void run() {
1732: try {
1733: Thread.sleep(500L);
1734: } catch (InterruptedException ie) {
1735: }
1736: SwingUtilities.invokeLater(sizeSaver);
1737: }
1738: }.start();
1739: } //}}}
1740: } //}}}
1741:
1742: //}}}
1743: }
|