1 /******************************************************************************* 2 * Copyright (c) 2005, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.ui.internal.navigator; 15 16 import org.eclipse.jface.action.Action; 17 import org.eclipse.jface.action.IAction; 18 import org.eclipse.jface.util.IPropertyChangeListener; 19 import org.eclipse.jface.util.PropertyChangeEvent; 20 import org.eclipse.swt.SWT; 21 import org.eclipse.swt.events.KeyAdapter; 22 import org.eclipse.swt.events.KeyEvent; 23 import org.eclipse.swt.events.MouseAdapter; 24 import org.eclipse.swt.events.MouseEvent; 25 import org.eclipse.swt.widgets.Event; 26 import org.eclipse.swt.widgets.Listener; 27 import org.eclipse.swt.widgets.Text; 28 import org.eclipse.ui.IActionBars; 29 import org.eclipse.ui.PlatformUI; 30 import org.eclipse.ui.actions.ActionFactory; 31 32 /** 33 * Handles the redirection of the global Cut, Copy, Paste, and 34 * Select All actions to either the current inline text control 35 * or the part's supplied action handler. 36 * <p> 37 * This class may be instantiated; it is not intended to be subclassed. 38 * </p><p> 39 * Example usage: 40 * </p> 41 * <pre> 42 * textActionHandler = new TextActionHandler(this.getViewSite().getActionBars()); 43 * textActionHandler.addText((Text)textCellEditor1.getControl()); 44 * textActionHandler.addText((Text)textCellEditor2.getControl()); 45 * textActionHandler.setSelectAllAction(selectAllAction); 46 * </pre> 47 */ 48 public class TextActionHandler { 49 private DeleteActionHandler textDeleteAction = new DeleteActionHandler(); 50 51 private CutActionHandler textCutAction = new CutActionHandler(); 52 53 private CopyActionHandler textCopyAction = new CopyActionHandler(); 54 55 private PasteActionHandler textPasteAction = new PasteActionHandler(); 56 57 private SelectAllActionHandler textSelectAllAction = new SelectAllActionHandler(); 58 59 private IAction deleteAction; 60 61 private IAction cutAction; 62 63 private IAction copyAction; 64 65 private IAction pasteAction; 66 67 private IAction selectAllAction; 68 69 private IPropertyChangeListener deleteActionListener = new PropertyChangeListener( 70 textDeleteAction); 71 72 private IPropertyChangeListener cutActionListener = new PropertyChangeListener( 73 textCutAction); 74 75 private IPropertyChangeListener copyActionListener = new PropertyChangeListener( 76 textCopyAction); 77 78 private IPropertyChangeListener pasteActionListener = new PropertyChangeListener( 79 textPasteAction); 80 81 private IPropertyChangeListener selectAllActionListener = new PropertyChangeListener( 82 textSelectAllAction); 83 84 private Listener textControlListener = new TextControlListener(); 85 86 private Text activeTextControl; 87 88 private MouseAdapter mouseAdapter = new MouseAdapter() { 89 @Override 90 public void mouseUp(MouseEvent e) { 91 updateActionsEnableState(); 92 } 93 }; 94 95 private KeyAdapter keyAdapter = new KeyAdapter() { 96 @Override 97 public void keyReleased(KeyEvent e) { 98 updateActionsEnableState(); 99 } 100 }; 101 102 private class TextControlListener implements Listener { 103 @Override handleEvent(Event event)104 public void handleEvent(Event event) { 105 switch (event.type) { 106 case SWT.Activate: 107 activeTextControl = (Text) event.widget; 108 updateActionsEnableState(); 109 break; 110 case SWT.Deactivate: 111 activeTextControl = null; 112 updateActionsEnableState(); 113 break; 114 default: 115 break; 116 } 117 } 118 } 119 120 private class PropertyChangeListener implements IPropertyChangeListener { 121 private IAction actionHandler; 122 PropertyChangeListener(IAction actionHandler)123 protected PropertyChangeListener(IAction actionHandler) { 124 super(); 125 this.actionHandler = actionHandler; 126 } 127 128 @Override propertyChange(PropertyChangeEvent event)129 public void propertyChange(PropertyChangeEvent event) { 130 if (activeTextControl != null) { 131 return; 132 } 133 if (event.getProperty().equals(IAction.ENABLED)) { 134 Boolean bool = (Boolean) event.getNewValue(); 135 actionHandler.setEnabled(bool.booleanValue()); 136 } 137 } 138 } 139 140 private class DeleteActionHandler extends Action { DeleteActionHandler()141 protected DeleteActionHandler() { 142 super(CommonNavigatorMessages.Delete); 143 setId("TextDeleteActionHandler");//$NON-NLS-1$ 144 setEnabled(false); 145 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, 146 INavigatorHelpContextIds.TEXT_DELETE_ACTION); 147 } 148 149 @Override runWithEvent(Event event)150 public void runWithEvent(Event event) { 151 if (activeTextControl != null && !activeTextControl.isDisposed()) { 152 activeTextControl.clearSelection(); 153 return; 154 } 155 if (deleteAction != null) { 156 deleteAction.runWithEvent(event); 157 return; 158 } 159 } 160 161 /** 162 * Update state. 163 */ updateEnabledState()164 public void updateEnabledState() { 165 if (activeTextControl != null && !activeTextControl.isDisposed()) { 166 setEnabled(activeTextControl.getSelectionCount() > 0 167 || activeTextControl.getCaretPosition() < activeTextControl 168 .getCharCount()); 169 return; 170 } 171 if (deleteAction != null) { 172 setEnabled(deleteAction.isEnabled()); 173 return; 174 } 175 setEnabled(false); 176 } 177 } 178 179 private class CutActionHandler extends Action { 180 protected CutActionHandler() { 181 super(CommonNavigatorMessages.Cut); 182 setId("TextCutActionHandler");//$NON-NLS-1$ 183 setEnabled(false); 184 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, 185 INavigatorHelpContextIds.TEXT_CUT_ACTION); 186 } 187 188 @Override 189 public void runWithEvent(Event event) { 190 if (activeTextControl != null && !activeTextControl.isDisposed()) { 191 activeTextControl.cut(); 192 return; 193 } 194 if (cutAction != null) { 195 cutAction.runWithEvent(event); 196 return; 197 } 198 } 199 200 /** 201 * Update state. 202 */ 203 public void updateEnabledState() { 204 if (activeTextControl != null && !activeTextControl.isDisposed()) { 205 setEnabled(activeTextControl.getSelectionCount() > 0); 206 return; 207 } 208 if (cutAction != null) { 209 setEnabled(cutAction.isEnabled()); 210 return; 211 } 212 setEnabled(false); 213 } 214 } 215 216 private class CopyActionHandler extends Action { CopyActionHandler()217 protected CopyActionHandler() { 218 super(CommonNavigatorMessages.Copy); 219 setId("TextCopyActionHandler");//$NON-NLS-1$ 220 setEnabled(false); 221 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, 222 INavigatorHelpContextIds.TEXT_COPY_ACTION); 223 } 224 225 @Override runWithEvent(Event event)226 public void runWithEvent(Event event) { 227 if (activeTextControl != null && !activeTextControl.isDisposed()) { 228 activeTextControl.copy(); 229 return; 230 } 231 if (copyAction != null) { 232 copyAction.runWithEvent(event); 233 return; 234 } 235 } 236 237 /** 238 * Update the state. 239 */ updateEnabledState()240 public void updateEnabledState() { 241 if (activeTextControl != null && !activeTextControl.isDisposed()) { 242 setEnabled(activeTextControl.getSelectionCount() > 0); 243 return; 244 } 245 if (copyAction != null) { 246 setEnabled(copyAction.isEnabled()); 247 return; 248 } 249 setEnabled(false); 250 } 251 } 252 253 private class PasteActionHandler extends Action { PasteActionHandler()254 protected PasteActionHandler() { 255 super(CommonNavigatorMessages.Paste); 256 setId("TextPasteActionHandler");//$NON-NLS-1$ 257 setEnabled(false); 258 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, 259 INavigatorHelpContextIds.TEXT_PASTE_ACTION); 260 } 261 262 @Override runWithEvent(Event event)263 public void runWithEvent(Event event) { 264 if (activeTextControl != null && !activeTextControl.isDisposed()) { 265 activeTextControl.paste(); 266 return; 267 } 268 if (pasteAction != null) { 269 pasteAction.runWithEvent(event); 270 return; 271 } 272 } 273 274 /** 275 * Update the state 276 */ updateEnabledState()277 public void updateEnabledState() { 278 if (activeTextControl != null && !activeTextControl.isDisposed()) { 279 setEnabled(true); 280 return; 281 } 282 if (pasteAction != null) { 283 setEnabled(pasteAction.isEnabled()); 284 return; 285 } 286 setEnabled(false); 287 } 288 } 289 290 private class SelectAllActionHandler extends Action { SelectAllActionHandler()291 protected SelectAllActionHandler() { 292 super(CommonNavigatorMessages.TextAction_selectAll); 293 setId("TextSelectAllActionHandler");//$NON-NLS-1$ 294 setEnabled(false); 295 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, 296 INavigatorHelpContextIds.TEXT_SELECT_ALL_ACTION); 297 } 298 299 @Override runWithEvent(Event event)300 public void runWithEvent(Event event) { 301 if (activeTextControl != null && !activeTextControl.isDisposed()) { 302 activeTextControl.selectAll(); 303 return; 304 } 305 if (selectAllAction != null) { 306 selectAllAction.runWithEvent(event); 307 return; 308 } 309 } 310 311 /** 312 * Update the state. 313 */ updateEnabledState()314 public void updateEnabledState() { 315 if (activeTextControl != null && !activeTextControl.isDisposed()) { 316 setEnabled(true); 317 return; 318 } 319 if (selectAllAction != null) { 320 setEnabled(selectAllAction.isEnabled()); 321 return; 322 } 323 setEnabled(false); 324 } 325 } 326 327 /** 328 * Creates a <code>Text</code> control action handler 329 * for the global Cut, Copy, Paste, Delete, and Select All 330 * of the action bar. 331 * 332 * @param actionBar the action bar to register global 333 * action handlers for Cut, Copy, Paste, Delete, 334 * and Select All 335 */ TextActionHandler(IActionBars actionBar)336 public TextActionHandler(IActionBars actionBar) { 337 super(); 338 actionBar.setGlobalActionHandler(ActionFactory.CUT.getId(), 339 textCutAction); 340 actionBar.setGlobalActionHandler(ActionFactory.COPY.getId(), 341 textCopyAction); 342 actionBar.setGlobalActionHandler(ActionFactory.PASTE.getId(), 343 textPasteAction); 344 actionBar.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), 345 textSelectAllAction); 346 actionBar.setGlobalActionHandler(ActionFactory.DELETE.getId(), 347 textDeleteAction); 348 } 349 350 /** 351 * Add a <code>Text</code> control to the handler 352 * so that the Cut, Copy, Paste, Delete, and Select All 353 * actions are redirected to it when active. 354 * 355 * @param textControl the inline <code>Text</code> control 356 */ addText(Text textControl)357 public void addText(Text textControl) { 358 if (textControl == null) { 359 return; 360 } 361 362 activeTextControl = textControl; 363 textControl.addListener(SWT.Activate, textControlListener); 364 textControl.addListener(SWT.Deactivate, textControlListener); 365 366 // We really want a selection listener but it is not supported so we 367 // use a key listener and a mouse listener to know when selection changes 368 // may have occured 369 textControl.addKeyListener(keyAdapter); 370 textControl.addMouseListener(mouseAdapter); 371 372 } 373 374 /** 375 * Dispose of this action handler 376 */ dispose()377 public void dispose() { 378 setCutAction(null); 379 setCopyAction(null); 380 setPasteAction(null); 381 setSelectAllAction(null); 382 setDeleteAction(null); 383 } 384 385 /** 386 * Removes a <code>Text</code> control from the handler 387 * so that the Cut, Copy, Paste, Delete, and Select All 388 * actions are no longer redirected to it when active. 389 * 390 * @param textControl the inline <code>Text</code> control 391 */ removeText(Text textControl)392 public void removeText(Text textControl) { 393 if (textControl == null) { 394 return; 395 } 396 397 textControl.removeListener(SWT.Activate, textControlListener); 398 textControl.removeListener(SWT.Deactivate, textControlListener); 399 400 textControl.removeMouseListener(mouseAdapter); 401 textControl.removeKeyListener(keyAdapter); 402 403 activeTextControl = null; 404 updateActionsEnableState(); 405 } 406 407 /** 408 * Set the default <code>IAction</code> handler for the Copy 409 * action. This <code>IAction</code> is run only if no active 410 * inline text control. 411 * 412 * @param action the <code>IAction</code> to run for the 413 * Copy action, or <code>null</code> if not interested. 414 */ setCopyAction(IAction action)415 public void setCopyAction(IAction action) { 416 if (copyAction == action) { 417 return; 418 } 419 420 if (copyAction != null) { 421 copyAction.removePropertyChangeListener(copyActionListener); 422 } 423 424 copyAction = action; 425 426 if (copyAction != null) { 427 copyAction.addPropertyChangeListener(copyActionListener); 428 } 429 430 textCopyAction.updateEnabledState(); 431 } 432 433 /** 434 * Set the default <code>IAction</code> handler for the Cut 435 * action. This <code>IAction</code> is run only if no active 436 * inline text control. 437 * 438 * @param action the <code>IAction</code> to run for the 439 * Cut action, or <code>null</code> if not interested. 440 */ setCutAction(IAction action)441 public void setCutAction(IAction action) { 442 if (cutAction == action) { 443 return; 444 } 445 446 if (cutAction != null) { 447 cutAction.removePropertyChangeListener(cutActionListener); 448 } 449 450 cutAction = action; 451 452 if (cutAction != null) { 453 cutAction.addPropertyChangeListener(cutActionListener); 454 } 455 456 textCutAction.updateEnabledState(); 457 } 458 459 /** 460 * Set the default <code>IAction</code> handler for the Paste 461 * action. This <code>IAction</code> is run only if no active 462 * inline text control. 463 * 464 * @param action the <code>IAction</code> to run for the 465 * Paste action, or <code>null</code> if not interested. 466 */ setPasteAction(IAction action)467 public void setPasteAction(IAction action) { 468 if (pasteAction == action) { 469 return; 470 } 471 472 if (pasteAction != null) { 473 pasteAction.removePropertyChangeListener(pasteActionListener); 474 } 475 476 pasteAction = action; 477 478 if (pasteAction != null) { 479 pasteAction.addPropertyChangeListener(pasteActionListener); 480 } 481 482 textPasteAction.updateEnabledState(); 483 } 484 485 /** 486 * Set the default <code>IAction</code> handler for the Select All 487 * action. This <code>IAction</code> is run only if no active 488 * inline text control. 489 * 490 * @param action the <code>IAction</code> to run for the 491 * Select All action, or <code>null</code> if not interested. 492 */ setSelectAllAction(IAction action)493 public void setSelectAllAction(IAction action) { 494 if (selectAllAction == action) { 495 return; 496 } 497 498 if (selectAllAction != null) { 499 selectAllAction 500 .removePropertyChangeListener(selectAllActionListener); 501 } 502 503 selectAllAction = action; 504 505 if (selectAllAction != null) { 506 selectAllAction.addPropertyChangeListener(selectAllActionListener); 507 } 508 509 textSelectAllAction.updateEnabledState(); 510 } 511 512 /** 513 * Set the default <code>IAction</code> handler for the Delete 514 * action. This <code>IAction</code> is run only if no active 515 * inline text control. 516 * 517 * @param action the <code>IAction</code> to run for the 518 * Delete action, or <code>null</code> if not interested. 519 */ setDeleteAction(IAction action)520 public void setDeleteAction(IAction action) { 521 if (deleteAction == action) { 522 return; 523 } 524 525 if (deleteAction != null) { 526 deleteAction.removePropertyChangeListener(deleteActionListener); 527 } 528 529 deleteAction = action; 530 531 if (deleteAction != null) { 532 deleteAction.addPropertyChangeListener(deleteActionListener); 533 } 534 535 textDeleteAction.updateEnabledState(); 536 } 537 538 /** 539 * Update the enable state of the Cut, Copy, 540 * Paste, Delete, and Select All action handlers 541 */ updateActionsEnableState()542 private void updateActionsEnableState() { 543 textCutAction.updateEnabledState(); 544 textCopyAction.updateEnabledState(); 545 textPasteAction.updateEnabledState(); 546 textSelectAllAction.updateEnabledState(); 547 textDeleteAction.updateEnabledState(); 548 } 549 } 550 551