1 package jalview.appletgui;
\r
3 import java.awt.BorderLayout;
\r
4 import java.awt.Color;
\r
5 import java.awt.Container;
\r
6 import java.awt.FlowLayout;
\r
7 import java.awt.Font;
\r
8 import java.awt.Frame;
\r
9 import java.awt.GraphicsConfiguration;
\r
10 import java.awt.HeadlessException;
\r
11 import java.awt.Label;
\r
12 import java.awt.Menu;
\r
13 import java.awt.MenuBar;
\r
14 import java.awt.Panel;
\r
15 import java.awt.PopupMenu;
\r
16 import java.awt.event.ActionListener;
\r
17 import java.awt.event.ItemListener;
\r
18 import java.awt.event.MouseEvent;
\r
19 import java.awt.event.MouseListener;
\r
20 import java.util.Enumeration;
\r
21 import java.util.Hashtable;
\r
23 * This class implements a pattern form embedding toolbars as a panel with popups
\r
24 * for situations where the system menu bar is either invisible or inappropriate.
\r
25 * It was derived from the code for embedding the jalview applet alignFrame as
\r
26 * a component on the web-page, which requires the local alignFrame menu to be
\r
27 * attached to that panel rather than placed on the parent (which isn't allowed
\r
29 * TODO: try to modify the embeddedMenu display so it looks like a real toolbar menu
\r
30 * TODO: modify click/mouse handler for embeddedMenu so it behaves more like a real pulldown menu toolbar
\r
32 * @author Jim Procter and Andrew Waterhouse
\r
35 public class EmbmenuFrame extends Frame implements MouseListener
\r
38 * map from labels to popup menus for the embedded menubar
\r
40 protected Hashtable embeddedPopup;
\r
42 * the embedded menu is built on this and should be
\r
43 * added to the frame at the appropriate position.
\r
46 protected Panel embeddedMenu;
\r
48 public EmbmenuFrame() throws HeadlessException
\r
52 public EmbmenuFrame(String title) throws HeadlessException
\r
57 * Check if the applet is running on a platform that requires the Frame menuBar to be embedded,
\r
58 * and if so, embeds it.
\r
59 * @param tobeAdjusted the panel that is to be reduced to make space for the embedded menu bar
\r
60 * @return true if menuBar was embedded and tobeAdjusted's height modified
\r
62 protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
\r
64 MenuBar topMenuBar = getMenuBar();
\r
65 if (topMenuBar==null)
\r
69 // DEBUG Hint: can test embedded menus by inserting true here.
\r
70 if (new jalview.util.Platform().isAMac())
\r
72 // Build the embedded menu panel
\r
73 embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, "Arial", Font.PLAIN, 10, true); // try to pickup system font.
\r
75 // add the components to the TreePanel area.
\r
76 add(embeddedMenu, BorderLayout.NORTH);
\r
77 tobeAdjusted.setSize(getSize().width,
\r
79 - embeddedMenu.HEIGHT);
\r
85 * move all menus on menuBar onto embeddedMenu.
\r
86 * embeddedPopup is used to store the popups for each menu removed from the menuBar and added
\r
88 * NOTE: it is up to the caller to remove menuBar from the Frame if it is already attached.
\r
93 * @param overrideFonts true if we take the menuBar fonts in preference to the supplied defaults
\r
94 * @return the embedded menu instance to be added to the frame.
\r
96 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
\r
97 int fstyle, int fsz, boolean overrideFonts)
\r
99 return makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz, overrideFonts, false);
\r
102 * Create or add elements to the embedded menu from menuBar. This removes all menu from
\r
103 * menuBar and it is up to the caller to remove the now useless menuBar from the Frame if it is already attached.
\r
108 * @param overrideFonts
\r
109 * @param append true means existing menu will be emptied before adding new elements
\r
112 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
\r
113 int fstyle, int fsz, boolean overrideFonts, boolean append)
\r
117 if (embeddedPopup != null)
\r
119 embeddedPopup.clear(); // TODO: check if j1.1
\r
121 if (embeddedMenu!=null)
\r
123 embeddedMenu.removeAll();
\r
126 if (embeddedPopup==null)
\r
128 embeddedPopup = new Hashtable();
\r
131 embeddedMenu = makeEmbeddedPopupMenu(menuBar, fn, fstyle, fsz, overrideFonts, embeddedPopup, new Panel(), this);
\r
132 return embeddedMenu;
\r
135 * Generic method to move elements from menubar onto embeddedMenu using the existing or the supplied font,
\r
136 * and adds binding from panel to attached menus in embeddedPopup
\r
137 * This removes all menu from
\r
138 * menuBar and it is up to the caller to remove the now useless menuBar from the Frame if it is already attached.
\r
139 * @param menuBar must be non-null
\r
143 * @param overrideFonts
\r
144 * @param embeddedPopup must be non-null
\r
145 * @param embeddedMenu if null, a new panel will be created and returned
\r
146 * @param clickHandler - usually the instance of EmbmenuFrame that holds references to embeddedPopup and embeddedMenu
\r
147 * @return the panel instance for convenience.
\r
149 protected Panel makeEmbeddedPopupMenu(MenuBar menuBar, String fn,
\r
150 int fstyle, int fsz, boolean overrideFonts, Hashtable embeddedPopup, Panel embeddedMenu, MouseListener clickHandler)
\r
152 if (embeddedPopup==null)
\r
154 throw new Error("Implementation error - embeddedPopup must be non-null");
\r
158 Font mbf = menuBar.getFont();
\r
161 fn = mbf.getName();
\r
162 fstyle = mbf.getStyle();
\r
163 fsz = mbf.getSize();
\r
166 if (embeddedMenu==null)
\r
167 embeddedMenu = new Panel();
\r
168 FlowLayout flowLayout1 = new FlowLayout();
\r
169 embeddedMenu.setBackground(Color.lightGray);
\r
170 embeddedMenu.setLayout(flowLayout1);
\r
172 for (int mbi = 0,nMbi=menuBar.getMenuCount(); mbi<nMbi; mbi++)
\r
174 Menu mi = menuBar.getMenu(mbi);
\r
175 Label elab = new Label(mi.getLabel());
\r
176 elab.setFont(new java.awt.Font(fn, fstyle, fsz));
\r
177 // add the menu entries
\r
178 PopupMenu popup = new PopupMenu();
\r
179 int m, mSize = mi.getItemCount();
\r
180 for (m = 0; m < mSize; m++)
\r
182 popup.add(mi.getItem(m));
\r
186 embeddedPopup.put(elab, popup);
\r
187 embeddedMenu.add(elab);
\r
188 elab.addMouseListener(clickHandler);
\r
190 flowLayout1.setAlignment(FlowLayout.LEFT);
\r
191 flowLayout1.setHgap(2);
\r
192 flowLayout1.setVgap(0);
\r
193 return embeddedMenu;
\r
196 public void mousePressed(MouseEvent evt)
\r
198 PopupMenu popup = null;
\r
199 Label source = (Label) evt.getSource();
\r
200 popup = getPopupMenu(source);
\r
203 embeddedMenu.add(popup);
\r
204 popup.show(embeddedMenu,
\r
205 source.getBounds().x,
\r
206 source.getBounds().y + source.getBounds().getSize().height);
\r
211 * get the menu for source from the hash.
\r
212 * @param source what was clicked on.
\r
214 PopupMenu getPopupMenu(Label source)
\r
216 return (PopupMenu) embeddedPopup.get(source);
\r
219 public void mouseClicked(MouseEvent evt)
\r
222 public void mouseReleased(MouseEvent evt)
\r
225 public void mouseEntered(MouseEvent evt)
\r
228 public void mouseExited(MouseEvent evt)
\r
232 * called to clear the GUI resources taken up for embedding
\r
233 * and remove any self references so we can be garbage collected.
\r
235 public void destroyMenus()
\r
237 if (embeddedPopup!=null)
\r
239 Enumeration e = embeddedPopup.keys();
\r
240 while (e.hasMoreElements())
\r
242 Label lb = (Label) e.nextElement();
\r
243 lb.removeMouseListener(this);
\r
245 embeddedPopup.clear();
\r
247 if (embeddedMenu!=null)
\r
249 embeddedMenu.removeAll();
\r
253 * calls destroyMenus()
\r
255 public void finalize() throws Throwable {
\r
257 embeddedPopup=null;
\r