/jEdit/tags/jedit-4-3-pre10/org/gjt/sp/jedit/GUIUtilities.java

# · Java · 1837 lines · 990 code · 191 blank · 656 comment · 176 complexity · 2ea88b14431a4189f92ddccd75b672cc MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. * GUIUtilities.java - Various GUI utility functions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2004 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit;
  23. //{{{ Imports
  24. import java.awt.Color;
  25. import java.awt.Component;
  26. import java.awt.Container;
  27. import java.awt.Dimension;
  28. import java.awt.Font;
  29. import java.awt.Frame;
  30. import java.awt.GraphicsConfiguration;
  31. import java.awt.GraphicsDevice;
  32. import java.awt.GraphicsEnvironment;
  33. import java.awt.Image;
  34. import java.awt.Point;
  35. import java.awt.Rectangle;
  36. import java.awt.Window;
  37. import java.awt.Dialog;
  38. import java.awt.event.ComponentAdapter;
  39. import java.awt.event.ComponentEvent;
  40. import java.awt.event.MouseEvent;
  41. import java.awt.event.WindowAdapter;
  42. import java.awt.event.WindowEvent;
  43. import java.awt.event.WindowStateListener;
  44. import java.net.URL;
  45. import java.util.Hashtable;
  46. import java.util.Locale;
  47. import java.util.Map;
  48. import java.util.StringTokenizer;
  49. import javax.swing.*;
  50. import org.gjt.sp.jedit.browser.VFSFileChooserDialog;
  51. import org.gjt.sp.jedit.gui.EnhancedButton;
  52. import org.gjt.sp.jedit.gui.FloatingWindowContainer;
  53. import org.gjt.sp.jedit.gui.SplashScreen;
  54. import org.gjt.sp.jedit.gui.VariableGridLayout;
  55. import org.gjt.sp.jedit.menu.EnhancedCheckBoxMenuItem;
  56. import org.gjt.sp.jedit.menu.EnhancedMenu;
  57. import org.gjt.sp.jedit.menu.EnhancedMenuItem;
  58. import org.gjt.sp.jedit.syntax.SyntaxStyle;
  59. import org.gjt.sp.jedit.syntax.Token;
  60. import org.gjt.sp.jedit.textarea.TextAreaMouseHandler;
  61. import org.gjt.sp.util.Log;
  62. //}}}
  63. /**
  64. * Various GUI functions.<p>
  65. *
  66. * The most frequently used members of this class are:
  67. *
  68. * <ul>
  69. * <li>{@link #loadIcon(String)}</li>
  70. * <li>{@link #confirm(Component,String,Object[],int,int)}</li>
  71. * <li>{@link #error(Component,String,Object[])}</li>
  72. * <li>{@link #message(Component,String,Object[])}</li>
  73. * <li>{@link #showVFSFileDialog(View,String,int,boolean)}</li>
  74. * <li>{@link #loadGeometry(Window,String)}</li>
  75. * <li>{@link #saveGeometry(Window,String)}</li>
  76. * <li>{@link #showPopupMenu(JPopupMenu,Component,int,int)}</li>
  77. * </ul>
  78. *
  79. * @author Slava Pestov
  80. * @version $Id: GUIUtilities.java 9995 2007-07-10 23:22:40Z Vampire0 $
  81. */
  82. public class GUIUtilities
  83. {
  84. //{{{ Some predefined icons
  85. /**
  86. * @deprecated Use <code>GUIUtilities.loadIcon("new.gif");</code>
  87. * instead.
  88. */
  89. public static Icon NEW_BUFFER_ICON;
  90. /**
  91. * @deprecated Use <code>GUIUtilities.loadIcon("dirty.gif");</code>
  92. * instead.
  93. */
  94. public static Icon DIRTY_BUFFER_ICON;
  95. /**
  96. * @deprecated Use <code>GUIUtilities.loadIcon("readonly.gif");</code>
  97. * instead.
  98. */
  99. public static Icon READ_ONLY_BUFFER_ICON;
  100. /**
  101. * @deprecated Use <code>GUIUtilities.loadIcon("normal.gif");</code>
  102. * instead.
  103. */
  104. public static Icon NORMAL_BUFFER_ICON;
  105. /**
  106. * @deprecated Use <code>GUIUtilities.loadIcon("jedit-icon.gif");</code>
  107. * instead.
  108. */
  109. public static Icon WINDOW_ICON;
  110. //}}}
  111. //{{{ Icon methods
  112. //{{{ setIconPath() method
  113. /**
  114. * Sets the path where jEdit looks for icons.
  115. * @since jEdit 4.2pre5
  116. */
  117. public static void setIconPath(String iconPath)
  118. {
  119. GUIUtilities.iconPath = iconPath;
  120. if(icons != null)
  121. icons.clear();
  122. } //}}}
  123. //{{{ loadIcon() method
  124. /**
  125. * Loads an icon.
  126. * @param iconName The icon name
  127. * @since jEdit 2.6pre7
  128. */
  129. public static Icon loadIcon(String iconName)
  130. {
  131. if(icons == null)
  132. icons = new Hashtable<String, Icon>();
  133. // check if there is a cached version first
  134. Icon icon = icons.get(iconName);
  135. if(icon != null)
  136. return icon;
  137. URL url;
  138. try
  139. {
  140. // get the icon
  141. if(MiscUtilities.isURL(iconName))
  142. url = new URL(iconName);
  143. else
  144. url = new URL(iconPath + iconName);
  145. }
  146. catch(Exception e)
  147. {
  148. try
  149. {
  150. url = new URL(defaultIconPath + iconName);
  151. }
  152. catch(Exception ex)
  153. {
  154. Log.log(Log.ERROR,GUIUtilities.class,
  155. "Icon not found: " + iconName);
  156. Log.log(Log.ERROR,GUIUtilities.class,ex);
  157. return null;
  158. }
  159. }
  160. icon = new ImageIcon(url);
  161. icons.put(iconName,icon);
  162. return icon;
  163. } //}}}
  164. //{{{ getEditorIcon() method
  165. /**
  166. * Returns the default editor window image.
  167. */
  168. public static Image getEditorIcon()
  169. {
  170. return ((ImageIcon)loadIcon("jedit-icon.gif")).getImage();
  171. } //}}}
  172. //{{{ getPluginIcon() method
  173. /**
  174. * Returns the default plugin window image.
  175. */
  176. public static Image getPluginIcon()
  177. {
  178. return getEditorIcon();
  179. } //}}}
  180. //}}}
  181. //{{{ Menus, tool bars
  182. //{{{ loadMenuBar() method
  183. /**
  184. * Creates a menubar. Plugins should not need to call this method.
  185. * @param name The menu bar name
  186. * @since jEdit 3.2pre5
  187. */
  188. public static JMenuBar loadMenuBar(String name)
  189. {
  190. return loadMenuBar(jEdit.getActionContext(),name);
  191. } //}}}
  192. //{{{ loadMenuBar() method
  193. /**
  194. * Creates a menubar. Plugins should not need to call this method.
  195. * @param context An action context
  196. * @param name The menu bar name
  197. * @since jEdit 4.2pre1
  198. */
  199. public static JMenuBar loadMenuBar(ActionContext context, String name)
  200. {
  201. String menus = jEdit.getProperty(name);
  202. StringTokenizer st = new StringTokenizer(menus);
  203. JMenuBar mbar = new JMenuBar();
  204. while(st.hasMoreTokens())
  205. {
  206. String menuName = st.nextToken();
  207. mbar.add(loadMenu(context, menuName));
  208. }
  209. return mbar;
  210. } //}}}
  211. //{{{ loadMenu() method
  212. /**
  213. * Creates a menu. The menu label is set from the
  214. * <code><i>name</i>.label</code> property. The menu contents is taken
  215. * from the <code><i>name</i></code> property, which is a whitespace
  216. * separated list of action names. An action name of <code>-</code>
  217. * inserts a separator in the menu.
  218. * @param name The menu name
  219. * @see #loadMenuItem(String)
  220. * @since jEdit 2.6pre2
  221. */
  222. public static JMenu loadMenu(String name)
  223. {
  224. return loadMenu(jEdit.getActionContext(),name);
  225. } //}}}
  226. //{{{ loadMenu() method
  227. /**
  228. * Creates a menu. The menu label is set from the
  229. * <code><i>name</i>.label</code> property. The menu contents is taken
  230. * from the <code><i>name</i></code> property, which is a whitespace
  231. * separated list of action names. An action name of <code>-</code>
  232. * inserts a separator in the menu.
  233. * @param context An action context; either
  234. * <code>jEdit.getActionContext()</code> or
  235. * <code>VFSBrowser.getActionContext()</code>.
  236. * @param name The menu name
  237. * @see #loadMenuItem(String)
  238. * @since jEdit 4.2pre1
  239. */
  240. public static JMenu loadMenu(ActionContext context, String name)
  241. {
  242. return new EnhancedMenu(name,
  243. jEdit.getProperty(name.concat(".label")),
  244. context);
  245. } //}}}
  246. //{{{ loadPopupMenu() method
  247. /**
  248. * Creates a popup menu.
  249. * @param name The menu name
  250. * @since jEdit 2.6pre2
  251. */
  252. public static JPopupMenu loadPopupMenu(String name)
  253. {
  254. return loadPopupMenu(jEdit.getActionContext(),name);
  255. } //}}}
  256. //{{{ loadPopupMenu() method
  257. /**
  258. * Creates a popup menu.
  259. * @param context An action context; either
  260. * <code>jEdit.getActionContext()</code> or
  261. * <code>VFSBrowser.getActionContext()</code>.
  262. * @param name The menu name
  263. * @since jEdit 4.2pre1
  264. */
  265. public static JPopupMenu loadPopupMenu(ActionContext context, String name)
  266. {
  267. JPopupMenu menu = new JPopupMenu();
  268. String menuItems = jEdit.getProperty(name);
  269. if(menuItems != null)
  270. {
  271. StringTokenizer st = new StringTokenizer(menuItems);
  272. while(st.hasMoreTokens())
  273. {
  274. String menuItemName = st.nextToken();
  275. if(menuItemName.equals("-"))
  276. menu.addSeparator();
  277. else
  278. menu.add(loadMenuItem(context,menuItemName,false));
  279. }
  280. }
  281. return menu;
  282. } //}}}
  283. //{{{ loadMenuItem() method
  284. /**
  285. * Creates a menu item. The menu item is bound to the action named by
  286. * <code>name</code> with label taken from the return value of the
  287. * {@link EditAction#getLabel()} method.
  288. *
  289. * @param name The menu item name
  290. * @see #loadMenu(String)
  291. * @since jEdit 2.6pre1
  292. */
  293. public static JMenuItem loadMenuItem(String name)
  294. {
  295. return loadMenuItem(jEdit.getActionContext(),name,true);
  296. } //}}}
  297. //{{{ loadMenuItem() method
  298. /**
  299. * Creates a menu item.
  300. * @param name The menu item name
  301. * @param setMnemonic True if the menu item should have a mnemonic
  302. * @since jEdit 3.1pre1
  303. */
  304. public static JMenuItem loadMenuItem(String name, boolean setMnemonic)
  305. {
  306. return loadMenuItem(jEdit.getActionContext(),name,setMnemonic);
  307. } //}}}
  308. //{{{ loadMenuItem() method
  309. /**
  310. * Creates a menu item.
  311. * @param context An action context; either
  312. * <code>jEdit.getActionContext()</code> or
  313. * <code>VFSBrowser.getActionContext()</code>.
  314. * @param name The menu item name
  315. * @param setMnemonic True if the menu item should have a mnemonic
  316. * @since jEdit 4.2pre1
  317. */
  318. public static JMenuItem loadMenuItem(ActionContext context, String name,
  319. boolean setMnemonic)
  320. {
  321. if(name.charAt(0) == '%')
  322. return loadMenu(context,name.substring(1));
  323. String label = jEdit.getProperty(name + ".label");
  324. if(label == null)
  325. label = name;
  326. char mnemonic;
  327. int index = label.indexOf('$');
  328. if(index != -1 && label.length() - index > 1)
  329. {
  330. mnemonic = Character.toLowerCase(label.charAt(index + 1));
  331. label = label.substring(0,index).concat(label.substring(++index));
  332. }
  333. else
  334. mnemonic = '\0';
  335. JMenuItem mi;
  336. if(jEdit.getBooleanProperty(name + ".toggle"))
  337. mi = new EnhancedCheckBoxMenuItem(label,name,context);
  338. else
  339. mi = new EnhancedMenuItem(label,name,context);
  340. if(!OperatingSystem.isMacOS() && setMnemonic && mnemonic != '\0')
  341. mi.setMnemonic(mnemonic);
  342. return mi;
  343. } //}}}
  344. // {{{ loadMenuItem(EditAction, boolean)
  345. public static JMenuItem loadMenuItem(EditAction editAction,
  346. boolean setMnemonic)
  347. {
  348. String name = editAction.getName();
  349. ActionContext context = jEdit.getActionContext();
  350. // String label = jEdit.getProperty(name + ".label");
  351. String label = editAction.getLabel();
  352. if(label == null)
  353. label = name;
  354. char mnemonic;
  355. int index = label.indexOf('$');
  356. if(index != -1 && label.length() - index > 1)
  357. {
  358. mnemonic = Character.toLowerCase(label.charAt(index + 1));
  359. label = label.substring(0,index).concat(label.substring(++index));
  360. }
  361. else
  362. mnemonic = '\0';
  363. JMenuItem mi;
  364. if(jEdit.getBooleanProperty(name + ".toggle"))
  365. mi = new EnhancedCheckBoxMenuItem(label,name,context);
  366. else
  367. mi = new EnhancedMenuItem(label,name,context);
  368. if(!OperatingSystem.isMacOS() && setMnemonic && mnemonic != '\0')
  369. mi.setMnemonic(mnemonic);
  370. return mi;
  371. } //}}}
  372. //{{{ loadToolBar() method
  373. /**
  374. * Creates a toolbar.
  375. * @param name The toolbar name
  376. * @since jEdit 4.2pre2
  377. */
  378. public static Box loadToolBar(String name)
  379. {
  380. return loadToolBar(jEdit.getActionContext(),name);
  381. } //}}}
  382. //{{{ loadToolBar() method
  383. /**
  384. * Creates a toolbar.
  385. * @param context An action context; either
  386. * <code>jEdit.getActionContext()</code> or
  387. * <code>VFSBrowser.getActionContext()</code>.
  388. * @param name The toolbar name
  389. * @since jEdit 4.2pre2
  390. */
  391. public static Box loadToolBar(ActionContext context, String name)
  392. {
  393. Box toolBar = new Box(BoxLayout.X_AXIS);
  394. String buttons = jEdit.getProperty(name);
  395. if(buttons != null)
  396. {
  397. StringTokenizer st = new StringTokenizer(buttons);
  398. while(st.hasMoreTokens())
  399. {
  400. String button = st.nextToken();
  401. if(button.equals("-"))
  402. toolBar.add(Box.createHorizontalStrut(12));
  403. else
  404. {
  405. JButton b = loadToolButton(context,button);
  406. if(b != null)
  407. toolBar.add(b);
  408. }
  409. }
  410. }
  411. toolBar.add(Box.createGlue());
  412. return toolBar;
  413. } //}}}
  414. //{{{ loadToolButton() method
  415. /**
  416. * Loads a tool bar button. The tooltip is constructed from
  417. * the <code><i>name</i>.label</code> and
  418. * <code><i>name</i>.shortcut</code> properties and the icon is loaded
  419. * from the resource named '/org/gjt/sp/jedit/icons/' suffixed
  420. * with the value of the <code><i>name</i>.icon</code> property.
  421. * @param name The name of the button
  422. */
  423. public static EnhancedButton loadToolButton(String name)
  424. {
  425. return loadToolButton(jEdit.getActionContext(),name);
  426. } //}}}
  427. //{{{ loadToolButton() method
  428. /**
  429. * Loads a tool bar button. The tooltip is constructed from
  430. * the <code><i>name</i>.label</code> and
  431. * <code><i>name</i>.shortcut</code> properties and the icon is loaded
  432. * from the resource named '/org/gjt/sp/jedit/icons/' suffixed
  433. * with the value of the <code><i>name</i>.icon</code> property.
  434. * @param context An action context; either
  435. * <code>jEdit.getActionContext()</code> or
  436. * <code>VFSBrowser.getActionContext()</code>.
  437. * @param name The name of the button
  438. * @since jEdit 4.2pre1
  439. */
  440. public static EnhancedButton loadToolButton(ActionContext context,
  441. String name)
  442. {
  443. String label = jEdit.getProperty(name + ".label");
  444. if(label == null)
  445. label = name;
  446. Icon icon;
  447. String iconName = jEdit.getProperty(name + ".icon");
  448. if(iconName == null)
  449. icon = loadIcon("BrokenImage.png");
  450. else
  451. {
  452. icon = loadIcon(iconName);
  453. if(icon == null)
  454. icon = loadIcon("BrokenImage.png");
  455. }
  456. String toolTip = prettifyMenuLabel(label);
  457. String shortcut1 = jEdit.getProperty(name + ".shortcut");
  458. String shortcut2 = jEdit.getProperty(name + ".shortcut2");
  459. if(shortcut1 != null || shortcut2 != null)
  460. {
  461. toolTip = toolTip + " ("
  462. + (shortcut1 != null
  463. ? shortcut1 : "")
  464. + ((shortcut1 != null && shortcut2 != null)
  465. ? " or " : "")
  466. + (shortcut2 != null
  467. ? shortcut2
  468. : "") + ')';
  469. }
  470. return new EnhancedButton(icon,toolTip,name,context);
  471. } //}}}
  472. //{{{ prettifyMenuLabel() method
  473. /**
  474. * `Prettifies' a menu item label by removing the `$' sign. This
  475. * can be used to process the contents of an <i>action</i>.label
  476. * property.
  477. */
  478. public static String prettifyMenuLabel(String label)
  479. {
  480. int index = label.indexOf('$');
  481. if(index != -1)
  482. {
  483. label = label.substring(0,index)
  484. .concat(label.substring(index + 1));
  485. }
  486. return label;
  487. } //}}}
  488. //}}}
  489. //{{{ Canned dialog boxes
  490. //{{{ message() method
  491. /**
  492. * Displays a dialog box.
  493. * The title of the dialog is fetched from
  494. * the <code><i>name</i>.title</code> property. The message is fetched
  495. * from the <code><i>name</i>.message</code> property. The message
  496. * is formatted by the property manager with <code>args</code> as
  497. * positional parameters.
  498. * @param comp The component to display the dialog for
  499. * @param name The name of the dialog
  500. * @param args Positional parameters to be substituted into the
  501. * message text
  502. */
  503. public static void message(Component comp, String name, Object[] args)
  504. {
  505. hideSplashScreen();
  506. JOptionPane.showMessageDialog(comp,
  507. jEdit.getProperty(name.concat(".message"),args),
  508. jEdit.getProperty(name.concat(".title"),args),
  509. JOptionPane.INFORMATION_MESSAGE);
  510. } //}}}
  511. //{{{ error() method
  512. /**
  513. * Displays an error dialog box.
  514. * The title of the dialog is fetched from
  515. * the <code><i>name</i>.title</code> property. The message is fetched
  516. * from the <code><i>name</i>.message</code> property. The message
  517. * is formatted by the property manager with <code>args</code> as
  518. * positional parameters.
  519. * @param comp The component to display the dialog for
  520. * @param name The name of the dialog
  521. * @param args Positional parameters to be substituted into the
  522. * message text
  523. */
  524. public static void error(Component comp, String name, Object[] args)
  525. {
  526. hideSplashScreen();
  527. JOptionPane.showMessageDialog(comp,
  528. jEdit.getProperty(name.concat(".message"),args),
  529. jEdit.getProperty(name.concat(".title"),args),
  530. JOptionPane.ERROR_MESSAGE);
  531. } //}}}
  532. //{{{ input() method
  533. /**
  534. * Displays an input dialog box and returns any text the user entered.
  535. * The title of the dialog is fetched from
  536. * the <code><i>name</i>.title</code> property. The message is fetched
  537. * from the <code><i>name</i>.message</code> property.
  538. * @param comp The component to display the dialog for
  539. * @param name The name of the dialog
  540. * @param def The text to display by default in the input field
  541. */
  542. public static String input(Component comp, String name, Object def)
  543. {
  544. return input(comp,name,null,def);
  545. } //}}}
  546. //{{{ inputProperty() method
  547. /**
  548. * Displays an input dialog box and returns any text the user entered.
  549. * The title of the dialog is fetched from
  550. * the <code><i>name</i>.title</code> property. The message is fetched
  551. * from the <code><i>name</i>.message</code> property.
  552. * @param comp The component to display the dialog for
  553. * @param name The name of the dialog
  554. * @param def The property whose text to display in the input field
  555. */
  556. public static String inputProperty(Component comp, String name,
  557. String def)
  558. {
  559. return inputProperty(comp,name,null,def);
  560. } //}}}
  561. //{{{ input() method
  562. /**
  563. * Displays an input dialog box and returns any text the user entered.
  564. * The title of the dialog is fetched from
  565. * the <code><i>name</i>.title</code> property. The message is fetched
  566. * from the <code><i>name</i>.message</code> property.
  567. * @param comp The component to display the dialog for
  568. * @param name The name of the dialog
  569. * @param def The text to display by default in the input field
  570. * @param args Positional parameters to be substituted into the
  571. * message text
  572. * @since jEdit 3.1pre3
  573. */
  574. public static String input(Component comp, String name,
  575. Object[] args, Object def)
  576. {
  577. hideSplashScreen();
  578. String retVal = (String)JOptionPane.showInputDialog(comp,
  579. jEdit.getProperty(name.concat(".message"),args),
  580. jEdit.getProperty(name.concat(".title")),
  581. JOptionPane.QUESTION_MESSAGE,null,null,def);
  582. return retVal;
  583. } //}}}
  584. //{{{ inputProperty() method
  585. /**
  586. * Displays an input dialog box and returns any text the user entered.
  587. * The title of the dialog is fetched from
  588. * the <code><i>name</i>.title</code> property. The message is fetched
  589. * from the <code><i>name</i>.message</code> property.
  590. * @param comp The component to display the dialog for
  591. * @param name The name of the dialog
  592. * @param args Positional parameters to be substituted into the
  593. * message text
  594. * @param def The property whose text to display in the input field
  595. * @since jEdit 3.1pre3
  596. */
  597. public static String inputProperty(Component comp, String name,
  598. Object[] args, String def)
  599. {
  600. hideSplashScreen();
  601. String retVal = (String)JOptionPane.showInputDialog(comp,
  602. jEdit.getProperty(name.concat(".message"),args),
  603. jEdit.getProperty(name.concat(".title")),
  604. JOptionPane.QUESTION_MESSAGE,
  605. null,null,jEdit.getProperty(def));
  606. if(retVal != null)
  607. jEdit.setProperty(def,retVal);
  608. return retVal;
  609. } //}}}
  610. //{{{ confirm() method
  611. /**
  612. * Displays a confirm dialog box and returns the button pushed by the
  613. * user. The title of the dialog is fetched from the
  614. * <code><i>name</i>.title</code> property. The message is fetched
  615. * from the <code><i>name</i>.message</code> property.
  616. * @param comp The component to display the dialog for
  617. * @param name The name of the dialog
  618. * @param args Positional parameters to be substituted into the
  619. * message text
  620. * @param buttons The buttons to display - for example,
  621. * JOptionPane.YES_NO_CANCEL_OPTION
  622. * @param type The dialog type - for example,
  623. * JOptionPane.WARNING_MESSAGE
  624. * @since jEdit 3.1pre3
  625. */
  626. public static int confirm(Component comp, String name,
  627. Object[] args, int buttons, int type)
  628. {
  629. hideSplashScreen();
  630. return JOptionPane.showConfirmDialog(comp,
  631. jEdit.getProperty(name + ".message",args),
  632. jEdit.getProperty(name + ".title"),buttons,type);
  633. } //}}}
  634. //{{{ listConfirm() method
  635. /**
  636. * Displays a confirm dialog box and returns the button pushed by the
  637. * user. The title of the dialog is fetched from the
  638. * <code><i>name</i>.title</code> property. The message is fetched
  639. * from the <code><i>name</i>.message</code> property. The dialog
  640. * also shows a list of entries given by the <code>listModel</code>
  641. * parameter.
  642. * @since jEdit 4.3pre1
  643. */
  644. public static int listConfirm(Component comp, String name, String[] args,
  645. Object[] listModel)
  646. {
  647. JList list = new JList(listModel);
  648. list.setVisibleRowCount(8);
  649. Object[] message = {
  650. jEdit.getProperty(name + ".message",args),
  651. new JScrollPane(list)
  652. };
  653. return JOptionPane.showConfirmDialog(comp,
  654. message,
  655. jEdit.getProperty(name + ".title"),
  656. JOptionPane.YES_NO_OPTION,
  657. JOptionPane.QUESTION_MESSAGE);
  658. } //}}}
  659. //{{{ showVFSFileDialog() methods
  660. /**
  661. * Displays a VFS file selection dialog box.
  662. * @param view The view, should be non-null
  663. * @param path The initial directory to display. May be null
  664. * @param type The dialog type. One of
  665. * {@link org.gjt.sp.jedit.browser.VFSBrowser#OPEN_DIALOG},
  666. * {@link org.gjt.sp.jedit.browser.VFSBrowser#SAVE_DIALOG}, or
  667. * {@link org.gjt.sp.jedit.browser.VFSBrowser#CHOOSE_DIRECTORY_DIALOG}.
  668. * @param multipleSelection True if multiple selection should be allowed
  669. * @return The selected file(s)
  670. * @since jEdit 2.6pre2
  671. */
  672. public static String[] showVFSFileDialog(View view, String path,
  673. int type, boolean multipleSelection)
  674. {
  675. // the view should not be null, but some plugins might do this
  676. if(view == null)
  677. {
  678. Log.log(Log.WARNING,GUIUtilities.class,
  679. "showVFSFileDialog(): given null view, assuming jEdit.getActiveView()");
  680. view = jEdit.getActiveView();
  681. }
  682. hideSplashScreen();
  683. VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
  684. view,path,type,multipleSelection);
  685. return fileChooser.getSelectedFiles();
  686. }
  687. /**
  688. * Displays a VFS file selection dialog box.
  689. * This version can specify a dialog as the parent instead
  690. * of the view.
  691. * @param view The view, should be non-null
  692. * @param path The initial directory to display. May be null
  693. * @param type The dialog type. One of
  694. * {@link org.gjt.sp.jedit.browser.VFSBrowser#OPEN_DIALOG},
  695. * {@link org.gjt.sp.jedit.browser.VFSBrowser#SAVE_DIALOG}, or
  696. * {@link org.gjt.sp.jedit.browser.VFSBrowser#CHOOSE_DIRECTORY_DIALOG}.
  697. * @param multipleSelection True if multiple selection should be allowed
  698. * @return The selected file(s)
  699. * @since jEdit 4.3pre10
  700. */
  701. public static String[] showVFSFileDialog(Dialog parent, View view,
  702. String path, int type, boolean multipleSelection)
  703. {
  704. hideSplashScreen();
  705. VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
  706. parent, view, path, type, multipleSelection, true);
  707. return fileChooser.getSelectedFiles();
  708. }
  709. /**
  710. * Displays a VFS file selection dialog box.
  711. * This version can specify a frame as the parent instead
  712. * of the view.
  713. * @param parent The parent frame
  714. * @param view The view, should be non-null
  715. * @param path The initial directory to display. May be null
  716. * @param type The dialog type. One of
  717. * {@link org.gjt.sp.jedit.browser.VFSBrowser#OPEN_DIALOG},
  718. * {@link org.gjt.sp.jedit.browser.VFSBrowser#SAVE_DIALOG}, or
  719. * {@link org.gjt.sp.jedit.browser.VFSBrowser#CHOOSE_DIRECTORY_DIALOG}.
  720. * @param multipleSelection True if multiple selection should be allowed
  721. * @return The selected file(s)
  722. * @since jEdit 4.3pre10
  723. */
  724. public static String[] showVFSFileDialog(Frame parent, View view,
  725. String path, int type, boolean multipleSelection)
  726. {
  727. hideSplashScreen();
  728. VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
  729. parent, view, path, type, multipleSelection, true);
  730. return fileChooser.getSelectedFiles();
  731. } //}}}
  732. //{{{ Colors and styles
  733. //{{{ parseColor() method
  734. /**
  735. * Converts a color name to a color object. The name must either be
  736. * a known string, such as `red', `green', etc (complete list is in
  737. * the <code>java.awt.Color</code> class) or a hex color value
  738. * prefixed with `#', for example `#ff0088'.
  739. * @param name The color name
  740. */
  741. public static Color parseColor(String name)
  742. {
  743. return parseColor(name, Color.black);
  744. } //}}}
  745. //{{{ parseColor() method
  746. public static Color parseColor(String name, Color defaultColor)
  747. {
  748. if(name == null)
  749. return defaultColor;
  750. else if(name.charAt(0) == '#')
  751. {
  752. try
  753. {
  754. return Color.decode(name);
  755. }
  756. catch(NumberFormatException nf)
  757. {
  758. return defaultColor;
  759. }
  760. }
  761. else if("red".equals(name))
  762. return Color.red;
  763. else if("green".equals(name))
  764. return Color.green;
  765. else if("blue".equals(name))
  766. return Color.blue;
  767. else if("yellow".equals(name))
  768. return Color.yellow;
  769. else if("orange".equals(name))
  770. return Color.orange;
  771. else if("white".equals(name))
  772. return Color.white;
  773. else if("lightGray".equals(name))
  774. return Color.lightGray;
  775. else if("gray".equals(name))
  776. return Color.gray;
  777. else if("darkGray".equals(name))
  778. return Color.darkGray;
  779. else if("black".equals(name))
  780. return Color.black;
  781. else if("cyan".equals(name))
  782. return Color.cyan;
  783. else if("magenta".equals(name))
  784. return Color.magenta;
  785. else if("pink".equals(name))
  786. return Color.pink;
  787. else
  788. return defaultColor;
  789. } //}}}
  790. //{{{ getColorHexString() method
  791. /**
  792. * Converts a color object to its hex value. The hex value
  793. * prefixed is with `#', for example `#ff0088'.
  794. * @param c The color object
  795. */
  796. public static String getColorHexString(Color c)
  797. {
  798. String colString = Integer.toHexString(c.getRGB() & 0xffffff);
  799. return "#000000".substring(0,7 - colString.length()).concat(colString);
  800. } //}}}
  801. //{{{ parseStyle() method
  802. /**
  803. * Converts a style string to a style object.
  804. * @param str The style string
  805. * @param family Style strings only specify font style, not font family
  806. * @param size Style strings only specify font style, not font family
  807. * @exception IllegalArgumentException if the style is invalid
  808. * @since jEdit 3.2pre6
  809. */
  810. public static SyntaxStyle parseStyle(String str, String family, int size)
  811. throws IllegalArgumentException
  812. {
  813. return parseStyle(str,family,size,true);
  814. } //}}}
  815. //{{{ parseStyle() method
  816. /**
  817. * Converts a style string to a style object.
  818. * @param str The style string
  819. * @param family Style strings only specify font style, not font family
  820. * @param size Style strings only specify font style, not font family
  821. * @param color If false, the styles will be monochrome
  822. * @exception IllegalArgumentException if the style is invalid
  823. * @since jEdit 4.0pre4
  824. */
  825. public static SyntaxStyle parseStyle(String str, String family, int size,
  826. boolean color)
  827. throws IllegalArgumentException
  828. {
  829. Color fgColor = Color.black;
  830. Color bgColor = null;
  831. boolean italic = false;
  832. boolean bold = false;
  833. StringTokenizer st = new StringTokenizer(str);
  834. while(st.hasMoreTokens())
  835. {
  836. String s = st.nextToken();
  837. if(s.startsWith("color:"))
  838. {
  839. if(color)
  840. fgColor = GUIUtilities.parseColor(s.substring(6), Color.black);
  841. }
  842. else if(s.startsWith("bgColor:"))
  843. {
  844. if(color)
  845. bgColor = GUIUtilities.parseColor(s.substring(8), null);
  846. }
  847. else if(s.startsWith("style:"))
  848. {
  849. for(int i = 6; i < s.length(); i++)
  850. {
  851. if(s.charAt(i) == 'i')
  852. italic = true;
  853. else if(s.charAt(i) == 'b')
  854. bold = true;
  855. else
  856. throw new IllegalArgumentException(
  857. "Invalid style: " + s);
  858. }
  859. }
  860. else
  861. throw new IllegalArgumentException(
  862. "Invalid directive: " + s);
  863. }
  864. return new SyntaxStyle(fgColor,bgColor,
  865. new Font(family,
  866. (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0),
  867. size));
  868. } //}}}
  869. //{{{ getStyleString() method
  870. /**
  871. * Converts a style into it's string representation.
  872. * @param style The style
  873. */
  874. public static String getStyleString(SyntaxStyle style)
  875. {
  876. StringBuilder buf = new StringBuilder();
  877. if (style.getForegroundColor() != null)
  878. {
  879. buf.append("color:").append(getColorHexString(style.getForegroundColor()));
  880. }
  881. if (style.getBackgroundColor() != null)
  882. {
  883. buf.append(" bgColor:").append(getColorHexString(style.getBackgroundColor()));
  884. }
  885. Font font = style.getFont();
  886. if (!font.isPlain())
  887. {
  888. buf.append(" style:");
  889. if (font.isItalic())
  890. buf.append('i');
  891. if (font.isBold())
  892. buf.append('b');
  893. }
  894. return buf.toString();
  895. } //}}}
  896. //{{{ loadStyles() method
  897. /**
  898. * Loads the syntax styles from the properties, giving them the specified
  899. * base font family and size.
  900. * @param family The font family
  901. * @param size The font size
  902. * @since jEdit 3.2pre6
  903. */
  904. public static SyntaxStyle[] loadStyles(String family, int size)
  905. {
  906. return loadStyles(family,size,true);
  907. } //}}}
  908. //{{{ loadStyles() method
  909. /**
  910. * Loads the syntax styles from the properties, giving them the specified
  911. * base font family and size.
  912. * @param family The font family
  913. * @param size The font size
  914. * @param color If false, the styles will be monochrome
  915. * @since jEdit 4.0pre4
  916. */
  917. public static SyntaxStyle[] loadStyles(String family, int size, boolean color)
  918. {
  919. SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
  920. // start at 1 not 0 to skip Token.NULL
  921. for(int i = 1; i < styles.length; i++)
  922. {
  923. try
  924. {
  925. String styleName = "view.style."
  926. + Token.tokenToString((byte)i)
  927. .toLowerCase(Locale.ENGLISH);
  928. styles[i] = GUIUtilities.parseStyle(
  929. jEdit.getProperty(styleName),
  930. family,size,color);
  931. }
  932. catch(Exception e)
  933. {
  934. Log.log(Log.ERROR,GUIUtilities.class,e);
  935. }
  936. }
  937. return styles;
  938. } //}}}
  939. //}}}
  940. //{{{ Loading, saving window geometry
  941. //{{{ loadGeometry() method
  942. /**
  943. * Loads a windows's geometry from the properties.
  944. * The geometry is loaded from the <code><i>name</i>.x</code>,
  945. * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
  946. * <code><i>name</i>.height</code> properties.
  947. *
  948. * @param win The window to load geometry from
  949. * @param parent The parent frame to be relative to.
  950. * @param name The name of the window
  951. */
  952. public static void loadGeometry(Window win, Container parent, String name ) {
  953. int x, y, width, height;
  954. Dimension size = win.getSize();
  955. width = jEdit.getIntegerProperty(name + ".width", size.width);
  956. height = jEdit.getIntegerProperty(name + ".height", size.height);
  957. x = jEdit.getIntegerProperty(name + ".x",50);
  958. y = jEdit.getIntegerProperty(name + ".y",50);
  959. if(parent != null)
  960. {
  961. Point location = parent.getLocation();
  962. x = location.x + x;
  963. y = location.y + y;
  964. }
  965. int extState = jEdit.getIntegerProperty(name + ".extendedState", Frame.NORMAL);
  966. Rectangle desired = new Rectangle(x,y,width,height);
  967. try
  968. {
  969. if(!Debug.DISABLE_MULTIHEAD)
  970. adjustForScreenBounds(desired);
  971. }
  972. catch(Exception e)
  973. {
  974. /* Workaround for OS X bug. */
  975. Log.log(Log.ERROR,GUIUtilities.class,e);
  976. }
  977. if(OperatingSystem.isX11() && Debug.GEOMETRY_WORKAROUND)
  978. new UnixWorkaround(win,name,desired,extState);
  979. else
  980. {
  981. win.setBounds(desired);
  982. if(win instanceof Frame)
  983. ((Frame)win).setExtendedState(extState);
  984. }
  985. } //}}}
  986. //{{{ loadGeometry() method
  987. /**
  988. * Loads a windows's geometry from the properties.
  989. * The geometry is loaded from the <code><i>name</i>.x</code>,
  990. * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
  991. * <code><i>name</i>.height</code> properties.
  992. *
  993. * @param win The window to load geometry from
  994. * @param name The name of the window
  995. */
  996. public static void loadGeometry(Window win, String name)
  997. {
  998. loadGeometry(win, win.getParent(), name);
  999. } //}}}
  1000. //{{{ adjustForScreenBounds() method
  1001. /**
  1002. * Gives a rectangle the specified bounds, ensuring it is within the
  1003. * screen bounds.
  1004. * @since jEdit 4.2pre3
  1005. */
  1006. public static void adjustForScreenBounds(Rectangle desired)
  1007. {
  1008. // Make sure the window is displayed in visible region
  1009. Rectangle osbounds = OperatingSystem.getScreenBounds(desired);
  1010. if(desired.x < osbounds.x || desired.x+desired.width
  1011. > desired.x + osbounds.width)
  1012. {
  1013. if (desired.width > osbounds.width)
  1014. desired.width = osbounds.width;
  1015. desired.x = (osbounds.width - desired.width) / 2;
  1016. }
  1017. if(desired.y < osbounds.y || desired.y+desired.height
  1018. > osbounds.y + osbounds.height)
  1019. {
  1020. if (desired.height >= osbounds.height)
  1021. desired.height = osbounds.height;
  1022. desired.y = (osbounds.height - desired.height) / 2;
  1023. }
  1024. } //}}}
  1025. //{{{ UnixWorkaround class
  1026. static class UnixWorkaround
  1027. {
  1028. Window win;
  1029. String name;
  1030. Rectangle desired;
  1031. Rectangle required;
  1032. long start;
  1033. boolean windowOpened;
  1034. //{{{ UnixWorkaround constructor
  1035. UnixWorkaround(Window win, String name, Rectangle desired,
  1036. int extState)
  1037. {
  1038. this.win = win;
  1039. this.name = name;
  1040. this.desired = desired;
  1041. int adjust_x, adjust_y, adjust_width, adjust_height;
  1042. adjust_x = jEdit.getIntegerProperty(name + ".dx",0);
  1043. adjust_y = jEdit.getIntegerProperty(name + ".dy",0);
  1044. adjust_width = jEdit.getIntegerProperty(name + ".d-width",0);
  1045. adjust_height = jEdit.getIntegerProperty(name + ".d-height",0);
  1046. required = new Rectangle(
  1047. desired.x - adjust_x,
  1048. desired.y - adjust_y,
  1049. desired.width - adjust_width,
  1050. desired.height - adjust_height);
  1051. Log.log(Log.DEBUG,GUIUtilities.class,"Window " + name
  1052. + ": desired geometry is " + desired);
  1053. Log.log(Log.DEBUG,GUIUtilities.class,"Window " + name
  1054. + ": setting geometry to " + required);
  1055. start = System.currentTimeMillis();
  1056. win.setBounds(required);
  1057. if(win instanceof Frame)
  1058. ((Frame)win).setExtendedState(extState);
  1059. win.addComponentListener(new ComponentHandler());
  1060. win.addWindowListener(new WindowHandler());
  1061. } //}}}
  1062. //{{{ ComponentHandler class
  1063. class ComponentHandler extends ComponentAdapter
  1064. {
  1065. //{{{ componentMoved() method
  1066. public void componentMoved(ComponentEvent evt)
  1067. {
  1068. if(System.currentTimeMillis() - start < 1000L)
  1069. {
  1070. Rectangle r = win.getBounds();
  1071. if(!windowOpened && r.equals(required))
  1072. return;
  1073. if(!r.equals(desired))
  1074. {
  1075. Log.log(Log.DEBUG,GUIUtilities.class,
  1076. "Window resize blocked: " + win.getBounds());
  1077. win.setBounds(desired);
  1078. }
  1079. }
  1080. win.removeComponentListener(this);
  1081. } //}}}
  1082. //{{{ componentResized() method
  1083. public void componentResized(ComponentEvent evt)
  1084. {
  1085. if(System.currentTimeMillis() - start < 1000L)
  1086. {
  1087. Rectangle r = win.getBounds();
  1088. if(!windowOpened && r.equals(required))
  1089. return;
  1090. if(!r.equals(desired))
  1091. {
  1092. Log.log(Log.DEBUG,GUIUtilities.class,
  1093. "Window resize blocked: " + win.getBounds());
  1094. win.setBounds(desired);
  1095. }
  1096. }
  1097. win.removeComponentListener(this);
  1098. } //}}}
  1099. } //}}}
  1100. //{{{ WindowHandler class
  1101. class WindowHandler extends WindowAdapter
  1102. {
  1103. //{{{ windowOpened() method
  1104. public void windowOpened(WindowEvent evt)
  1105. {
  1106. windowOpened = true;
  1107. Rectangle r = win.getBounds();
  1108. Log.log(Log.DEBUG,GUIUtilities.class,"Window "
  1109. + name + ": bounds after opening: " + r);
  1110. jEdit.setIntegerProperty(name + ".dx",
  1111. r.x - required.x);
  1112. jEdit.setIntegerProperty(name + ".dy",
  1113. r.y - required.y);
  1114. jEdit.setIntegerProperty(name + ".d-width",
  1115. r.width - required.width);
  1116. jEdit.setIntegerProperty(name + ".d-height",
  1117. r.height - required.height);
  1118. win.removeWindowListener(this);
  1119. } //}}}
  1120. } //}}}
  1121. } //}}}
  1122. //{{{ saveGeometry() method
  1123. /**
  1124. * Saves a window's geometry to the properties.
  1125. * The geometry is saved to the <code><i>name</i>.x</code>,
  1126. * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
  1127. * <code><i>name</i>.height</code> properties.<br />
  1128. * For Frame's and descendents use {@link #addSizeSaver(Frame,String)} to save the sizes
  1129. * correct even if the Frame is in maximized or iconified state.
  1130. * @param win The window to load geometry from
  1131. * @param name The name of the window
  1132. * @see #addSizeSaver(Frame,String)
  1133. */
  1134. public static void saveGeometry(Window win, String name) {
  1135. saveGeometry (win, win.getParent(), name);
  1136. } //}}}
  1137. //{{{ saveGeometry() method
  1138. /**
  1139. * Saves a window's geometry to the properties.
  1140. * The geometry is saved to the <code><i>name</i>.x</code>,
  1141. * <code><i>name</i>.y</code>, <code><i>name</i>.width</code> and
  1142. * <code><i>name</i>.height</code> properties.<br />
  1143. * For Frame's and descendents use {@link #addSizeSaver(Frame,Container,String)} to save the sizes
  1144. * correct even if the Frame is in maximized or iconified state.
  1145. * @param win The window to load geometry from
  1146. * @param parent The parent frame to be relative to.
  1147. * @param name The name of the window
  1148. * @see #addSizeSaver(Frame,Container,String)
  1149. */
  1150. public static void saveGeometry(Window win, Container parent, String name)
  1151. {
  1152. if(win instanceof Frame)
  1153. {
  1154. jEdit.setIntegerProperty(name + ".extendedState",
  1155. ((Frame)win).getExtendedState());
  1156. }
  1157. Rectangle bounds = win.getBounds();
  1158. int x = bounds.x;
  1159. int y = bounds.y;
  1160. if (parent != null)
  1161. {
  1162. Rectangle parentBounds = parent.getBounds();
  1163. x = x - parentBounds.x;
  1164. y = y - parentBounds.y;
  1165. }
  1166. jEdit.setIntegerProperty(name + ".x",x);
  1167. jEdit.setIntegerProperty(name + ".y",y);
  1168. jEdit.setIntegerProperty(name + ".width", bounds.width);
  1169. jEdit.setIntegerProperty(name + ".height", bounds.height);
  1170. } //}}}
  1171. //{{{ centerOnScreen() method
  1172. /**
  1173. * Centers the given window on the screen. This method is needed because
  1174. * JDK 1.3 does not have a <code>JWindow.setLocationRelativeTo()</code>
  1175. * method.
  1176. * @since jEdit 4.2pre3
  1177. * @deprecated use {@link javax.swing.JWindow#setLocationRelativeTo(java.awt.Component)}
  1178. */
  1179. @Deprecated
  1180. public static void centerOnScreen(Window win)
  1181. {
  1182. GraphicsDevice gd = GraphicsEnvironment
  1183. .getLocalGraphicsEnvironment()
  1184. .getDefaultScreenDevice();
  1185. Rectangle gcbounds = gd.getDefaultConfiguration().getBounds();
  1186. int x = gcbounds.x + (gcbounds.width - win.getWidth()) / 2;
  1187. int y = gcbounds.y + (gcbounds.height - win.getHeight()) / 2;
  1188. win.setLocation(x,y);
  1189. } //}}}
  1190. //}}}
  1191. //{{{ hideSplashScreen() method
  1192. /**
  1193. * Ensures that the splash screen is not visible. This should be
  1194. * called before displaying any dialog boxes or windows at
  1195. * startup.
  1196. */
  1197. public static void hideSplashScreen()
  1198. {
  1199. if(splash != null)
  1200. {
  1201. splash.dispose();
  1202. splash = null;
  1203. }
  1204. } //}}}
  1205. //{{{ createMultilineLabel() method
  1206. /**
  1207. * Creates a component that displays a multiple line message. This
  1208. * is implemented by assembling a number of <code>JLabels</code> in
  1209. * a <code>JPanel</code>.
  1210. * @param str The string, with lines delimited by newline
  1211. * (<code>\n</code>) characters.
  1212. * @since jEdit 4.1pre3
  1213. */
  1214. public static JComponent createMultilineLabel(String str)
  1215. {
  1216. JPanel panel = new JPanel(new VariableGridLayout(
  1217. VariableGridLayout.FIXED_NUM_COLUMNS,1,1,1));
  1218. int lastOffset = 0;
  1219. while(true)
  1220. {
  1221. int index = str.indexOf('\n',lastOffset);
  1222. if(index == -1)
  1223. break;
  1224. else
  1225. {
  1226. panel.add(new JLabel(str.substring(lastOffset,index)));
  1227. lastOffset = index + 1;
  1228. }
  1229. }
  1230. if(lastOffset != str.length())
  1231. panel.add(new JLabel(str.substring(lastOffset)));
  1232. return panel;
  1233. } //}}}
  1234. //{{{ requestFocus() method
  1235. /**
  1236. * Focuses on the specified component as soon as the window becomes
  1237. * active.
  1238. * @param win The window
  1239. * @param comp The component
  1240. */
  1241. public static void requestFocus(final Window win, final Component comp)
  1242. {
  1243. win.addWindowFocusListener(new WindowAdapter()
  1244. {
  1245. public void windowGainedFocus(WindowEvent evt)
  1246. {
  1247. SwingUtilities.invokeLater(new Runnable(){
  1248. public void run() {
  1249. comp.requestFocusInWindow();
  1250. }
  1251. });
  1252. win.removeWindowFocusListener(this);
  1253. }
  1254. });
  1255. } //}}}
  1256. //{{{ isPopupTrigger() method
  1257. /**
  1258. * Returns if the specified event is the popup trigger event.
  1259. * This implements precisely defined behavior, as opposed to
  1260. * MouseEvent.isPopupTrigger().
  1261. * @param evt The event
  1262. * @since jEdit 3.2pre8
  1263. */
  1264. public static boolean isPopupTrigger(MouseEvent evt)
  1265. {
  1266. return TextAreaMouseHandler.isRightButton(evt.getModifiers());
  1267. } //}}}
  1268. //{{{ isMiddleButton() method
  1269. /**
  1270. * @param modifiers The modifiers flag from a mouse event
  1271. * @since jEdit 4.1pre9
  1272. */
  1273. public static boolean isMiddleButton(int modifiers)
  1274. {
  1275. return TextAreaMouseHandler.isMiddleButton(modifiers);
  1276. } //}}}
  1277. //{{{ isRightButton() method
  1278. /**
  1279. * @param modifiers The modifiers flag from a mouse event
  1280. * @since jEdit 4.1pre9
  1281. */
  1282. public static boolean isRightButton(int modifiers)
  1283. {
  1284. return TextAreaMouseHandler.isRightButton(modifiers);
  1285. } //}}}
  1286. //{{{ showPopupMenu() method
  1287. /**
  1288. * Shows the specified popup menu, ensuring it is displayed within
  1289. * the bounds of the screen.
  1290. * @param popup The popup menu
  1291. * @param comp The component to show it for
  1292. * @param x The x co-ordinate
  1293. * @param y The y co-ordinate
  1294. * @since jEdit 4.0pre1
  1295. * @see {@link javax.swing.JComponent#setComponentPopupMenu(javax.swing.JPopupMenu)},
  1296. * which works better and is simpler to use: you don't have to write the code to
  1297. * show/hide popups in response to mouse events anymore.
  1298. */
  1299. public static void showPopupMenu(JPopupMenu popup, Component comp,
  1300. int x, int y)
  1301. {
  1302. showPopupMenu(popup,comp,x,y,true);
  1303. } //}}}
  1304. //{{{ showPopupMenu() method
  1305. /**
  1306. * Shows the specified popup menu, ensuring it is displayed within
  1307. * the bounds of the screen.
  1308. * @param popup The popup menu
  1309. * @param comp The component to show it for
  1310. * @param x The x co-ordinate
  1311. * @param y The y co-ordinate
  1312. * @param point If true, then the popup originates from a single point;
  1313. * otherwise it will originate from the component itself. This affects
  1314. * positioning in the case where the popup does not fit onscreen.
  1315. *
  1316. * @since jEdit 4.1pre1
  1317. */
  1318. public static void showPopupMenu(JPopupMenu popup, Component comp,
  1319. int x, int y, boolean point)
  1320. {
  1321. int offsetX = 0;
  1322. int offsetY = 0;
  1323. int extraOffset = (point ? 1 : 0);
  1324. Component win = comp;
  1325. while(!(win instanceof Window || win == null))
  1326. {
  1327. offsetX += win.getX();
  1328. offsetY += win.getY();
  1329. win = win.getParent();
  1330. }
  1331. if(win != null)
  1332. {
  1333. Dimension size = popup.getPreferredSize();
  1334. Rectangle screenSize = new Rectangle();
  1335. GraphicsEnvironment ge = GraphicsEnvironment
  1336. .getLocalGraphicsEnvironment();
  1337. GraphicsDevice[] devices = ge.getScreenDevices();
  1338. for (int j = 0; j < devices.length; j++)
  1339. {
  1340. GraphicsDevice device = devices[j];
  1341. GraphicsConfiguration[] gc =
  1342. device.getConfigurations();
  1343. for (int i=0; i < gc.length; i++)
  1344. {
  1345. screenSize =
  1346. screenSize.union(
  1347. gc[i].getBounds());
  1348. }
  1349. }
  1350. if(x + offsetX + size.width + win.getX() > screenSize.width
  1351. && x + offsetX + win.getX() >= size.width)
  1352. {
  1353. //System.err.println("x overflow");
  1354. if(point)
  1355. x -= (size.width + extraOffset);
  1356. else
  1357. x = (win.getWidth() - size.width - offsetX + extraOffset);
  1358. }
  1359. else
  1360. {
  1361. x += extraOffset;
  1362. }
  1363. //System.err.println("y=" + y + ",offsetY=" + offsetY
  1364. // + ",size.height=" + size.height
  1365. // + ",win.height=" + win.getHeight());
  1366. if(y + offsetY + size.height + win.getY() > screenSize.height
  1367. && y + offsetY + win.getY() >= size.height)
  1368. {
  1369. if(point)
  1370. y = (win.getHeight() - size.height - offsetY + extraOffset);
  1371. else
  1372. y = -size.height - 1;
  1373. }
  1374. else
  1375. {
  1376. y += extraOffset;
  1377. }
  1378. popup.show(comp,x,y);
  1379. }
  1380. else
  1381. popup.show(comp,x + extraOffset,y + extraOffset);
  1382. } //}}}
  1383. //{{{ isAncestorOf() method
  1384. /**
  1385. * Returns if the first component is an ancestor of the
  1386. * second by traversing up the component hierarchy.
  1387. *
  1388. * @param comp1 The ancestor
  1389. * @param comp2 The component to check
  1390. * @since jEdit 4.1pre5
  1391. */
  1392. public static boolean isAncestorOf(Component comp1, Component comp2)
  1393. {
  1394. while(comp2 != null)
  1395. {
  1396. if(comp1 == comp2)
  1397. return true;
  1398. else
  1399. comp2 = comp2.getParent();
  1400. }
  1401. return false;
  1402. } //}}}
  1403. //{{{ getParentDialog() method
  1404. /**
  1405. * Traverses the given component's parent tree looking for an
  1406. * instance of JDialog, and return it. If not found, return null.
  1407. * @param c The component
  1408. */
  1409. public static JDialog getParentDialog(Component c)
  1410. {
  1411. return (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, c);
  1412. } //}}}
  1413. //{{{ getComponentParent() method
  1414. /**
  1415. * Finds a parent of the specified component.
  1416. * @param comp The component
  1417. * @param clazz Looks for a parent with this class (exact match, not
  1418. * derived).
  1419. * @since jEdit 4.2pre1
  1420. */
  1421. public static Component getComponentParent(Component comp, Class clazz)
  1422. {
  1423. while(true)
  1424. {
  1425. if(comp == null)
  1426. break;
  1427. if(comp instanceof JComponent)
  1428. {
  1429. Component real = (Component)((JComponent)comp)
  1430. .getClientProperty("KORTE_REAL_FRAME");
  1431. if(real != null)
  1432. comp = real;
  1433. }
  1434. if(comp.getClass().equals(clazz))
  1435. return comp;
  1436. else if(comp instanceof JPopupMenu)
  1437. comp = ((JPopupMenu)comp).getInvoker();
  1438. else if(comp instanceof FloatingWindowContainer)
  1439. {
  1440. comp = ((FloatingWindowContainer)comp)
  1441. .getDockableWindowManager();
  1442. }
  1443. else
  1444. comp = comp.getParent();
  1445. }
  1446. return null;
  1447. } //}}}
  1448. //{{{ getView() method
  1449. /**
  1450. * Finds the view parent of the specified component.
  1451. * @since jEdit 4.0pre2
  1452. */
  1453. public static View getView(Component comp)
  1454. {
  1455. return (View)getComponentParent(comp,View.class);
  1456. } //}}}
  1457. //{{{ addSizeSaver() method
  1458. /**
  1459. * Adds a SizeSaver to the specified Frame. For non-Frame's use {@link #saveGeometry(Window,String)}
  1460. *
  1461. * @param frame The Frame for which to save the size
  1462. * @param name The prefix for the settings
  1463. * @since jEdit 4.3pre6
  1464. * @see #saveGeometry(Window,String)
  1465. */
  1466. public static void addSizeSaver(Frame frame, String name)
  1467. {
  1468. addSizeSaver(frame,frame.getParent(),name);
  1469. } //}}}
  1470. //{{{ addSizeSaver() method
  1471. /**
  1472. * Adds a SizeSaver to the specified Frame. For non-Frame's use {@link #saveGeometry(Window,Container,String)}
  1473. *
  1474. * @param frame The Frame for which to save the size
  1475. * @param parent The parent to be relative to
  1476. * @param name The prefix for the settings
  1477. * @since jEdit 4.3pre7
  1478. * @see #saveGeometry(Window,Container,String)
  1479. */
  1480. public static void addSizeSaver(Frame frame, Container parent, String name)
  1481. {
  1482. SizeSaver ss = new SizeSaver(frame,parent,name);
  1483. frame.addWindowStateListener(ss);
  1484. frame.addComponentListener(ss);
  1485. } //}}}
  1486. //{{{ initContinuousLayout() method
  1487. /**
  1488. * Init the continuous layout flag using the jEdit's property
  1489. * appearance.continuousLayout
  1490. *
  1491. * @param split the split. It must never be null
  1492. * @since jEdit 4.3pre9
  1493. */
  1494. public static void initContinuousLayout(JSplitPane split)
  1495. {
  1496. boolean continuousLayout = split.isContinuousLayout();
  1497. if (continuousLayout != jEdit.getBooleanProperty("appearance.continuousLayout"))
  1498. split.setContinuousLayout(!continuousLayout);
  1499. } //}}}
  1500. //{{{ Package-private members
  1501. //{{{ init() method
  1502. static void init()
  1503. {
  1504. // don't do this in static{} since we need jEdit.initMisc()
  1505. // run first so we have the jeditresource: protocol
  1506. NEW_BUFFER_ICON = loadIcon("new.gif");
  1507. DIRTY_BUFFER_ICON = loadIcon("dirty.gif");
  1508. READ_ONLY_BUFFER_ICON = loadIcon("readonly.gif");
  1509. NORMAL_BUFFER_ICON = loadIcon("normal.gif");
  1510. WINDOW_ICON = loadIcon("jedit-icon.gif");
  1511. } //}}}
  1512. //{{{ showSplashScreen() method
  1513. static void showSplashScreen()
  1514. {
  1515. splash = new SplashScreen();
  1516. } //}}}
  1517. //{{{ advanceSplashProgress() method
  1518. static void advanceSplashProgress()
  1519. {
  1520. if(splash != null)
  1521. splash.advance();
  1522. } //}}}
  1523. //{{{ advanceSplashProgress() method
  1524. static void advanceSplashProgress(String label)
  1525. {
  1526. if(splash != null)
  1527. splash.advance(label);
  1528. } //}}}
  1529. //}}}
  1530. //{{{ Private members
  1531. private static SplashScreen splash;
  1532. private static Map<String, Icon> icons;
  1533. private static String iconPath = "jeditresource:/org/gjt/sp/jedit/icons/";
  1534. private static String defaultIconPath = "jeditresource:/org/gjt/sp/jedit/icons/";
  1535. private GUIUtilities() {}
  1536. //}}}
  1537. //{{{ Inner classes
  1538. //{{{ SizeSaver class
  1539. /**
  1540. * A combined ComponentListener and WindowStateListener to continually save a Frames size.<br />
  1541. * For non-Frame's use {@link #saveGeometry(Window,String)}
  1542. *
  1543. * @author Bj??rn Kautler
  1544. * @version $Id: GUIUtilities.java 9995 2007-07-10 23:22:40Z Vampire0 $
  1545. * @since jEdit 4.3pre6
  1546. * @see #saveGeometry(Window,Container,String)
  1547. */
  1548. static class SizeSaver extends ComponentAdapter implements WindowStateListener
  1549. {
  1550. private Frame frame;
  1551. private Container parent;
  1552. private String name;
  1553. //{{{ SizeSaver constructor
  1554. /**
  1555. * Constructs a new SizeSaver.
  1556. *
  1557. * @param frame The Frame for which to save the size
  1558. * @param name The prefix for the settings
  1559. */
  1560. SizeSaver(Frame frame, String name)
  1561. {
  1562. this.frame = frame;
  1563. this.parent = frame.getParent();
  1564. } //}}}
  1565. //{{{ SizeSaver constructor
  1566. /**
  1567. * Constructs a new SizeSaver.
  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. */
  1573. public SizeSaver(Frame frame, Container parent, String name)
  1574. {
  1575. if ((null == frame) || (null == name))
  1576. {
  1577. throw new NullPointerException();
  1578. }
  1579. this.frame = frame;
  1580. this.parent = parent;
  1581. this.name = name;
  1582. } //}}}
  1583. //{{{ windowStateChanged() method
  1584. public void windowStateChanged(WindowEvent wse)
  1585. {
  1586. int extendedState = wse.getNewState();
  1587. jEdit.setIntegerProperty(name + ".extendedState",extendedState);
  1588. Rectangle bounds = frame.getBounds();
  1589. save(extendedState, bounds);
  1590. } //}}}
  1591. //{{{ save() method
  1592. private void save(int extendedState, Rectangle bounds)
  1593. {
  1594. switch (extendedState)
  1595. {
  1596. case Frame.MAXIMIZED_VERT:
  1597. jEdit.setIntegerProperty(name + ".x",bounds.x);
  1598. jEdit.setIntegerProperty(name + ".width",bounds.width);
  1599. break;
  1600. case Frame.MAXIMIZED_HORIZ:
  1601. jEdit.se