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

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