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)
199 "Implementation error - embeddedPopup must be non-null");
203 Font mbf = menuBar.getFont();
207 fstyle = mbf.getStyle();
211 if (embeddedMenu == null)
212 embeddedMenu = new Panel();
213 FlowLayout flowLayout1 = new FlowLayout();
214 embeddedMenu.setBackground(Color.lightGray);
215 embeddedMenu.setLayout(flowLayout1);
217 for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
219 Menu mi = menuBar.getMenu(mbi);
220 Label elab = new Label(mi.getLabel());
221 elab.setFont(new java.awt.Font(fn, fstyle, fsz));
222 // add the menu entries
223 PopupMenu popup = new PopupMenu();
224 int m, mSize = mi.getItemCount();
225 for (m = 0; m < mSize; m++)
227 popup.add(mi.getItem(m));
231 embeddedPopup.put(elab, popup);
232 embeddedMenu.add(elab);
233 elab.addMouseListener(clickHandler);
235 flowLayout1.setAlignment(FlowLayout.LEFT);
236 flowLayout1.setHgap(2);
237 flowLayout1.setVgap(0);
241 public void mousePressed(MouseEvent evt)
243 PopupMenu popup = null;
244 Label source = (Label) evt.getSource();
245 popup = getPopupMenu(source);
248 embeddedMenu.add(popup);
249 popup.show(embeddedMenu, source.getBounds().x, source.getBounds().y
250 + source.getBounds().getSize().height);
255 * get the menu for source from the hash.
258 * what was clicked on.
260 PopupMenu getPopupMenu(Label source)
262 return (PopupMenu) embeddedPopup.get(source);
265 public void mouseClicked(MouseEvent evt)
269 public void mouseReleased(MouseEvent evt)
273 public void mouseEntered(MouseEvent evt)
277 public void mouseExited(MouseEvent evt)
282 * called to clear the GUI resources taken up for embedding and remove any
283 * self references so we can be garbage collected.
285 public void destroyMenus()
287 if (embeddedPopup != null)
289 Enumeration e = embeddedPopup.keys();
290 while (e.hasMoreElements())
292 Label lb = (Label) e.nextElement();
293 lb.removeMouseListener(this);
295 embeddedPopup.clear();
297 if (embeddedMenu != null)
299 embeddedMenu.removeAll();
304 * calls destroyMenus()
306 public void finalize() throws Throwable
309 embeddedPopup = null;