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.Container;
23 import java.awt.FlowLayout;
25 import java.awt.Frame;
26 import java.awt.GraphicsConfiguration;
27 import java.awt.HeadlessException;
28 import java.awt.Label;
30 import java.awt.MenuBar;
31 import java.awt.Panel;
32 import java.awt.PopupMenu;
33 import java.awt.event.ActionListener;
34 import java.awt.event.ItemListener;
35 import java.awt.event.MouseEvent;
36 import java.awt.event.MouseListener;
37 import java.util.Enumeration;
38 import java.util.Hashtable;
41 * This class implements a pattern form embedding toolbars as a panel with
42 * popups for situations where the system menu bar is either invisible or
43 * inappropriate. It was derived from the code for embedding the jalview applet
44 * alignFrame as a component on the web-page, which requires the local
45 * alignFrame menu to be attached to that panel rather than placed on the parent
46 * (which isn't allowed anyhow). TODO: try to modify the embeddedMenu display so
47 * it looks like a real toolbar menu TODO: modify click/mouse handler for
48 * embeddedMenu so it behaves more like a real pulldown menu toolbar
50 * @author Jim Procter and Andrew Waterhouse
53 public class EmbmenuFrame extends Frame implements MouseListener
56 * map from labels to popup menus for the embedded menubar
58 protected Hashtable embeddedPopup;
61 * the embedded menu is built on this and should be added to the frame at the
62 * appropriate position.
65 protected Panel embeddedMenu;
67 public EmbmenuFrame() throws HeadlessException
72 public EmbmenuFrame(String title) throws HeadlessException
78 * Check if the applet is running on a platform that requires the Frame
79 * menuBar to be embedded, and if so, embeds it.
82 * the panel that is to be reduced to make space for the embedded
84 * @return true if menuBar was embedded and tobeAdjusted's height modified
86 protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
88 MenuBar topMenuBar = getMenuBar();
89 if (topMenuBar == null)
93 // DEBUG Hint: can test embedded menus by inserting true here.
94 if (new jalview.util.Platform().isAMac())
96 // Build the embedded menu panel
97 embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, "Arial", Font.PLAIN,
98 10, true); // try to pickup system font.
100 // add the components to the TreePanel area.
101 add(embeddedMenu, BorderLayout.NORTH);
102 tobeAdjusted.setSize(getSize().width, getSize().height
103 - embeddedMenu.HEIGHT);
110 * move all menus on menuBar onto embeddedMenu. embeddedPopup is used to store
111 * the popups for each menu removed from the menuBar and added to the panel.
112 * NOTE: it is up to the caller to remove menuBar from the Frame if it is
119 * @param overrideFonts
120 * true if we take the menuBar fonts in preference to the supplied
122 * @return the embedded menu instance to be added to the frame.
124 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
125 int fstyle, int fsz, boolean overrideFonts)
127 return makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz, overrideFonts,
132 * Create or add elements to the embedded menu from menuBar. This removes all
133 * menu from menuBar and it is up to the caller to remove the now useless
134 * menuBar from the Frame if it is already attached.
140 * @param overrideFonts
142 * true means existing menu will be emptied before adding new
146 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
147 int fstyle, int fsz, boolean overrideFonts, boolean append)
151 if (embeddedPopup != null)
153 embeddedPopup.clear(); // TODO: check if j1.1
155 if (embeddedMenu != null)
157 embeddedMenu.removeAll();
160 if (embeddedPopup == null)
162 embeddedPopup = new Hashtable();
165 embeddedMenu = makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz,
166 overrideFonts, embeddedPopup, new Panel(), this);
171 * Generic method to move elements from menubar onto embeddedMenu using the
172 * existing or the supplied font, and adds binding from panel to attached
173 * menus in embeddedPopup This removes all menu from menuBar and it is up to
174 * the caller to remove the now useless menuBar from the Frame if it is
182 * @param overrideFonts
183 * @param embeddedPopup
185 * @param embeddedMenu
186 * if null, a new panel will be created and returned
187 * @param clickHandler
188 * - usually the instance of EmbmenuFrame that holds references to
189 * embeddedPopup and embeddedMenu
190 * @return the panel instance for convenience.
192 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
193 int fstyle, int fsz, boolean overrideFonts,
194 Hashtable embeddedPopup, Panel embeddedMenu,
195 MouseListener clickHandler)
197 if (embeddedPopup == null)
200 "Implementation error - embeddedPopup must be non-null");
204 Font mbf = menuBar.getFont();
208 fstyle = mbf.getStyle();
212 if (embeddedMenu == null)
213 embeddedMenu = new Panel();
214 FlowLayout flowLayout1 = new FlowLayout();
215 embeddedMenu.setBackground(Color.lightGray);
216 embeddedMenu.setLayout(flowLayout1);
218 for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
220 Menu mi = menuBar.getMenu(mbi);
221 Label elab = new Label(mi.getLabel());
222 elab.setFont(new java.awt.Font(fn, fstyle, fsz));
223 // add the menu entries
224 PopupMenu popup = new PopupMenu();
225 int m, mSize = mi.getItemCount();
226 for (m = 0; m < mSize; m++)
228 popup.add(mi.getItem(m));
232 embeddedPopup.put(elab, popup);
233 embeddedMenu.add(elab);
234 elab.addMouseListener(clickHandler);
236 flowLayout1.setAlignment(FlowLayout.LEFT);
237 flowLayout1.setHgap(2);
238 flowLayout1.setVgap(0);
242 public void mousePressed(MouseEvent evt)
244 PopupMenu popup = null;
245 Label source = (Label) evt.getSource();
246 popup = getPopupMenu(source);
249 embeddedMenu.add(popup);
250 popup.show(embeddedMenu, source.getBounds().x, source.getBounds().y
251 + source.getBounds().getSize().height);
256 * get the menu for source from the hash.
259 * what was clicked on.
261 PopupMenu getPopupMenu(Label source)
263 return (PopupMenu) embeddedPopup.get(source);
266 public void mouseClicked(MouseEvent evt)
270 public void mouseReleased(MouseEvent evt)
274 public void mouseEntered(MouseEvent evt)
278 public void mouseExited(MouseEvent evt)
283 * called to clear the GUI resources taken up for embedding and remove any
284 * self references so we can be garbage collected.
286 public void destroyMenus()
288 if (embeddedPopup != null)
290 Enumeration e = embeddedPopup.keys();
291 while (e.hasMoreElements())
293 Label lb = (Label) e.nextElement();
294 lb.removeMouseListener(this);
296 embeddedPopup.clear();
298 if (embeddedMenu != null)
300 embeddedMenu.removeAll();
305 * calls destroyMenus()
307 public void finalize() throws Throwable
310 embeddedPopup = null;