1 19 20 package org.netbeans.core.windows.view.ui; 21 22 import java.awt.Dimension ; 23 import java.awt.KeyboardFocusManager ; 24 import java.awt.Rectangle ; 25 import java.awt.event.ActionEvent ; 26 import java.awt.event.ActionListener ; 27 import java.awt.event.InputEvent ; 28 import java.awt.event.KeyEvent ; 29 import java.awt.event.WindowEvent ; 30 import java.awt.event.WindowFocusListener ; 31 import javax.swing.AbstractAction ; 32 import javax.swing.JWindow ; 33 import javax.swing.SwingUtilities ; 34 import javax.swing.Timer ; 35 import org.netbeans.core.windows.WindowManagerImpl; 36 import org.netbeans.core.windows.actions.RecentViewListAction; 37 import org.netbeans.swing.popupswitcher.SwitcherTable; 38 import org.netbeans.swing.popupswitcher.SwitcherTableItem; 39 import org.openide.awt.StatusDisplayer; 40 import org.openide.util.Utilities; 41 import org.openide.windows.WindowManager; 42 43 51 public final class KeyboardPopupSwitcher implements WindowFocusListener { 52 53 54 private static final int TIME_TO_SHOW = 200; 55 56 57 private static KeyboardPopupSwitcher instance; 58 59 63 private static JWindow popup; 64 65 66 private static boolean shown; 67 68 72 private static Timer invokerTimer; 73 74 78 private static boolean invokerTimerRunning; 79 80 86 private static int hits; 87 88 92 private static SwitcherTableItem[] items; 93 94 private SwitcherTable pTable; 95 96 private static int triggerKey; private static int reverseKey = KeyEvent.VK_SHIFT; 98 private static int releaseKey; 100 private int x; 101 private int y; 102 103 104 private boolean fwd = true; 105 106 110 public static boolean processShortcut(KeyEvent kev) { 111 WindowManagerImpl wmi = WindowManagerImpl.getInstance(); 112 if (!wmi.getMainWindow().isFocused() && 114 !wmi.isSeparateWindow(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow())) { 115 return false; 116 } 117 118 boolean isCtrlTab = kev.getKeyCode() == KeyEvent.VK_TAB && 119 kev.getModifiers() == InputEvent.CTRL_MASK; 120 boolean isCtrlShiftTab = kev.getKeyCode() == KeyEvent.VK_TAB && 121 kev.getModifiers() == (InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK); 122 if (KeyboardPopupSwitcher.isShown()) { 123 assert instance != null; 124 instance.processKeyEvent(kev); 125 kev.consume(); 127 return true; 128 } 129 if ((isCtrlTab || isCtrlShiftTab)) { if (KeyboardPopupSwitcher.isAlive()) { 131 KeyboardPopupSwitcher.processInterruption(kev); 132 } else { 133 AbstractAction rva = new RecentViewListAction(); 134 rva.actionPerformed(new ActionEvent (kev.getSource(), 135 ActionEvent.ACTION_PERFORMED, "C-TAB")); 136 return true; 137 } 138 kev.consume(); 142 return true; 143 } 144 if (kev.getKeyCode() == KeyEvent.VK_CONTROL && KeyboardPopupSwitcher.isAlive()) { 145 KeyboardPopupSwitcher.processInterruption(kev); 146 return true; 147 } 148 return false; 149 } 150 151 164 public static void selectItem(SwitcherTableItem items[], int releaseKey, 165 int triggerKey) { 166 if (invokerTimerRunning) { 168 return; 169 } 170 KeyboardPopupSwitcher.items = items; 171 KeyboardPopupSwitcher.releaseKey = releaseKey; 172 KeyboardPopupSwitcher.triggerKey = triggerKey; 173 invokerTimer = new Timer (TIME_TO_SHOW, new PopupInvoker()); 174 invokerTimer.setRepeats(false); 175 invokerTimer.start(); 176 invokerTimerRunning = true; 177 } 178 179 180 private static void cleanupInterrupter() { 181 invokerTimerRunning = false; 182 if (invokerTimer != null) { 183 invokerTimer.stop(); 184 } 185 } 186 187 190 private static class PopupInvoker implements ActionListener { 191 192 public void actionPerformed(ActionEvent e) { 193 if (invokerTimerRunning) { 194 cleanupInterrupter(); 195 instance = new KeyboardPopupSwitcher(hits + 1); 196 instance.showPopup(); 197 } 198 } 199 } 200 201 206 public static boolean isShown() { 207 return shown; 208 } 209 210 216 private static boolean isAlive() { 217 return invokerTimerRunning || shown; 218 } 219 220 224 private KeyboardPopupSwitcher(int initialSelection) { 225 pTable = new SwitcherTable(items); 226 Dimension popupDim = pTable.getPreferredSize(); 228 Rectangle screen = Utilities.getUsableScreenBounds(); 229 this.x = screen.x + ((screen.width / 2) - (popupDim.width / 2)); 230 this.y = screen.y + ((screen.height / 2) - (popupDim.height / 2)); 231 int cols = pTable.getColumnCount(); 233 int rows = pTable.getRowCount(); 234 assert cols > 0 : "There aren't any columns in the KeyboardPopupSwitcher's table"; assert rows > 0 : "There aren't any rows in the KeyboardPopupSwitcher's table"; changeTableSelection((rows > initialSelection) ? initialSelection : 237 initialSelection, 0); 238 } 239 240 private void showPopup() { 241 if (!isShown()) { 242 popup = new JWindow (); 245 popup.setAlwaysOnTop(true); 246 popup.getContentPane().add(pTable); 247 popup.setLocation(x, y); 248 popup.pack(); 249 popup.setVisible(true); 250 SwingUtilities.invokeLater(new Runnable () { 253 public void run () { 254 WindowManager.getDefault().getMainWindow(). 255 addWindowFocusListener( KeyboardPopupSwitcher.this ); 256 } 257 }); 258 shown = true; 259 } 260 } 261 262 267 private static void processInterruption(KeyEvent kev) { 268 int keyCode = kev.getKeyCode(); 269 if (keyCode == releaseKey && kev.getID() == KeyEvent.KEY_RELEASED) { 270 cleanupInterrupter(); 274 hits = 0; 275 AbstractAction rva = new RecentViewListAction(); 276 rva.actionPerformed(new ActionEvent (kev.getSource(), 277 ActionEvent.ACTION_PERFORMED, 278 "immediately")); kev.consume(); 280 } else if (keyCode == triggerKey 282 && kev.getModifiers() == InputEvent.CTRL_MASK 283 && kev.getID() == KeyEvent.KEY_PRESSED) { 284 hits++; 286 kev.consume(); 287 cleanupInterrupter(); 288 instance = new KeyboardPopupSwitcher(hits + 1); 289 instance.showPopup(); 290 } 291 } 292 293 294 private void processKeyEvent(KeyEvent kev) { 295 switch (kev.getID()) { 296 case KeyEvent.KEY_PRESSED: 297 int code = kev.getKeyCode(); 298 if (code == reverseKey) { 299 fwd = false; 300 } else if (code == triggerKey) { 301 int lastRowIdx = pTable.getRowCount() - 1; 302 int lastColIdx = pTable.getColumnCount() - 1; 303 int selRow = pTable.getSelectedRow(); 304 int selCol = pTable.getSelectedColumn(); 305 int row = selRow; 306 int col = selCol; 307 308 if (fwd) { 310 if (selRow >= lastRowIdx) { 311 row = 0; 312 col = (selCol >= lastColIdx ? 0 : ++col); 313 } else { 314 row++; 315 if (pTable.getValueAt(row, col) == null) { 316 row = 0; 317 col = 0; 318 } 319 } 320 } else { 321 if (selRow == 0) { 322 if (selCol == 0) { 323 col = lastColIdx; 324 row = pTable.getLastValidRow(); 325 } else { 326 col--; 327 row = lastRowIdx; 328 } 329 } else { 330 row--; 331 } 332 } 333 if (row >= 0 && col >= 0) { 334 changeTableSelection(row, col); 335 } 336 } 337 kev.consume(); 338 break; 339 case KeyEvent.KEY_RELEASED: 340 code = kev.getKeyCode(); 341 if (code == reverseKey) { 342 fwd = true; 343 kev.consume(); 344 } else if (code == KeyEvent.VK_ESCAPE) { cancelSwitching(); 346 } else if (code == releaseKey) { 347 performSwitching(); 348 } 349 break; 350 } 351 } 352 353 354 private void changeTableSelection(int row, int col) { 355 pTable.changeSelection(row, col, false, false); 356 SwitcherTableItem item = pTable.getSelectedItem(); 358 if (item != null) { 359 String statusText = item.getDescription(); 360 StatusDisplayer.getDefault().setStatusText( 361 statusText != null ? statusText : ""); 362 } 363 } 364 365 369 private void cancelSwitching() { 370 hideCurrentPopup(); 371 StatusDisplayer.getDefault().setStatusText(""); 372 } 373 374 375 private void performSwitching() { 376 if (popup != null) { 377 SwitcherTableItem item = pTable.getSelectedItem(); 379 if (item != null) { 380 item.activate(); 381 } 382 } 383 cancelSwitching(); 384 } 385 386 private synchronized void hideCurrentPopup() { 387 if (popup != null) { 388 SwingUtilities.invokeLater(new PopupHider(popup)); 392 } 393 } 394 395 public void windowGainedFocus(WindowEvent e) { 396 } 397 398 public void windowLostFocus(WindowEvent e) { 399 if (e.getOppositeWindow() != popup) { 402 cancelSwitching(); 403 } 404 } 405 406 413 private class PopupHider implements Runnable { 414 private JWindow toHide; 415 public PopupHider(JWindow popup) { 416 toHide = popup; 417 } 418 419 public void run() { 420 toHide.setVisible(false); 421 shown = false; 422 hits = 0; 423 WindowManager.getDefault().getMainWindow().removeWindowFocusListener( KeyboardPopupSwitcher.this ); 425 } 426 } 427 } 428 | Popular Tags |