| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011, the Dart project authors. | 2 * Copyright (c) 2011, the Dart project authors. |
| 3 * | 3 * |
| 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except | 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except |
| 5 * in compliance with the License. You may obtain a copy of the License at | 5 * in compliance with the License. You may obtain a copy of the License at |
| 6 * | 6 * |
| 7 * http://www.eclipse.org/legal/epl-v10.html | 7 * http://www.eclipse.org/legal/epl-v10.html |
| 8 * | 8 * |
| 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License | 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License |
| 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express | 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 import org.eclipse.swt.events.MouseTrackAdapter; | 27 import org.eclipse.swt.events.MouseTrackAdapter; |
| 28 import org.eclipse.swt.graphics.Point; | 28 import org.eclipse.swt.graphics.Point; |
| 29 import org.eclipse.swt.widgets.Composite; | 29 import org.eclipse.swt.widgets.Composite; |
| 30 import org.eclipse.swt.widgets.Control; | 30 import org.eclipse.swt.widgets.Control; |
| 31 import org.eclipse.swt.widgets.Display; | 31 import org.eclipse.swt.widgets.Display; |
| 32 import org.eclipse.swt.widgets.Event; | 32 import org.eclipse.swt.widgets.Event; |
| 33 import org.eclipse.swt.widgets.Listener; | 33 import org.eclipse.swt.widgets.Listener; |
| 34 import org.eclipse.swt.widgets.Menu; | 34 import org.eclipse.swt.widgets.Menu; |
| 35 import org.eclipse.swt.widgets.Text; | 35 import org.eclipse.swt.widgets.Text; |
| 36 import org.eclipse.ui.IWorkbenchWindow; | 36 import org.eclipse.ui.IWorkbenchWindow; |
| 37 import org.eclipse.ui.PlatformUI; |
| 38 import org.eclipse.ui.keys.IBindingService; |
| 37 import org.eclipse.ui.menus.WorkbenchWindowControlContribution; | 39 import org.eclipse.ui.menus.WorkbenchWindowControlContribution; |
| 38 | 40 |
| 39 import java.util.HashMap; | 41 import java.util.HashMap; |
| 40 import java.util.Map; | 42 import java.util.Map; |
| 41 import java.util.Map.Entry; | 43 import java.util.Map.Entry; |
| 42 | 44 |
| 43 /** | 45 /** |
| 44 * Contributes the omnibox toolbar control. | 46 * Contributes the omnibox toolbar control. |
| 45 */ | 47 */ |
| 46 public class OmniBoxControlContribution extends WorkbenchWindowControlContributi
on { | 48 public class OmniBoxControlContribution extends WorkbenchWindowControlContributi
on { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 * keybinding). | 93 * keybinding). |
| 92 * | 94 * |
| 93 * @param window the host window | 95 * @param window the host window |
| 94 * @return the location to root the popup | 96 * @return the location to root the popup |
| 95 */ | 97 */ |
| 96 public static Point getPopupLocation(IWorkbenchWindow window) { | 98 public static Point getPopupLocation(IWorkbenchWindow window) { |
| 97 OmniBoxControlContribution contrib = CONTROL_MAP.get(window); | 99 OmniBoxControlContribution contrib = CONTROL_MAP.get(window); |
| 98 if (contrib == null) { | 100 if (contrib == null) { |
| 99 return new Point(0, 0); | 101 return new Point(0, 0); |
| 100 } | 102 } |
| 101 return locationRelativeToControl(contrib.control); | 103 return locationRelativeToControl(contrib.textControl); |
| 102 } | 104 } |
| 103 | 105 |
| 104 private static Point locationRelativeToControl(Text control) { | 106 private static Point locationRelativeToControl(Text control) { |
| 105 return control.toDisplay(0 + POPUP_PIXEL_HORIZ_NUDGE, control.getSize().y | 107 return control.toDisplay(0 + POPUP_PIXEL_HORIZ_NUDGE, control.getSize().y |
| 106 + POPUP_PIXEL_VERT_NUDGE); | 108 + POPUP_PIXEL_VERT_NUDGE); |
| 107 } | 109 } |
| 108 | 110 |
| 109 private Text control; | 111 private Text textControl; |
| 110 | 112 |
| 111 private boolean inControl; | 113 private boolean inControl; |
| 112 | 114 |
| 113 private OmniBoxPopup popup; | 115 private OmniBoxPopup popup; |
| 114 | 116 |
| 115 //used to track whether text is being modified programmatically (e.g., waterma
rk-setting) | 117 //used to track whether text is being modified programmatically (e.g., waterma
rk-setting) |
| 116 private boolean listenForTextModify = true; | 118 private boolean listenForTextModify = true; |
| 117 | 119 |
| 118 //used when we want to advance focus off of the text control (ideally to resto
re previous) | 120 //used when we want to advance focus off of the text control (ideally to resto
re previous) |
| 119 private Control previousFocusControl; | 121 private Control previousFocusControl; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 131 disposedWindow = entry.getKey(); | 133 disposedWindow = entry.getKey(); |
| 132 break; | 134 break; |
| 133 } | 135 } |
| 134 } | 136 } |
| 135 if (disposedWindow != null) { | 137 if (disposedWindow != null) { |
| 136 CONTROL_MAP.remove(disposedWindow); | 138 CONTROL_MAP.remove(disposedWindow); |
| 137 } | 139 } |
| 138 } | 140 } |
| 139 | 141 |
| 140 public void giveFocus() { | 142 public void giveFocus() { |
| 141 cacheFocusControl(control.getDisplay().getFocusControl()); | 143 cacheFocusControl(textControl.getDisplay().getFocusControl()); |
| 142 control.setFocus(); | 144 textControl.setFocus(); |
| 143 clearWatermark(); | 145 clearWatermark(); |
| 144 } | 146 } |
| 145 | 147 |
| 146 @Override | 148 @Override |
| 147 protected Control createControl(Composite parent) { | 149 protected Control createControl(Composite parent) { |
| 148 control = createTextControl(parent); | 150 textControl = createTextControl(parent); |
| 149 setWatermarkText(); | 151 setWatermarkText(); |
| 150 hookupListeners(); | 152 hookupListeners(); |
| 151 CONTROL_MAP.put(getWorkbenchWindow(), this); | 153 CONTROL_MAP.put(getWorkbenchWindow(), this); |
| 152 return control; | 154 return textControl; |
| 153 } | 155 } |
| 154 | 156 |
| 155 protected void defocus() { | 157 protected void defocus() { |
| 156 if (previousFocusControl != null && !previousFocusControl.isDisposed()) { | 158 if (previousFocusControl != null && !previousFocusControl.isDisposed()) { |
| 157 previousFocusControl.setFocus(); | 159 previousFocusControl.setFocus(); |
| 158 } else { | 160 } else { |
| 159 control.getParent().setFocus(); | 161 textControl.getParent().setFocus(); |
| 160 } | 162 } |
| 161 } | 163 } |
| 162 | 164 |
| 163 protected void handleMouseEnter() { | |
| 164 inControl = true; | |
| 165 //cache on mouse enter to ensure we can restore focus after an invocation in
itiated by a mouse click | |
| 166 cacheFocusControl(control.getDisplay().getFocusControl()); | |
| 167 } | |
| 168 | |
| 169 protected void handleMouseExit() { | |
| 170 inControl = false; | |
| 171 } | |
| 172 | |
| 173 protected void handleSelection() { | |
| 174 clearWatermark(); | |
| 175 } | |
| 176 | |
| 177 protected void refreshPopup() { | 165 protected void refreshPopup() { |
| 178 if (popup != null && !popup.isDisposed()) { | 166 if (popup != null && !popup.isDisposed()) { |
| 179 popup.refresh(getFilterText()); | 167 popup.refresh(getFilterText()); |
| 180 } | 168 } |
| 181 } | 169 } |
| 182 | 170 |
| 183 private void cacheFocusControl(Control focusControl) { | 171 private void cacheFocusControl(Control focusControl) { |
| 184 //since the point of caching the control is to restore focus away from us, | 172 //since the point of caching the control is to restore focus away from us, |
| 185 //ignore any sets to "self" | 173 //ignore any sets to "self" |
| 186 if (focusControl != control) { | 174 if (focusControl != textControl) { |
| 187 previousFocusControl = focusControl; | 175 previousFocusControl = focusControl; |
| 188 } | 176 } |
| 189 } | 177 } |
| 190 | 178 |
| 191 private void clearWatermark() { | 179 private void clearWatermark() { |
| 192 //ensure watermark (or valid text) does not get re-cleared | 180 //ensure watermark (or valid text) does not get re-cleared |
| 193 if (control.getForeground().equals(OmniBoxColors.SEARCHBOX_TEXT_COLOR)) { | 181 if (textControl.getForeground().equals(OmniBoxColors.SEARCHBOX_TEXT_COLOR))
{ |
| 194 return; | 182 return; |
| 195 } | 183 } |
| 196 silentSetControlText(""); //$NON-NLS-1$ | 184 silentSetControlText(""); //$NON-NLS-1$ |
| 197 control.setForeground(OmniBoxColors.SEARCHBOX_TEXT_COLOR); | 185 textControl.setForeground(OmniBoxColors.SEARCHBOX_TEXT_COLOR); |
| 198 } | 186 } |
| 199 | 187 |
| 200 private Text createTextControl(Composite parent) { | 188 private Text createTextControl(Composite parent) { |
| 201 Text text = new Text(parent, SEARCH_BOX_STYLE_BITS); | 189 Text text = new Text(parent, SEARCH_BOX_STYLE_BITS); |
| 202 text.setToolTipText(OmniBoxMessages.OmniBoxControlContribution_control_toolt
ip); | 190 text.setToolTipText(OmniBoxMessages.OmniBoxControlContribution_control_toolt
ip); |
| 203 // Disables the default context menu for native SWT text boxes | 191 // Disables the default context menu for native SWT text boxes |
| 204 text.setMenu(new Menu(parent)); | 192 text.setMenu(new Menu(parent)); |
| 205 return text; | 193 return text; |
| 206 } | 194 } |
| 207 | 195 |
| 208 private String getFilterText() { | 196 private String getFilterText() { |
| 209 return control.getText().toLowerCase(); | 197 return textControl.getText().toLowerCase(); |
| 198 } |
| 199 |
| 200 private void handleFocusGained() { |
| 201 //disable global keybinding handlers so we can trap copy/paste/etc |
| 202 ((IBindingService) PlatformUI.getWorkbench().getService(IBindingService.clas
s)).setKeyFilterEnabled(false); |
| 203 clearWatermark(); |
| 204 } |
| 205 |
| 206 private void handleFocusLost() { |
| 207 //re-enable global keybinding handlers |
| 208 ((IBindingService) PlatformUI.getWorkbench().getService(IBindingService.clas
s)).setKeyFilterEnabled(true); |
| 209 |
| 210 //GTK linux requires special casing to handle the case where a click |
| 211 //outside the search box (or popup) should cause the popup to close |
| 212 //We identify this case by keying off focus changes --- if focus |
| 213 //is transfered to another control we trigger a close |
| 214 if (Util.isLinux()) { |
| 215 //Exec async to ensure that it occurs after the focus change |
| 216 Display.getDefault().asyncExec(new Runnable() { |
| 217 @Override |
| 218 public void run() { |
| 219 Control focusControl = Display.getDefault().getFocusControl(); |
| 220 if (focusControl != textControl && popup != null && focusControl != po
pup.table) { |
| 221 popup.close(); |
| 222 } |
| 223 } |
| 224 }); |
| 225 } |
| 226 if (popupClosed()) { |
| 227 setWatermarkText(); |
| 228 } |
| 229 } |
| 230 |
| 231 private void handleKeyPressed(KeyEvent e) { |
| 232 if (SWT.ARROW_DOWN == e.keyCode) { |
| 233 if (popupClosed()) { |
| 234 openPopup(); |
| 235 refreshPopup(); |
| 236 } |
| 237 |
| 238 } |
| 239 |
| 240 if (popupClosed()) { |
| 241 //have escape defocus |
| 242 if (SWT.ESC == e.character) { |
| 243 defocus(); |
| 244 return; |
| 245 } |
| 246 //and don't let other control characters invoke the popup |
| 247 if (Character.isISOControl(e.character)) { |
| 248 return; |
| 249 } |
| 250 openPopup(); |
| 251 } |
| 252 |
| 253 if (popup != null && !popup.isDisposed()) { |
| 254 popup.sendKeyPress(e); |
| 255 } |
| 256 } |
| 257 |
| 258 private void handleModifyText() { |
| 259 if (!listenForTextModify) { |
| 260 return; |
| 261 } |
| 262 String filterText = getFilterText(); |
| 263 if (filterText.length() > 0) { |
| 264 if (popupClosed()) { |
| 265 openPopup(); |
| 266 } |
| 267 refreshPopup(); |
| 268 } else { |
| 269 popup.close(); |
| 270 } |
| 271 } |
| 272 |
| 273 private void handleMouseEnter() { |
| 274 inControl = true; |
| 275 //cache on mouse enter to ensure we can restore focus after an invocation in
itiated by a mouse click |
| 276 cacheFocusControl(textControl.getDisplay().getFocusControl()); |
| 277 } |
| 278 |
| 279 private void handleMouseExit() { |
| 280 inControl = false; |
| 281 } |
| 282 |
| 283 private void handleMouseUp() { |
| 284 if (inControl) { |
| 285 handleSelection(); |
| 286 } |
| 287 } |
| 288 |
| 289 private void handleSelection() { |
| 290 clearWatermark(); |
| 210 } | 291 } |
| 211 | 292 |
| 212 private void hookupListeners() { | 293 private void hookupListeners() { |
| 213 control.addMouseListener(new MouseAdapter() { | 294 textControl.addMouseListener(new MouseAdapter() { |
| 214 @Override | 295 @Override |
| 215 public void mouseUp(MouseEvent e) { | 296 public void mouseUp(MouseEvent e) { |
| 216 if (inControl) { | 297 handleMouseUp(); |
| 217 handleSelection(); | |
| 218 } | |
| 219 } | 298 } |
| 220 }); | 299 }); |
| 221 | 300 |
| 222 control.addMouseTrackListener(new MouseTrackAdapter() { | 301 textControl.addMouseTrackListener(new MouseTrackAdapter() { |
| 223 @Override | 302 @Override |
| 224 public void mouseEnter(MouseEvent e) { | 303 public void mouseEnter(MouseEvent e) { |
| 225 handleMouseEnter(); | 304 handleMouseEnter(); |
| 226 } | 305 } |
| 227 | 306 |
| 228 @Override | 307 @Override |
| 229 public void mouseExit(MouseEvent e) { | 308 public void mouseExit(MouseEvent e) { |
| 230 handleMouseExit(); | 309 handleMouseExit(); |
| 231 } | 310 } |
| 232 }); | 311 }); |
| 233 | 312 |
| 234 control.addModifyListener(new ModifyListener() { | 313 textControl.addModifyListener(new ModifyListener() { |
| 235 @Override | 314 @Override |
| 236 public void modifyText(ModifyEvent e) { | 315 public void modifyText(ModifyEvent e) { |
| 237 if (!listenForTextModify) { | 316 handleModifyText(); |
| 238 return; | |
| 239 } | |
| 240 String filterText = getFilterText(); | |
| 241 if (filterText.length() > 0) { | |
| 242 if (popupClosed()) { | |
| 243 openPopup(); | |
| 244 } | |
| 245 refreshPopup(); | |
| 246 } else { | |
| 247 popup.close(); | |
| 248 } | |
| 249 } | 317 } |
| 250 }); | 318 }); |
| 251 | 319 |
| 252 control.addKeyListener(new KeyAdapter() { | 320 textControl.addKeyListener(new KeyAdapter() { |
| 253 @Override | 321 @Override |
| 254 public void keyPressed(KeyEvent e) { | 322 public void keyPressed(KeyEvent e) { |
| 255 | 323 handleKeyPressed(e); |
| 256 if (SWT.ARROW_DOWN == e.keyCode) { | |
| 257 if (popupClosed()) { | |
| 258 openPopup(); | |
| 259 refreshPopup(); | |
| 260 } | |
| 261 | |
| 262 } | |
| 263 | |
| 264 if (popupClosed()) { | |
| 265 //have escape defocus | |
| 266 if (SWT.ESC == e.character) { | |
| 267 defocus(); | |
| 268 return; | |
| 269 } | |
| 270 //and don't let other control characters invoke the popup | |
| 271 if (Character.isISOControl(e.character)) { | |
| 272 return; | |
| 273 } | |
| 274 openPopup(); | |
| 275 } | |
| 276 | |
| 277 if (popup != null && !popup.isDisposed()) { | |
| 278 popup.sendKeyPress(e); | |
| 279 } | |
| 280 } | 324 } |
| 281 }); | 325 }); |
| 282 | 326 |
| 283 control.addFocusListener(new FocusListener() { | 327 textControl.addFocusListener(new FocusListener() { |
| 284 @Override | 328 @Override |
| 285 public void focusGained(FocusEvent e) { | 329 public void focusGained(FocusEvent e) { |
| 286 clearWatermark(); | 330 handleFocusGained(); |
| 287 } | 331 } |
| 288 | 332 |
| 289 @Override | 333 @Override |
| 290 public void focusLost(FocusEvent e) { | 334 public void focusLost(FocusEvent e) { |
| 291 //GTK linux requires special casing to handle the case where a click | 335 handleFocusLost(); |
| 292 //outside the search box (or popup) should cause the popup to close | |
| 293 //We identify this case by keying off focus changes --- if focus | |
| 294 //is transfered to another control we trigger a close | |
| 295 if (Util.isLinux()) { | |
| 296 //Exec async to esnure that it occurs after the focus change | |
| 297 Display.getDefault().asyncExec(new Runnable() { | |
| 298 @Override | |
| 299 public void run() { | |
| 300 Control focusControl = Display.getDefault().getFocusControl(); | |
| 301 if (focusControl != control && popup != null && focusControl != po
pup.table) { | |
| 302 popup.close(); | |
| 303 } | |
| 304 } | |
| 305 }); | |
| 306 } | |
| 307 if (popupClosed()) { | |
| 308 setWatermarkText(); | |
| 309 } | |
| 310 } | 336 } |
| 311 }); | 337 }); |
| 312 } | 338 } |
| 313 | 339 |
| 314 private void openPopup() { | 340 private void openPopup() { |
| 315 popup = new OmniBoxPopup(getWorkbenchWindow(), null) { | 341 popup = new OmniBoxPopup(getWorkbenchWindow(), null) { |
| 316 @Override | 342 @Override |
| 317 public boolean close() { | 343 public boolean close() { |
| 318 setWatermarkText(); | 344 setWatermarkText(); |
| 319 defocus(); | 345 defocus(); |
| 320 return super.close(); | 346 return super.close(); |
| 321 } | 347 } |
| 322 | 348 |
| 323 @Override | 349 @Override |
| 324 protected Point getDefaultLocation(Point initialSize) { | 350 protected Point getDefaultLocation(Point initialSize) { |
| 325 return locationRelativeToControl(control); | 351 return locationRelativeToControl(textControl); |
| 326 } | 352 } |
| 327 | 353 |
| 328 @Override | 354 @Override |
| 329 protected Point getDefaultSize() { | 355 protected Point getDefaultSize() { |
| 330 return new Point(control.getSize().x - POPUP_PIXEL_HORIZ_NUDGE * 2, 360)
; | 356 return new Point(textControl.getSize().x - POPUP_PIXEL_HORIZ_NUDGE * 2,
360); |
| 331 } | 357 } |
| 332 | 358 |
| 333 }; | 359 }; |
| 334 popup.setFilterControl(control); | 360 popup.setFilterControl(textControl); |
| 335 popup.open(); | 361 popup.open(); |
| 336 | 362 |
| 337 if (Util.isMac()) { | 363 if (Util.isMac()) { |
| 338 control.addListener(SWT.Deactivate, new Listener() { | 364 textControl.addListener(SWT.Deactivate, new Listener() { |
| 339 @Override | 365 @Override |
| 340 public void handleEvent(Event event) { | 366 public void handleEvent(Event event) { |
| 341 //selecting the scrollbar will deactivate but in that case we don't wa
nt to close | 367 //selecting the scrollbar will deactivate but in that case we don't wa
nt to close |
| 342 if (event.display.getFocusControl() != popup.table) { | 368 if (event.display.getFocusControl() != popup.table) { |
| 343 popup.close(); | 369 popup.close(); |
| 344 } | 370 } |
| 345 control.removeListener(SWT.Deactivate, this); | 371 textControl.removeListener(SWT.Deactivate, this); |
| 346 } | 372 } |
| 347 }); | 373 }); |
| 348 } | 374 } |
| 349 } | 375 } |
| 350 | 376 |
| 351 private boolean popupClosed() { | 377 private boolean popupClosed() { |
| 352 return popup == null || popup.isDisposed(); | 378 return popup == null || popup.isDisposed(); |
| 353 } | 379 } |
| 354 | 380 |
| 355 private void setWatermarkText() { | 381 private void setWatermarkText() { |
| 356 silentSetControlText(WATERMARK_TEXT); | 382 silentSetControlText(WATERMARK_TEXT); |
| 357 control.setForeground(OmniBoxColors.WATERMARK_TEXT_COLOR); | 383 textControl.setForeground(OmniBoxColors.WATERMARK_TEXT_COLOR); |
| 358 } | 384 } |
| 359 | 385 |
| 360 //set text without notifying listeners | 386 //set text without notifying listeners |
| 361 private void silentSetControlText(String txt) { | 387 private void silentSetControlText(String txt) { |
| 362 listenForTextModify = false; | 388 listenForTextModify = false; |
| 363 control.setText(txt); | 389 textControl.setText(txt); |
| 364 listenForTextModify = true; | 390 listenForTextModify = true; |
| 365 } | 391 } |
| 366 | 392 |
| 367 } | 393 } |
| OLD | NEW |