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 jalview.util.MessageManager;
25 import java.awt.BorderLayout;
26 import java.awt.Color;
27 import java.awt.FlowLayout;
29 import java.awt.Frame;
30 import java.awt.HeadlessException;
31 import java.awt.Label;
33 import java.awt.MenuBar;
34 import java.awt.Panel;
35 import java.awt.PopupMenu;
36 import java.awt.event.MouseEvent;
37 import java.awt.event.MouseListener;
38 import java.util.Enumeration;
39 import java.util.Hashtable;
42 * This class implements a pattern for embedding toolbars as a panel with popups
43 * for situations where the system menu bar is either invisible or
44 * inappropriate. It was derived from the code for embedding the jalview applet
45 * alignFrame as a component on the web-page, which requires the local
46 * alignFrame menu to be attached to that panel rather than placed on the parent
47 * (which isn't allowed anyhow). TODO: try to modify the embeddedMenu display so
48 * it looks like a real toolbar menu TODO: modify click/mouse handler for
49 * embeddedMenu so it behaves more like a real pulldown menu toolbar
51 * @author Jim Procter and Andrew Waterhouse
54 public class EmbmenuFrame extends Frame implements MouseListener
56 protected static final Font FONT_ARIAL_PLAIN_11 = new Font(
57 "Arial", Font.PLAIN, 11);
60 * map from labels to popup menus for the embedded menubar
62 protected Hashtable embeddedPopup;
65 * the embedded menu is built on this and should be added to the frame at the
66 * appropriate position.
69 protected Panel embeddedMenu;
71 public EmbmenuFrame() throws HeadlessException
76 public EmbmenuFrame(String title) throws HeadlessException
82 * Check if the applet is running on a platform that requires the Frame
83 * menuBar to be embedded, and if so, embeds it.
86 * the panel that is to be reduced to make space for the embedded
88 * @return true if menuBar was embedded and tobeAdjusted's height modified
90 protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
92 MenuBar topMenuBar = getMenuBar();
93 if (topMenuBar == null)
97 // DEBUG Hint: can test embedded menus by inserting true here.
98 if (new jalview.util.Platform().isAMac())
100 // Build the embedded menu panel
101 embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, FONT_ARIAL_PLAIN_11,
102 true, false); // try to pickup system font.
104 // add the components to the Panel area.
105 add(embeddedMenu, BorderLayout.NORTH);
106 tobeAdjusted.setSize(getSize().width,
107 getSize().height - embeddedMenu.getHeight());
114 * Create or add elements to the embedded menu from menuBar. This removes all
115 * menu from menuBar and it is up to the caller to remove the now useless
116 * menuBar from the Frame if it is already attached.
120 * @param overrideFonts
122 * true means existing menu will be emptied before adding new
126 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, Font font,
127 boolean overrideFonts, boolean append)
131 if (embeddedPopup != null)
133 embeddedPopup.clear(); // TODO: check if j1.1
135 if (embeddedMenu != null)
137 embeddedMenu.removeAll();
140 if (embeddedPopup == null)
142 embeddedPopup = new Hashtable();
145 embeddedMenu = makeEmbeddedPopupMenu(menuBar, font,
146 overrideFonts, embeddedPopup, new Panel(), this);
151 * Generic method to move elements from menubar onto embeddedMenu using the
152 * existing or the supplied font, and adds binding from panel to attached
153 * menus in embeddedPopup This removes all menu from menuBar and it is up to
154 * the caller to remove the now useless menuBar from the Frame if it is
160 * @param overrideFonts
161 * @param embeddedPopup
163 * @param embeddedMenu
164 * if null, a new panel will be created and returned
165 * @param clickHandler
166 * - usually the instance of EmbmenuFrame that holds references to
167 * embeddedPopup and embeddedMenu
168 * @return the panel instance for convenience.
170 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, Font font,
171 boolean overrideFonts,
172 Hashtable embeddedPopup, Panel embeddedMenu,
173 MouseListener clickHandler)
175 if (embeddedPopup == null)
177 throw new Error(MessageManager.getString("error.implementation_error_embeddedpopup_not_null"));
181 Font mbf = menuBar.getFont();
187 if (embeddedMenu == null)
189 embeddedMenu = new Panel();
191 FlowLayout flowLayout1 = new FlowLayout();
192 embeddedMenu.setBackground(Color.lightGray);
193 embeddedMenu.setLayout(flowLayout1);
195 for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
197 Menu mi = menuBar.getMenu(mbi);
198 Label elab = new Label(mi.getLabel());
200 // add the menu entries
201 PopupMenu popup = new PopupMenu();
202 int m, mSize = mi.getItemCount();
203 for (m = 0; m < mSize; m++)
205 popup.add(mi.getItem(m));
209 embeddedPopup.put(elab, popup);
210 embeddedMenu.add(elab);
211 elab.addMouseListener(clickHandler);
213 flowLayout1.setAlignment(FlowLayout.LEFT);
214 flowLayout1.setHgap(2);
215 flowLayout1.setVgap(0);
219 public void mousePressed(MouseEvent evt)
221 PopupMenu popup = null;
222 Label source = (Label) evt.getSource();
223 popup = getPopupMenu(source);
226 embeddedMenu.add(popup);
227 popup.show(embeddedMenu, source.getBounds().x, source.getBounds().y
228 + source.getBounds().getSize().height);
233 * get the menu for source from the hash.
236 * what was clicked on.
238 PopupMenu getPopupMenu(Label source)
240 return (PopupMenu) embeddedPopup.get(source);
243 public void mouseClicked(MouseEvent evt)
247 public void mouseReleased(MouseEvent evt)
251 public void mouseEntered(MouseEvent evt)
255 public void mouseExited(MouseEvent evt)
260 * called to clear the GUI resources taken up for embedding and remove any
261 * self references so we can be garbage collected.
263 public void destroyMenus()
265 if (embeddedPopup != null)
267 Enumeration e = embeddedPopup.keys();
268 while (e.hasMoreElements())
270 Label lb = (Label) e.nextElement();
271 lb.removeMouseListener(this);
273 embeddedPopup.clear();
275 if (embeddedMenu != null)
277 embeddedMenu.removeAll();
282 * calls destroyMenus()
284 public void finalize() throws Throwable
287 embeddedPopup = null;