1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.menubar; 18 19 import org.eclipse.jface.action.IAction; 20 import org.eclipse.jface.action.IMenuManager; 21 import org.eclipse.jface.action.Separator; 22 import org.eclipse.swt.SWT; 23 import org.eclipse.swt.events.SelectionAdapter; 24 import org.eclipse.swt.events.SelectionEvent; 25 import org.eclipse.swt.widgets.Display; 26 import org.eclipse.swt.widgets.Menu; 27 import org.eclipse.swt.widgets.MenuItem; 28 29 30 /** 31 * On Mac, {@link MenuBarEnhancer#setupMenu} plugs a listener on the About and the 32 * Preferences menu items of the standard "application" menu in the menu bar. 33 * On Windows or Linux, it adds relevant items to a given {@link Menu} linked to 34 * the same listeners. 35 */ 36 public final class MenuBarEnhancer { 37 38 private MenuBarEnhancer() { 39 } 40 41 /** 42 * Creates an instance of {@link IMenuBarEnhancer} specific to the current platform 43 * and invoke its {@link IMenuBarEnhancer#setupMenu} to updates the menu bar. 44 * <p/> 45 * Depending on the platform, this will either hook into the existing About menu item 46 * and a Preferences or Options menu item or add new ones to the given {@code swtMenu}. 47 * Depending on the platform, the menu items might be decorated with the 48 * given {@code appName}. 49 * <p/> 50 * Potential errors are reported through {@link IMenuBarCallback}. 51 * 52 * @param appName Name used for the About menu item and similar. Must not be null. 53 * @param swtMenu For non-mac platform this is the menu where the "About" and 54 * the "Options" menu items are created. Typically the menu might be 55 * called "Tools". Must not be null. 56 * @param callbacks Callbacks called when "About" and "Preferences" menu items are invoked. 57 * Must not be null. 58 * @return A actual {@link IMenuBarEnhancer} implementation. Never null. 59 * This is currently not of any use for the caller but is left in case 60 * we want to expand the functionality later. 61 */ 62 public static IMenuBarEnhancer setupMenu( 63 String appName, 64 final Menu swtMenu, 65 IMenuBarCallback callbacks) { 66 67 IMenuBarEnhancer enhancer = getEnhancer(callbacks); 68 69 // Default implementation for generic platforms 70 if (enhancer == null) { 71 enhancer = new IMenuBarEnhancer() { 72 73 public MenuBarMode getMenuBarMode() { 74 return MenuBarMode.GENERIC; 75 } 76 77 public void setupMenu( 78 String appName, 79 Display display, 80 final IMenuBarCallback callbacks) { 81 if (swtMenu.getItemCount() > 0) { 82 new MenuItem(swtMenu, SWT.SEPARATOR); 83 } 84 85 // Note: we use "Preferences" on Mac and "Options" on Windows/Linux. 86 final MenuItem pref = new MenuItem(swtMenu, SWT.NONE); 87 pref.setText("&Options..."); 88 89 final MenuItem about = new MenuItem(swtMenu, SWT.NONE); 90 about.setText("&About..."); 91 92 pref.addSelectionListener(new SelectionAdapter() { 93 @Override 94 public void widgetSelected(SelectionEvent e) { 95 try { 96 pref.setEnabled(false); 97 callbacks.onPreferencesMenuSelected(); 98 super.widgetSelected(e); 99 } finally { 100 pref.setEnabled(true); 101 } 102 } 103 }); 104 105 about.addSelectionListener(new SelectionAdapter() { 106 @Override 107 public void widgetSelected(SelectionEvent e) { 108 try { 109 about.setEnabled(false); 110 callbacks.onAboutMenuSelected(); 111 super.widgetSelected(e); 112 } finally { 113 about.setEnabled(true); 114 } 115 } 116 }); 117 } 118 }; 119 } 120 121 enhancer.setupMenu(appName, swtMenu.getDisplay(), callbacks); 122 return enhancer; 123 } 124 125 126 public static IMenuBarEnhancer setupMenuManager( 127 String appName, 128 Display display, 129 final IMenuManager menuManager, 130 final IAction aboutAction, 131 final IAction preferencesAction, 132 final IAction quitAction) { 133 134 IMenuBarCallback callbacks = new IMenuBarCallback() { 135 public void printError(String format, Object... args) { 136 System.err.println(String.format(format, args)); 137 } 138 139 public void onPreferencesMenuSelected() { 140 if (preferencesAction != null) { 141 preferencesAction.run(); 142 } 143 } 144 145 public void onAboutMenuSelected() { 146 if (aboutAction != null) { 147 aboutAction.run(); 148 } 149 } 150 }; 151 152 IMenuBarEnhancer enhancer = getEnhancer(callbacks); 153 154 // Default implementation for generic platforms 155 if (enhancer == null) { 156 enhancer = new IMenuBarEnhancer() { 157 158 public MenuBarMode getMenuBarMode() { 159 return MenuBarMode.GENERIC; 160 } 161 162 public void setupMenu( 163 String appName, 164 Display display, 165 final IMenuBarCallback callbacks) { 166 if (!menuManager.isEmpty()) { 167 menuManager.add(new Separator()); 168 } 169 170 if (aboutAction != null) { 171 menuManager.add(aboutAction); 172 } 173 if (preferencesAction != null) { 174 menuManager.add(preferencesAction); 175 } 176 if (quitAction != null) { 177 if (aboutAction != null || preferencesAction != null) { 178 menuManager.add(new Separator()); 179 } 180 menuManager.add(quitAction); 181 } 182 } 183 }; 184 } 185 186 enhancer.setupMenu(appName, display, callbacks); 187 return enhancer; 188 } 189 190 private static IMenuBarEnhancer getEnhancer(IMenuBarCallback callbacks) { 191 IMenuBarEnhancer enhancer = null; 192 String p = SWT.getPlatform(); 193 String className = null; 194 if ("cocoa".equals(p)) { //$NON-NLS-1$ 195 className = "com.android.menubar.internal.MenuBarEnhancerCocoa"; //$NON-NLS-1$ 196 } 197 198 if (System.getenv("DEBUG_SWTMENUBAR") != null) { 199 callbacks.printError("DEBUG SwtMenuBar: SWT=%1$s, class=%2$s", p, className); 200 } 201 202 if (className != null) { 203 try { 204 Class<?> clazz = Class.forName(className); 205 enhancer = (IMenuBarEnhancer) clazz.newInstance(); 206 } catch (Exception e) { 207 // Log an error and fallback on the default implementation. 208 callbacks.printError( 209 "Failed to instantiate %1$s: %2$s", //$NON-NLS-1$ 210 className, 211 e.toString()); 212 } 213 } 214 return enhancer; 215 } 216 } 217