2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ 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.Platform;
25 import java.awt.BorderLayout;
26 import java.awt.Color;
27 import java.awt.FlowLayout;
29 import awt2swing.Frame;
30 import java.awt.HeadlessException;
31 import awt2swing.Label;
32 import awt2swing.Menu;
33 import awt2swing.MenuBar;
34 import awt2swing.MenuItem;
35 import awt2swing.Panel;
36 import awt2swing.PopupMenu;
37 import java.awt.event.MouseEvent;
38 import java.awt.event.MouseListener;
39 import java.util.HashMap;
42 import javax.swing.JMenuItem;
45 * This class implements a pattern for embedding toolbars as a panel with popups
46 * for situations where the system menu bar is either invisible or
47 * inappropriate. It was derived from the code for embedding the jalview applet
48 * alignFrame as a component on the web-page, which requires the local
49 * alignFrame menu to be attached to that panel rather than placed on the parent
50 * (which isn't allowed anyhow). TODO: try to modify the embeddedMenu display so
51 * it looks like a real toolbar menu TODO: modify click/mouse handler for
52 * embeddedMenu so it behaves more like a real pulldown menu toolbar
54 * @author Jim Procter and Andrew Waterhouse
57 public class EmbmenuFrame extends Frame implements MouseListener
59 protected static final Font FONT_ARIAL_PLAIN_11 = new Font(
60 "Arial", Font.PLAIN, 11);
62 public static final Font DEFAULT_MENU_FONT = FONT_ARIAL_PLAIN_11;
65 * map from labels to popup menus for the embedded menubar
67 protected Map<Label, PopupMenu> embeddedPopup = new HashMap<Label, PopupMenu>();
70 * the embedded menu is built on this and should be added to the frame at the
71 * appropriate position.
74 protected Panel embeddedMenu;
76 public EmbmenuFrame() throws HeadlessException
81 public EmbmenuFrame(String title) throws HeadlessException
87 * Check if the applet is running on a platform that requires the Frame
88 * menuBar to be embedded, and if so, embeds it.
91 * the panel that is to be reduced to make space for the embedded
93 * @return true if menuBar was embedded and tobeAdjusted's height modified
95 protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
97 MenuBar topMenuBar = (MenuBar) getJMenuBar();
98 if (topMenuBar == null)
102 // DEBUG Hint: can test embedded menus by inserting true here.
103 if (Platform.isAMac())
105 // Build the embedded menu panel, allowing override with system font
106 embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, true, false);
108 // add the components to the Panel area.
109 add(embeddedMenu, BorderLayout.NORTH);
110 tobeAdjusted.setSize(getSize().width,
111 getSize().height - embeddedMenu.getHeight());
118 * Create or add elements to the embedded menu from menuBar. This removes all
119 * menu from menuBar and it is up to the caller to remove the now useless
120 * menuBar from the Frame if it is already attached.
123 * @param overrideFonts
125 * true means existing menu will be emptied before adding new
129 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar,
130 boolean overrideFonts, boolean append)
134 embeddedPopup.clear(); // TODO: check if j1.1
135 if (embeddedMenu != null)
137 embeddedMenu.removeAll();
140 embeddedMenu = makeEmbeddedPopupMenu(menuBar, DEFAULT_MENU_FONT,
141 overrideFonts, new Panel(), this);
146 * Generic method to move elements from menubar onto embeddedMenu using the
147 * existing or the supplied font, and adds binding from panel to attached
148 * menus in embeddedPopup This removes all menu from menuBar and it is up to
149 * the caller to remove the now useless menuBar from the Frame if it is
155 * @param overrideFonts
156 * @param embeddedMenu
157 * if null, a new panel will be created and returned
158 * @param clickHandler
159 * - usually the instance of EmbmenuFrame that holds references to
160 * embeddedPopup and embeddedMenu
161 * @return the panel instance for convenience.
163 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, Font font,
164 boolean overrideFonts,
166 MouseListener clickHandler)
171 Font mbf = menuBar.getFont();
177 if (embeddedMenu == null)
179 embeddedMenu = new Panel();
181 FlowLayout flowLayout1 = new FlowLayout();
182 embeddedMenu.setBackground(Color.lightGray);
183 embeddedMenu.setLayout(flowLayout1);
185 for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
187 Menu mi = (Menu) menuBar.getMenu(mbi);
188 Label elab = new Label(mi.getLabel());
190 // add the menu entries
191 PopupMenu popup = new PopupMenu();
192 int m, mSize = mi.getItemCount();
193 for (m = 0; m < mSize; m++)
195 // BH slight difference in Swing -- no actual item separator, just null
196 if (mi.getItem(m) == null)
197 popup.addSeparator();
199 popup.add(mi.getItem(m));
203 embeddedPopup.put(elab, popup);
204 embeddedMenu.add(elab);
205 elab.addMouseListener(clickHandler);
207 flowLayout1.setAlignment(FlowLayout.LEFT);
208 flowLayout1.setHgap(2);
209 flowLayout1.setVgap(0);
213 public void mousePressed(MouseEvent evt)
215 PopupMenu popup = null;
216 Label source = (Label) evt.getSource();
217 popup = getPopupMenu(source);
220 embeddedMenu.add(popup);
221 popup.show(embeddedMenu, source.getBounds().x, source.getBounds().y
222 + source.getBounds().getSize().height);
227 * get the menu for source from the hash.
230 * what was clicked on.
232 PopupMenu getPopupMenu(Label source)
234 return embeddedPopup.get(source);
237 public void mouseClicked(MouseEvent evt)
241 public void mouseReleased(MouseEvent evt)
245 public void mouseEntered(MouseEvent evt)
249 public void mouseExited(MouseEvent evt)
254 * called to clear the GUI resources taken up for embedding and remove any
255 * self references so we can be garbage collected.
257 public void destroyMenus()
259 if (embeddedPopup != null)
261 for (Label lb : embeddedPopup.keySet())
263 lb.removeMouseListener(this);
265 embeddedPopup.clear();
267 if (embeddedMenu != null)
269 embeddedMenu.removeAll();
274 * calls destroyMenus()
276 public void finalize() throws Throwable
279 embeddedPopup = null;