2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
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 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/>.
17 * The Jalview Authors are detailed in the 'AUTHORS' file.
19 package jalview.appletgui;
21 import java.awt.BorderLayout;
22 import java.awt.Color;
23 import java.awt.FlowLayout;
25 import java.awt.Frame;
26 import java.awt.HeadlessException;
27 import java.awt.Label;
29 import java.awt.MenuBar;
30 import java.awt.Panel;
31 import java.awt.PopupMenu;
32 import java.awt.event.MouseEvent;
33 import java.awt.event.MouseListener;
34 import java.util.Enumeration;
35 import java.util.Hashtable;
38 * This class implements a pattern form embedding toolbars as a panel with
39 * popups for situations where the system menu bar is either invisible or
40 * inappropriate. It was derived from the code for embedding the jalview applet
41 * alignFrame as a component on the web-page, which requires the local
42 * alignFrame menu to be attached to that panel rather than placed on the parent
43 * (which isn't allowed anyhow). TODO: try to modify the embeddedMenu display so
44 * it looks like a real toolbar menu TODO: modify click/mouse handler for
45 * embeddedMenu so it behaves more like a real pulldown menu toolbar
47 * @author Jim Procter and Andrew Waterhouse
50 public class EmbmenuFrame extends Frame implements MouseListener
53 * map from labels to popup menus for the embedded menubar
55 protected Hashtable embeddedPopup;
58 * the embedded menu is built on this and should be added to the frame at the
59 * appropriate position.
62 protected Panel embeddedMenu;
64 public EmbmenuFrame() throws HeadlessException
69 public EmbmenuFrame(String title) throws HeadlessException
75 * Check if the applet is running on a platform that requires the Frame
76 * menuBar to be embedded, and if so, embeds it.
79 * the panel that is to be reduced to make space for the embedded
81 * @return true if menuBar was embedded and tobeAdjusted's height modified
83 protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
85 MenuBar topMenuBar = getMenuBar();
86 if (topMenuBar == null)
90 // DEBUG Hint: can test embedded menus by inserting true here.
91 if (new jalview.util.Platform().isAMac())
93 // Build the embedded menu panel
94 embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, "Arial", Font.PLAIN,
95 11, true); // try to pickup system font.
97 // add the components to the TreePanel area.
98 add(embeddedMenu, BorderLayout.NORTH);
99 tobeAdjusted.setSize(getSize().width, getSize().height
100 - embeddedMenu.HEIGHT);
107 * move all menus on menuBar onto embeddedMenu. embeddedPopup is used to store
108 * the popups for each menu removed from the menuBar and added to the panel.
109 * NOTE: it is up to the caller to remove menuBar from the Frame if it is
116 * @param overrideFonts
117 * true if we take the menuBar fonts in preference to the supplied
119 * @return the embedded menu instance to be added to the frame.
121 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
122 int fstyle, int fsz, boolean overrideFonts)
124 return makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz, overrideFonts,
129 * Create or add elements to the embedded menu from menuBar. This removes all
130 * menu from menuBar and it is up to the caller to remove the now useless
131 * menuBar from the Frame if it is already attached.
137 * @param overrideFonts
139 * true means existing menu will be emptied before adding new
143 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
144 int fstyle, int fsz, boolean overrideFonts, boolean append)
148 if (embeddedPopup != null)
150 embeddedPopup.clear(); // TODO: check if j1.1
152 if (embeddedMenu != null)
154 embeddedMenu.removeAll();
157 if (embeddedPopup == null)
159 embeddedPopup = new Hashtable();
162 embeddedMenu = makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz,
163 overrideFonts, embeddedPopup, new Panel(), this);
168 * Generic method to move elements from menubar onto embeddedMenu using the
169 * existing or the supplied font, and adds binding from panel to attached
170 * menus in embeddedPopup This removes all menu from menuBar and it is up to
171 * the caller to remove the now useless menuBar from the Frame if it is
179 * @param overrideFonts
180 * @param embeddedPopup
182 * @param embeddedMenu
183 * if null, a new panel will be created and returned
184 * @param clickHandler
185 * - usually the instance of EmbmenuFrame that holds references to
186 * embeddedPopup and embeddedMenu
187 * @return the panel instance for convenience.
189 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
190 int fstyle, int fsz, boolean overrideFonts,
191 Hashtable embeddedPopup, Panel embeddedMenu,
192 MouseListener clickHandler)
194 if (embeddedPopup == null)
197 "Implementation error - embeddedPopup must be non-null");
201 Font mbf = menuBar.getFont();
205 fstyle = mbf.getStyle();
209 if (embeddedMenu == null)
210 embeddedMenu = new Panel();
211 FlowLayout flowLayout1 = new FlowLayout();
212 embeddedMenu.setBackground(Color.lightGray);
213 embeddedMenu.setLayout(flowLayout1);
215 for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
217 Menu mi = menuBar.getMenu(mbi);
218 Label elab = new Label(mi.getLabel());
219 elab.setFont(new java.awt.Font(fn, fstyle, fsz));
220 // add the menu entries
221 PopupMenu popup = new PopupMenu();
222 int m, mSize = mi.getItemCount();
223 for (m = 0; m < mSize; m++)
225 popup.add(mi.getItem(m));
229 embeddedPopup.put(elab, popup);
230 embeddedMenu.add(elab);
231 elab.addMouseListener(clickHandler);
233 flowLayout1.setAlignment(FlowLayout.LEFT);
234 flowLayout1.setHgap(2);
235 flowLayout1.setVgap(0);
239 public void mousePressed(MouseEvent evt)
241 PopupMenu popup = null;
242 Label source = (Label) evt.getSource();
243 popup = getPopupMenu(source);
246 embeddedMenu.add(popup);
247 popup.show(embeddedMenu, source.getBounds().x, source.getBounds().y
248 + source.getBounds().getSize().height);
253 * get the menu for source from the hash.
256 * what was clicked on.
258 PopupMenu getPopupMenu(Label source)
260 return (PopupMenu) embeddedPopup.get(source);
263 public void mouseClicked(MouseEvent evt)
267 public void mouseReleased(MouseEvent evt)
271 public void mouseEntered(MouseEvent evt)
275 public void mouseExited(MouseEvent evt)
280 * called to clear the GUI resources taken up for embedding and remove any
281 * self references so we can be garbage collected.
283 public void destroyMenus()
285 if (embeddedPopup != null)
287 Enumeration e = embeddedPopup.keys();
288 while (e.hasMoreElements())
290 Label lb = (Label) e.nextElement();
291 lb.removeMouseListener(this);
293 embeddedPopup.clear();
295 if (embeddedMenu != null)
297 embeddedMenu.removeAll();
302 * calls destroyMenus()
304 public void finalize() throws Throwable
307 embeddedPopup = null;