2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.appletgui;
20 import java.awt.BorderLayout;
21 import java.awt.Color;
22 import java.awt.FlowLayout;
24 import java.awt.Frame;
25 import java.awt.HeadlessException;
26 import java.awt.Label;
28 import java.awt.MenuBar;
29 import java.awt.Panel;
30 import java.awt.PopupMenu;
31 import java.awt.event.MouseEvent;
32 import java.awt.event.MouseListener;
33 import java.util.Enumeration;
34 import java.util.Hashtable;
37 * This class implements a pattern form embedding toolbars as a panel with
38 * popups for situations where the system menu bar is either invisible or
39 * inappropriate. It was derived from the code for embedding the jalview applet
40 * alignFrame as a component on the web-page, which requires the local
41 * alignFrame menu to be attached to that panel rather than placed on the parent
42 * (which isn't allowed anyhow). TODO: try to modify the embeddedMenu display so
43 * it looks like a real toolbar menu TODO: modify click/mouse handler for
44 * embeddedMenu so it behaves more like a real pulldown menu toolbar
46 * @author Jim Procter and Andrew Waterhouse
49 public class EmbmenuFrame extends Frame implements MouseListener
52 * map from labels to popup menus for the embedded menubar
54 protected Hashtable embeddedPopup;
57 * the embedded menu is built on this and should be added to the frame at the
58 * appropriate position.
61 protected Panel embeddedMenu;
63 public EmbmenuFrame() throws HeadlessException
68 public EmbmenuFrame(String title) throws HeadlessException
74 * Check if the applet is running on a platform that requires the Frame
75 * menuBar to be embedded, and if so, embeds it.
78 * the panel that is to be reduced to make space for the embedded
80 * @return true if menuBar was embedded and tobeAdjusted's height modified
82 protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
84 MenuBar topMenuBar = getMenuBar();
85 if (topMenuBar == null)
89 // DEBUG Hint: can test embedded menus by inserting true here.
90 if (new jalview.util.Platform().isAMac())
92 // Build the embedded menu panel
93 embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, "Arial", Font.PLAIN,
94 10, true); // try to pickup system font.
96 // add the components to the TreePanel area.
97 add(embeddedMenu, BorderLayout.NORTH);
98 tobeAdjusted.setSize(getSize().width, getSize().height
99 - embeddedMenu.HEIGHT);
106 * move all menus on menuBar onto embeddedMenu. embeddedPopup is used to store
107 * the popups for each menu removed from the menuBar and added to the panel.
108 * NOTE: it is up to the caller to remove menuBar from the Frame if it is
115 * @param overrideFonts
116 * true if we take the menuBar fonts in preference to the supplied
118 * @return the embedded menu instance to be added to the frame.
120 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
121 int fstyle, int fsz, boolean overrideFonts)
123 return makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz, overrideFonts,
128 * Create or add elements to the embedded menu from menuBar. This removes all
129 * menu from menuBar and it is up to the caller to remove the now useless
130 * menuBar from the Frame if it is already attached.
136 * @param overrideFonts
138 * true means existing menu will be emptied before adding new
142 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
143 int fstyle, int fsz, boolean overrideFonts, boolean append)
147 if (embeddedPopup != null)
149 embeddedPopup.clear(); // TODO: check if j1.1
151 if (embeddedMenu != null)
153 embeddedMenu.removeAll();
156 if (embeddedPopup == null)
158 embeddedPopup = new Hashtable();
161 embeddedMenu = makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz,
162 overrideFonts, embeddedPopup, new Panel(), this);
167 * Generic method to move elements from menubar onto embeddedMenu using the
168 * existing or the supplied font, and adds binding from panel to attached
169 * menus in embeddedPopup This removes all menu from menuBar and it is up to
170 * the caller to remove the now useless menuBar from the Frame if it is
178 * @param overrideFonts
179 * @param embeddedPopup
181 * @param embeddedMenu
182 * if null, a new panel will be created and returned
183 * @param clickHandler
184 * - usually the instance of EmbmenuFrame that holds references to
185 * embeddedPopup and embeddedMenu
186 * @return the panel instance for convenience.
188 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
189 int fstyle, int fsz, boolean overrideFonts,
190 Hashtable embeddedPopup, Panel embeddedMenu,
191 MouseListener clickHandler)
193 if (embeddedPopup == null)
196 "Implementation error - embeddedPopup must be non-null");
200 Font mbf = menuBar.getFont();
204 fstyle = mbf.getStyle();
208 if (embeddedMenu == null)
209 embeddedMenu = new Panel();
210 FlowLayout flowLayout1 = new FlowLayout();
211 embeddedMenu.setBackground(Color.lightGray);
212 embeddedMenu.setLayout(flowLayout1);
214 for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
216 Menu mi = menuBar.getMenu(mbi);
217 Label elab = new Label(mi.getLabel());
218 elab.setFont(new java.awt.Font(fn, fstyle, fsz));
219 // add the menu entries
220 PopupMenu popup = new PopupMenu();
221 int m, mSize = mi.getItemCount();
222 for (m = 0; m < mSize; m++)
224 popup.add(mi.getItem(m));
228 embeddedPopup.put(elab, popup);
229 embeddedMenu.add(elab);
230 elab.addMouseListener(clickHandler);
232 flowLayout1.setAlignment(FlowLayout.LEFT);
233 flowLayout1.setHgap(2);
234 flowLayout1.setVgap(0);
238 public void mousePressed(MouseEvent evt)
240 PopupMenu popup = null;
241 Label source = (Label) evt.getSource();
242 popup = getPopupMenu(source);
245 embeddedMenu.add(popup);
246 popup.show(embeddedMenu, source.getBounds().x, source.getBounds().y
247 + source.getBounds().getSize().height);
252 * get the menu for source from the hash.
255 * what was clicked on.
257 PopupMenu getPopupMenu(Label source)
259 return (PopupMenu) embeddedPopup.get(source);
262 public void mouseClicked(MouseEvent evt)
266 public void mouseReleased(MouseEvent evt)
270 public void mouseEntered(MouseEvent evt)
274 public void mouseExited(MouseEvent evt)
279 * called to clear the GUI resources taken up for embedding and remove any
280 * self references so we can be garbage collected.
282 public void destroyMenus()
284 if (embeddedPopup != null)
286 Enumeration e = embeddedPopup.keys();
287 while (e.hasMoreElements())
289 Label lb = (Label) e.nextElement();
290 lb.removeMouseListener(this);
292 embeddedPopup.clear();
294 if (embeddedMenu != null)
296 embeddedMenu.removeAll();
301 * calls destroyMenus()
303 public void finalize() throws Throwable
306 embeddedPopup = null;