2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.appletgui;
23 import java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.FlowLayout;
27 import java.awt.Frame;
28 import java.awt.HeadlessException;
29 import java.awt.Label;
31 import java.awt.MenuBar;
32 import java.awt.Panel;
33 import java.awt.PopupMenu;
34 import java.awt.event.MouseEvent;
35 import java.awt.event.MouseListener;
36 import java.util.Enumeration;
37 import java.util.Hashtable;
40 * This class implements a pattern form embedding toolbars as a panel with
41 * popups for situations where the system menu bar is either invisible or
42 * inappropriate. It was derived from the code for embedding the jalview applet
43 * alignFrame as a component on the web-page, which requires the local
44 * alignFrame menu to be attached to that panel rather than placed on the parent
45 * (which isn't allowed anyhow). TODO: try to modify the embeddedMenu display so
46 * it looks like a real toolbar menu TODO: modify click/mouse handler for
47 * embeddedMenu so it behaves more like a real pulldown menu toolbar
49 * @author Jim Procter and Andrew Waterhouse
52 public class EmbmenuFrame extends Frame implements MouseListener
55 * map from labels to popup menus for the embedded menubar
57 protected Hashtable embeddedPopup;
60 * the embedded menu is built on this and should be added to the frame at the
61 * appropriate position.
64 protected Panel embeddedMenu;
66 public EmbmenuFrame() throws HeadlessException
71 public EmbmenuFrame(String title) throws HeadlessException
77 * Check if the applet is running on a platform that requires the Frame
78 * menuBar to be embedded, and if so, embeds it.
81 * the panel that is to be reduced to make space for the embedded
83 * @return true if menuBar was embedded and tobeAdjusted's height modified
85 protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
87 MenuBar topMenuBar = getMenuBar();
88 if (topMenuBar == null)
92 // DEBUG Hint: can test embedded menus by inserting true here.
93 if (new jalview.util.Platform().isAMac())
95 // Build the embedded menu panel
96 embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, "Arial", Font.PLAIN,
97 11, true); // try to pickup system font.
99 // add the components to the TreePanel area.
100 add(embeddedMenu, BorderLayout.NORTH);
101 tobeAdjusted.setSize(getSize().width, getSize().height
102 - embeddedMenu.HEIGHT);
109 * move all menus on menuBar onto embeddedMenu. embeddedPopup is used to store
110 * the popups for each menu removed from the menuBar and added to the panel.
111 * NOTE: it is up to the caller to remove menuBar from the Frame if it is
118 * @param overrideFonts
119 * true if we take the menuBar fonts in preference to the supplied
121 * @return the embedded menu instance to be added to the frame.
123 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
124 int fstyle, int fsz, boolean overrideFonts)
126 return makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz, overrideFonts,
131 * Create or add elements to the embedded menu from menuBar. This removes all
132 * menu from menuBar and it is up to the caller to remove the now useless
133 * menuBar from the Frame if it is already attached.
139 * @param overrideFonts
141 * true means existing menu will be emptied before adding new
145 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
146 int fstyle, int fsz, boolean overrideFonts, boolean append)
150 if (embeddedPopup != null)
152 embeddedPopup.clear(); // TODO: check if j1.1
154 if (embeddedMenu != null)
156 embeddedMenu.removeAll();
159 if (embeddedPopup == null)
161 embeddedPopup = new Hashtable();
164 embeddedMenu = makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz,
165 overrideFonts, embeddedPopup, new Panel(), this);
170 * Generic method to move elements from menubar onto embeddedMenu using the
171 * existing or the supplied font, and adds binding from panel to attached
172 * menus in embeddedPopup This removes all menu from menuBar and it is up to
173 * the caller to remove the now useless menuBar from the Frame if it is
181 * @param overrideFonts
182 * @param embeddedPopup
184 * @param embeddedMenu
185 * if null, a new panel will be created and returned
186 * @param clickHandler
187 * - usually the instance of EmbmenuFrame that holds references to
188 * embeddedPopup and embeddedMenu
189 * @return the panel instance for convenience.
191 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
192 int fstyle, int fsz, boolean overrideFonts,
193 Hashtable embeddedPopup, Panel embeddedMenu,
194 MouseListener clickHandler)
196 if (embeddedPopup == null)
198 throw new Error(MessageManager.getString("error.implementation_error_embeddedpopup_not_null"));
202 Font mbf = menuBar.getFont();
206 fstyle = mbf.getStyle();
210 if (embeddedMenu == null)
211 embeddedMenu = new Panel();
212 FlowLayout flowLayout1 = new FlowLayout();
213 embeddedMenu.setBackground(Color.lightGray);
214 embeddedMenu.setLayout(flowLayout1);
216 for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
218 Menu mi = menuBar.getMenu(mbi);
219 Label elab = new Label(mi.getLabel());
220 elab.setFont(new java.awt.Font(fn, fstyle, fsz));
221 // add the menu entries
222 PopupMenu popup = new PopupMenu();
223 int m, mSize = mi.getItemCount();
224 for (m = 0; m < mSize; m++)
226 popup.add(mi.getItem(m));
230 embeddedPopup.put(elab, popup);
231 embeddedMenu.add(elab);
232 elab.addMouseListener(clickHandler);
234 flowLayout1.setAlignment(FlowLayout.LEFT);
235 flowLayout1.setHgap(2);
236 flowLayout1.setVgap(0);
240 public void mousePressed(MouseEvent evt)
242 PopupMenu popup = null;
243 Label source = (Label) evt.getSource();
244 popup = getPopupMenu(source);
247 embeddedMenu.add(popup);
248 popup.show(embeddedMenu, source.getBounds().x, source.getBounds().y
249 + source.getBounds().getSize().height);
254 * get the menu for source from the hash.
257 * what was clicked on.
259 PopupMenu getPopupMenu(Label source)
261 return (PopupMenu) embeddedPopup.get(source);
264 public void mouseClicked(MouseEvent evt)
268 public void mouseReleased(MouseEvent evt)
272 public void mouseEntered(MouseEvent evt)
276 public void mouseExited(MouseEvent evt)
281 * called to clear the GUI resources taken up for embedding and remove any
282 * self references so we can be garbage collected.
284 public void destroyMenus()
286 if (embeddedPopup != null)
288 Enumeration e = embeddedPopup.keys();
289 while (e.hasMoreElements())
291 Label lb = (Label) e.nextElement();
292 lb.removeMouseListener(this);
294 embeddedPopup.clear();
296 if (embeddedMenu != null)
298 embeddedMenu.removeAll();
303 * calls destroyMenus()
305 public void finalize() throws Throwable
308 embeddedPopup = null;