Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

WindowMenuFrameManager.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * Copyright (c) 2006-2010 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.addons.ui_swing.framemanager.windowmenu;
  23. import com.dmdirc.FrameContainer;
  24. import com.dmdirc.FrameContainerComparator;
  25. import com.dmdirc.addons.ui_swing.SwingController;
  26. import com.dmdirc.config.IdentityManager;
  27. import com.dmdirc.interfaces.SelectionListener;
  28. import com.dmdirc.ui.IconManager;
  29. import com.dmdirc.ui.WindowManager;
  30. import com.dmdirc.ui.interfaces.Window;
  31. import com.dmdirc.ui.interfaces.FrameListener;
  32. import java.awt.event.ActionEvent;
  33. import java.awt.event.ActionListener;
  34. import java.util.HashMap;
  35. import java.util.Map;
  36. import java.util.concurrent.atomic.AtomicBoolean;
  37. import javax.swing.JMenu;
  38. import javax.swing.JMenuItem;
  39. import javax.swing.JPopupMenu;
  40. import javax.swing.JSeparator;
  41. import javax.swing.event.MenuEvent;
  42. import javax.swing.event.MenuListener;
  43. /**
  44. * Manages the window menu window list.
  45. */
  46. public final class WindowMenuFrameManager extends JMenu implements
  47. FrameListener, ActionListener, SelectionListener, MenuListener {
  48. /**
  49. * A version number for this class. It should be changed whenever the class
  50. * structure is changed (or anything else that would prevent serialized
  51. * objects being unserialized with the new class).
  52. */
  53. private static final long serialVersionUID = 1;
  54. /** Comparator. */
  55. private final FrameContainerComparator comparator =
  56. new FrameContainerComparator();
  57. /** Non frame container menu count. */
  58. private final int itemCount;
  59. /** Menu items for toggling, closing and minimising. */
  60. private final JMenuItem toggleStateMenuItem, closeMenuItem, minimiseMenuItem;
  61. /** Seperator. */
  62. private final JSeparator separator;
  63. /** Active window. */
  64. private Window activeWindow;
  65. /** Enabled menu items? */
  66. private final AtomicBoolean enabledMenuItems = new AtomicBoolean(false);
  67. /** Swing controller. */
  68. private final SwingController controller;
  69. /** Window -> menu map. */
  70. private Map<FrameContainer, FrameContainerMenu> menus =
  71. new HashMap<FrameContainer, FrameContainerMenu>();
  72. private Map<FrameContainer, FrameContainerMenuItem> items =
  73. new HashMap<FrameContainer, FrameContainerMenuItem>();
  74. private Map<FrameContainer, FrameContainerMenuItem> menuItems =
  75. new HashMap<FrameContainer, FrameContainerMenuItem>();
  76. /**
  77. * Creates a new instance of WindowMenuFrameManager.
  78. *
  79. * @param controller Swing controller
  80. */
  81. public WindowMenuFrameManager(final SwingController controller) {
  82. super();
  83. this.controller = controller;
  84. setText("Window");
  85. setMnemonic('w');
  86. WindowManager.addFrameListener(this);
  87. addMenuListener(this);
  88. minimiseMenuItem = new JMenuItem(IconManager.getIconManager().getIcon(
  89. "minimise"));
  90. minimiseMenuItem.setMnemonic('n');
  91. minimiseMenuItem.setText("Minimise");
  92. minimiseMenuItem.setActionCommand("Minimise");
  93. minimiseMenuItem.addActionListener(this);
  94. add(minimiseMenuItem);
  95. toggleStateMenuItem = new JMenuItem(IconManager.getIconManager().getIcon(
  96. "maximise"));
  97. toggleStateMenuItem.setMnemonic('m');
  98. toggleStateMenuItem.setText("Maximise");
  99. toggleStateMenuItem.setActionCommand("ToggleState");
  100. toggleStateMenuItem.addActionListener(this);
  101. add(toggleStateMenuItem);
  102. closeMenuItem = new JMenuItem(IconManager.getIconManager().getIcon(
  103. "close"));
  104. closeMenuItem.setMnemonic('c');
  105. closeMenuItem.setText("Close");
  106. closeMenuItem.setActionCommand("Close");
  107. closeMenuItem.addActionListener(this);
  108. add(closeMenuItem);
  109. separator = new JPopupMenu.Separator();
  110. add(separator);
  111. itemCount = getMenuComponentCount();
  112. checkToggleState();
  113. new WindowMenuScroller(this, controller.getDomain(), 4);
  114. }
  115. /**
  116. * Checks the number of components in the menu and enables menus items
  117. * appropriately.
  118. */
  119. private void checkMenuItems() {
  120. enabledMenuItems.set((getMenuComponentCount() > itemCount));
  121. separator.setVisible(enabledMenuItems.get());
  122. closeMenuItem.setEnabled(enabledMenuItems.get());
  123. toggleStateMenuItem.setEnabled(enabledMenuItems.get());
  124. minimiseMenuItem.setEnabled(enabledMenuItems.get());
  125. }
  126. /** {@inheritDoc} */
  127. @Override
  128. public void addWindow(final FrameContainer window) {
  129. final FrameContainerMenuItem item = new FrameContainerMenuItem(window,
  130. this);
  131. items.put(window, item);
  132. add(item, getIndex(window, this));
  133. window.addSelectionListener(this);
  134. }
  135. /** {@inheritDoc} */
  136. @Override
  137. public void delWindow(final FrameContainer window) {
  138. if (items.containsKey(window)) {
  139. remove(items.get(window));
  140. items.remove(window);
  141. } else if (menus.containsKey(window)) {
  142. remove(menus.get(window));
  143. menus.remove(window);
  144. }
  145. window.removeSelectionListener(this);
  146. }
  147. /** {@inheritDoc} */
  148. @Override
  149. public void addWindow(final FrameContainer parent,
  150. final FrameContainer window) {
  151. final FrameContainerMenuItem item = new FrameContainerMenuItem(window,
  152. this);
  153. JMenu parentMenu;
  154. if (!menus.containsKey(parent)) {
  155. final FrameContainerMenu replacement =
  156. new FrameContainerMenu(parent, controller);
  157. replaceItemWithMenu(getParentMenu(parent), items.get(parent),
  158. replacement);
  159. parentMenu = replacement;
  160. } else {
  161. parentMenu = menus.get(parent);
  162. }
  163. items.put(window, item);
  164. parentMenu.add(item, getIndex(window, parentMenu));
  165. window.addSelectionListener(this);
  166. }
  167. /** {@inheritDoc} */
  168. @Override
  169. public void delWindow(final FrameContainer parent,
  170. final FrameContainer window) {
  171. if (items.containsKey(window)) {
  172. final JMenu menu = getParentMenu(window);
  173. menu.remove(items.get(window));
  174. items.remove(window);
  175. if (menu.getMenuComponentCount() == 1) {
  176. replaceMenuWithItem(getParentMenu(parent), menus.get(parent),
  177. new FrameContainerMenuItem(parent, this));
  178. }
  179. } else if (menus.containsKey(window)) {
  180. menus.get(parent).remove(menus.get(window));
  181. menus.remove(window);
  182. }
  183. window.removeSelectionListener(this);
  184. }
  185. private JMenu getParentMenu(final FrameContainer window) {
  186. FrameContainer parent = null;
  187. Window parentWindow = WindowManager.getParent(window.getFrame());
  188. if (parentWindow != null) {
  189. parent = parentWindow.getContainer();
  190. }
  191. if (parent == null) {
  192. return this;
  193. } else {
  194. return menus.get(parent);
  195. }
  196. }
  197. private void replaceItemWithMenu(final JMenu parentMenu,
  198. final FrameContainerMenuItem item, final FrameContainerMenu menu) {
  199. parentMenu.remove(item);
  200. parentMenu.add(menu, getIndex(menu.getFrame(), parentMenu));
  201. menu.add(item, getIndex(item.getFrame(), menu));
  202. items.remove(item.getFrame());
  203. menus.put(menu.getFrame(), menu);
  204. menuItems.put(item.getFrame(), item);
  205. }
  206. private void replaceMenuWithItem(final JMenu parentMenu,
  207. final FrameContainerMenu menu, final FrameContainerMenuItem item) {
  208. parentMenu.remove(menu);
  209. parentMenu.add(item, getIndex(item.getFrame(), parentMenu));
  210. menus.remove(menu.getFrame());
  211. items.put(item.getFrame(), item);
  212. }
  213. /**
  214. * {@inheritDoc}
  215. *
  216. * @param e Action event
  217. */
  218. @Override
  219. public void actionPerformed(final ActionEvent e) {
  220. if (enabledMenuItems.get()) {
  221. if (e.getActionCommand().equals("ToggleState")) {
  222. activeWindow.toggleMaximise();
  223. } else if (e.getActionCommand().equals("Minimise")) {
  224. activeWindow.minimise();
  225. } else if (e.getActionCommand().equals("Close")) {
  226. activeWindow.close();
  227. }
  228. }
  229. }
  230. /** {@inheritDoc} */
  231. @Override
  232. public void selectionChanged(final Window window) {
  233. activeWindow = window;
  234. final Map<FrameContainer, SelectionListener> allItems =
  235. new HashMap<FrameContainer, SelectionListener>();
  236. synchronized (allItems) {
  237. allItems.putAll(menus);
  238. for (SelectionListener menuItem : allItems.values()) {
  239. menuItem.selectionChanged(window);
  240. }
  241. allItems.clear();
  242. allItems.putAll(items);
  243. allItems.putAll(menuItems);
  244. for (SelectionListener menuItem : allItems.values()) {
  245. menuItem.selectionChanged(window);
  246. }
  247. }
  248. }
  249. /**
  250. * Tells a parent its child is selected.
  251. *
  252. * @param window parent to inform
  253. */
  254. protected void parentSelection(final FrameContainer window) {
  255. menus.get(window).childSelected();
  256. }
  257. /**
  258. * Checks and sets the state of the toggle menu item.
  259. */
  260. private void checkToggleState() {
  261. checkMenuItems();
  262. if (activeWindow != null) {
  263. toggleStateMenuItem.setEnabled(true);
  264. closeMenuItem.setEnabled(true);
  265. minimiseMenuItem.setEnabled(true);
  266. if (activeWindow.isMaximum()) {
  267. toggleStateMenuItem.setText("Restore");
  268. toggleStateMenuItem.setIcon(IconManager.getIconManager().getIcon(
  269. "restore"));
  270. toggleStateMenuItem.setMnemonic('r');
  271. } else {
  272. toggleStateMenuItem.setText("Maximise");
  273. toggleStateMenuItem.setIcon(IconManager.getIconManager().getIcon(
  274. "maximise"));
  275. toggleStateMenuItem.setMnemonic('m');
  276. }
  277. }
  278. }
  279. /**
  280. * Compares the new child with the existing children or parent to decide
  281. * where it needs to be inserted.
  282. *
  283. * @param newChild new node to be inserted.
  284. * @param menu Menu for the node to be inserted in
  285. *
  286. * @return index where new node is to be inserted.
  287. */
  288. private int getIndex(final FrameContainer newChild, final JMenu menu) {
  289. final int count = menu == this ? itemCount : 0;
  290. for (int i = count; i < menu.getMenuComponentCount(); i++) {
  291. if (!(menu.getMenuComponent(i) instanceof FrameContainerMenuItem)) {
  292. continue;
  293. }
  294. final FrameContainer child =
  295. ((FrameContainerMenuItem) menu.getMenuComponent(i)).getFrame();
  296. if (sortBefore(newChild, child)) {
  297. return i;
  298. } else if (!sortAfter(newChild, child) && IdentityManager.
  299. getGlobalConfig().getOptionBool("treeview",
  300. "sortwindows") && newChild.toString().compareToIgnoreCase(
  301. child.toString()) < 0) {
  302. return i;
  303. }
  304. }
  305. return menu.getMenuComponentCount();
  306. }
  307. /**
  308. * Compares the types of the specified nodes' objects to see if the new
  309. * node should be sorted before the other.
  310. *
  311. * @param newChild The new child to be tested
  312. * @param child The existing child that it's being tested against
  313. *
  314. * @return True iff newChild should be sorted before child
  315. */
  316. private boolean sortBefore(final FrameContainer newChild,
  317. final FrameContainer child) {
  318. return comparator.compare(newChild, child) <= -1;
  319. }
  320. /**
  321. * Compares the types of the specified nodes' objects to see if the new
  322. * node should be sorted after the other.
  323. *
  324. * @param newChild The new child to be tested
  325. * @param child The existing child that it's being tested against
  326. *
  327. * @return True iff newChild should be sorted before child
  328. */
  329. private boolean sortAfter(final FrameContainer newChild,
  330. final FrameContainer child) {
  331. return comparator.compare(newChild, child) >= 1;
  332. }
  333. /** {@inheritDoc} */
  334. @Override
  335. public void menuSelected(final MenuEvent e) {
  336. checkToggleState();
  337. }
  338. /** {@inheritDoc} */
  339. @Override
  340. public void menuDeselected(final MenuEvent e) {
  341. //Ignore
  342. }
  343. /** {@inheritDoc} */
  344. @Override
  345. public void menuCanceled(final MenuEvent e) {
  346. //Ignore
  347. }
  348. }