1 19 package org.openide.explorer; 20 21 import org.openide.DialogDisplayer; 22 import org.openide.NotifyDescriptor; 23 import org.openide.actions.CopyAction; 24 import org.openide.actions.CutAction; 25 import org.openide.actions.DeleteAction; 26 import org.openide.actions.PasteAction; 27 import org.openide.filesystems.FileSystem; 28 import org.openide.filesystems.Repository; 29 import org.openide.nodes.Node; 30 import org.openide.util.Mutex; 31 import org.openide.util.NbBundle; 32 import org.openide.util.actions.ActionPerformer; 33 import org.openide.util.datatransfer.*; 34 import java.awt.datatransfer.*; 35 import java.awt.event.*; 36 37 import java.beans.PropertyChangeEvent ; 38 import java.beans.PropertyChangeListener ; 39 40 import java.io.IOException ; 41 42 import java.util.HashMap ; 43 import java.util.logging.Level ; 44 import java.util.logging.Logger ; 45 46 import javax.swing.*; 47 import org.openide.util.Exceptions; 48 49 50 62 public class ExplorerActions { 63 64 private static CopyAction copy = null; 65 private static CutAction cut = null; 66 private static DeleteAction delete = null; 67 private static PasteAction paste = null; 68 69 70 private final CopyCutActionPerformer copyActionPerformer = new CopyCutActionPerformer(true); 71 72 73 private final CopyCutActionPerformer cutActionPerformer = new CopyCutActionPerformer(false); 74 75 76 private final DeleteActionPerformer deleteActionPerformer = new DeleteActionPerformer(); 77 78 79 private final OwnPaste pasteActionPerformer = new OwnPaste(); 80 private ActionStateUpdater actionStateUpdater; 81 82 83 private ExplorerManager manager; 84 85 86 private Boolean confirmDelete; 87 88 89 private boolean attachPerformers; 90 91 93 public ExplorerActions() { 94 this(true); 95 } 96 97 101 ExplorerActions(boolean attachPerformers) { 102 this.attachPerformers = attachPerformers; 103 } 104 105 107 final Action copyAction() { 108 return copyActionPerformer; 109 } 110 111 112 final Action cutAction() { 113 return cutActionPerformer; 114 } 115 116 118 final Action deleteAction() { 119 return deleteActionPerformer; 120 } 121 122 124 final Action pasteAction() { 125 return pasteActionPerformer; 126 } 127 128 131 public synchronized void attach(ExplorerManager m) { 132 if (manager != null) { 133 detach(); 135 } 136 137 manager = m; 138 139 ExplorerPanel.associateActions(this, m); 141 142 actionStateUpdater = new ActionStateUpdater(); 145 manager.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(actionStateUpdater, manager)); 146 147 Clipboard c = getClipboard(); 148 149 if (c instanceof ExClipboard) { 150 ExClipboard clip = (ExClipboard) c; 151 clip.addClipboardListener( 152 (ClipboardListener) org.openide.util.WeakListeners.create( 153 ClipboardListener.class, actionStateUpdater, clip 154 ) 155 ); 156 } 157 158 updateActions(); 159 } 160 161 162 public synchronized void detach() { 163 if (manager == null) { 164 return; 165 } 166 167 actionStateUpdater = null; 169 170 stopActions(); 171 172 manager = null; 173 } 174 175 179 ExplorerManager getAttachedManager() { 180 return manager; 181 } 182 183 186 public final void setConfirmDelete(boolean yes) { 187 confirmDelete = Boolean.valueOf(yes); 188 } 189 190 193 public final boolean isConfirmDelete() { 194 return (confirmDelete == null) ? ExplorerPanel.isConfirmDelete() : confirmDelete.booleanValue(); 195 } 196 197 198 private void stopActions() { 199 if (copyActionPerformer != null) { 200 if (attachPerformers) { 201 if (copy.getActionPerformer() instanceof CopyCutActionPerformer) { 202 copy.setActionPerformer(null); 203 } 204 205 if (cut.getActionPerformer() instanceof CopyCutActionPerformer) { 206 cut.setActionPerformer(null); 207 } 208 209 paste.setPasteTypes(null); 210 211 if (delete.getActionPerformer() instanceof DeleteActionPerformer) { 212 delete.setActionPerformer(null); 213 } 214 } else { 215 copyActionPerformer.setEnabled(false); 216 cutActionPerformer.setEnabled(false); 217 deleteActionPerformer.setEnabled(false); 218 pasteActionPerformer.setEnabled(false); 219 } 220 } 221 } 222 223 226 private void updateActions() { 227 if (manager == null) { 228 return; 229 } 230 231 Node[] path = manager.getSelectedNodes(); 232 233 if (copy == null) { 234 copy = (CopyAction) CopyAction.findObject(CopyAction.class, true); 235 cut = (CutAction) CutAction.findObject(CutAction.class, true); 236 paste = (PasteAction) PasteAction.findObject(PasteAction.class, true); 237 delete = (DeleteAction) DeleteAction.findObject(DeleteAction.class, true); 238 } 239 240 int i; 241 int k = (path != null) ? path.length : 0; 242 243 if (k > 0) { 244 boolean incest = false; 245 246 if (k > 1) { 247 HashMap allNodes = new HashMap (101); 252 253 for (i = 0; i < k; i++) { 254 if (!checkParents(path[i], allNodes)) { 255 incest = true; 256 257 break; 258 } 259 } 260 } 261 262 for (i = 0; i < k; i++) { 263 if (incest || !path[i].canCopy()) { 264 if (attachPerformers) { 265 copy.setActionPerformer(null); 266 } else { 267 copyActionPerformer.setEnabled(false); 268 } 269 270 break; 271 } 272 } 273 274 if (i == k) { 275 if (attachPerformers) { 276 copy.setActionPerformer(copyActionPerformer); 277 } else { 278 copyActionPerformer.setEnabled(true); 279 } 280 } 281 282 for (i = 0; i < k; i++) { 283 if (incest || !path[i].canCut()) { 284 if (attachPerformers) { 285 cut.setActionPerformer(null); 286 } else { 287 cutActionPerformer.setEnabled(false); 288 } 289 290 break; 291 } 292 } 293 294 if (i == k) { 295 if (attachPerformers) { 296 cut.setActionPerformer(cutActionPerformer); 297 } else { 298 cutActionPerformer.setEnabled(true); 299 } 300 } 301 302 for (i = 0; i < k; i++) { 303 if (incest || !path[i].canDestroy()) { 304 if (attachPerformers) { 305 delete.setActionPerformer(null); 306 } else { 307 deleteActionPerformer.setEnabled(false); 308 } 309 310 break; 311 } 312 } 313 314 if (i == k) { 315 if (attachPerformers) { 316 delete.setActionPerformer(deleteActionPerformer); 317 } else { 318 deleteActionPerformer.setEnabled(true); 319 } 320 } 321 } else { 323 if (attachPerformers) { 324 copy.setActionPerformer(null); 325 cut.setActionPerformer(null); 326 delete.setActionPerformer(null); 327 } else { 328 copyActionPerformer.setEnabled(false); 329 cutActionPerformer.setEnabled(false); 330 deleteActionPerformer.setEnabled(false); 331 } 332 } 333 334 updatePasteAction(path); 335 } 336 337 342 private boolean checkParents(Node node, HashMap set) { 343 if (set.get(node) != null) { 344 return false; 345 } 346 347 set.put(node, this); 349 350 for (;;) { 351 node = node.getParentNode(); 352 353 if (node == null) { 354 return true; 355 } 356 357 if (set.put(node, node) == this) { 358 return false; 360 } 361 } 362 } 363 364 367 private void updatePasteAction(Node[] path) { 368 ExplorerManager man = manager; 369 370 if (man == null) { 371 if (attachPerformers) { 372 paste.setPasteTypes(null); 373 } else { 374 pasteActionPerformer.setPasteTypes(null); 375 } 376 377 return; 378 } 379 380 if ((path != null) && (path.length > 1)) { 381 if (attachPerformers) { 382 paste.setPasteTypes(null); 383 } else { 384 pasteActionPerformer.setPasteTypes(null); 385 } 386 387 return; 388 } else { 389 Node node = man.getExploredContext(); 390 Node[] selectedNodes = man.getSelectedNodes(); 391 392 if ((selectedNodes != null) && (selectedNodes.length == 1)) { 393 node = selectedNodes[0]; 394 } 395 396 if (node != null) { 397 Transferable trans = getClipboard().getContents(this); 398 updatePasteTypes(trans, node); 399 } 400 } 401 } 402 403 404 private void updatePasteTypes(Transferable trans, Node pan) { 405 if (trans != null) { 406 PasteType[] pasteTypes = (pan == null) ? new PasteType[] { } : pan.getPasteTypes(trans); 409 410 if (pasteTypes.length != 0) { 411 if (attachPerformers) { 412 paste.setPasteTypes(pasteTypes); 413 } else { 414 pasteActionPerformer.setPasteTypes(pasteTypes); 415 } 416 417 return; 418 } 419 420 boolean flavorSupported = false; 421 422 try { 423 flavorSupported = trans.isDataFlavorSupported(ExTransferable.multiFlavor); 424 } catch (java.lang.Exception e) { 425 } 428 429 if (flavorSupported) { 430 try { 433 MultiTransferObject obj = (MultiTransferObject) trans.getTransferData(ExTransferable.multiFlavor); 434 int count = obj.getCount(); 435 boolean ok = true; 436 Transferable[] t = new Transferable[count]; 437 PasteType[] p = new PasteType[count]; 438 439 for (int i = 0; i < count; i++) { 440 t[i] = obj.getTransferableAt(i); 441 pasteTypes = (pan == null) ? new PasteType[] { } : pan.getPasteTypes(t[i]); 442 443 if (pasteTypes.length == 0) { 444 ok = false; 445 446 break; 447 } 448 449 p[i] = pasteTypes[0]; 451 } 452 453 if (ok) { 454 PasteType[] arrOfPaste = new PasteType[] { new MultiPasteType(t, p) }; 455 456 if (attachPerformers) { 457 paste.setPasteTypes(arrOfPaste); 458 } else { 459 pasteActionPerformer.setPasteTypes(arrOfPaste); 460 } 461 462 return; 463 } 464 } catch (UnsupportedFlavorException e) { 465 } catch (IOException e) { 467 } 469 } 470 } 471 472 if (attachPerformers) { 473 if (paste != null) { 474 paste.setPasteTypes(null); 475 } 476 } else { 477 pasteActionPerformer.setPasteTypes(null); 478 } 479 } 480 481 482 private static Clipboard getClipboard() { 483 Clipboard c = (java.awt.datatransfer.Clipboard ) org.openide.util.Lookup.getDefault().lookup( 484 java.awt.datatransfer.Clipboard .class 485 ); 486 487 if (c == null) { 488 c = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard(); 489 } 490 491 return c; 492 } 493 494 495 private void updateActionsState() { 496 ActionStateUpdater asu; 497 498 synchronized (this) { 499 asu = actionStateUpdater; 500 } 501 502 if (asu != null) { 503 asu.update(); 504 } 505 } 506 507 508 private static class MultiPasteType extends PasteType { 509 510 Transferable[] t; 511 512 513 PasteType[] p; 514 515 516 MultiPasteType(Transferable[] t, PasteType[] p) { 517 this.t = t; 518 this.p = p; 519 } 520 521 526 public Transferable paste() throws IOException { 527 int size = p.length; 528 Transferable[] arr = new Transferable[size]; 529 530 for (int i = 0; i < size; i++) { 531 Transferable newTransferable = p[i].paste(); 532 533 if (newTransferable != null) { 534 arr[i] = newTransferable; 535 } else { 536 arr[i] = t[i]; 538 } 539 } 540 541 return new ExTransferable.Multi(arr); 542 } 543 } 544 545 547 private class OwnPaste extends AbstractAction { 548 private PasteType[] pasteTypes = new PasteType[] { }; 549 550 OwnPaste() { 551 } 552 553 public boolean isEnabled() { 554 updateActionsState(); 555 556 return super.isEnabled(); 557 } 558 559 public void setPasteTypes(PasteType[] arr) { 560 synchronized (this) { 561 this.pasteTypes = arr; 562 } 563 564 setEnabled(arr != null); 565 } 566 567 public void actionPerformed(ActionEvent e) { 568 if (pasteTypes == null) { 570 throw new IllegalStateException ("Should not be invoked at all. Paste types: null"); } else { 572 throw new IllegalStateException ( 573 "Should not be invoked at all. Paste types: " + java.util.Arrays.asList(pasteTypes) 574 ); } 576 } 577 578 public Object getValue(String s) { 579 updateActionsState(); 580 581 if ("delegates".equals(s)) { 583 return pasteTypes; 584 } 585 586 return super.getValue(s); 587 } 588 } 589 590 591 private class CopyCutActionPerformer extends AbstractAction implements org.openide.util.actions.ActionPerformer { 592 593 private boolean copyCut; 594 595 596 public CopyCutActionPerformer(boolean b) { 597 copyCut = b; 598 } 599 600 public boolean isEnabled() { 601 updateActionsState(); 602 603 return super.isEnabled(); 604 } 605 606 607 public void performAction(org.openide.util.actions.SystemAction action) { 608 Transferable trans = null; 609 Node[] sel = manager.getSelectedNodes(); 610 611 if (sel.length != 1) { 612 Transferable[] arrayTrans = new Transferable[sel.length]; 613 614 for (int i = 0; i < sel.length; i++) 615 if ((arrayTrans[i] = getTransferableOwner(sel[i])) == null) { 616 return; 617 } 618 619 trans = new ExTransferable.Multi(arrayTrans); 620 } else { 621 trans = getTransferableOwner(sel[0]); 622 } 623 624 if (trans != null) { 625 Clipboard clipboard = getClipboard(); 626 627 clipboard.setContents(trans, new StringSelection("")); } 629 } 630 631 private Transferable getTransferableOwner(Node node) { 632 try { 633 return copyCut ? node.clipboardCopy() : node.clipboardCut(); 634 } catch (java.io.IOException e) { 635 Logger.getLogger(ExplorerActions.class.getName()).log(Level.WARNING, null, e); 636 637 return null; 638 } 639 } 640 641 644 public void actionPerformed(ActionEvent e) { 645 performAction(null); 646 } 647 } 648 649 650 private class DeleteActionPerformer extends AbstractAction implements ActionPerformer { 651 DeleteActionPerformer() { 652 } 653 654 public boolean isEnabled() { 655 updateActionsState(); 656 657 return super.isEnabled(); 658 } 659 660 661 public void performAction(org.openide.util.actions.SystemAction action) { 662 final Node[] sel = manager.getSelectedNodes(); 663 664 if ((sel == null) || (sel.length == 0)) { 665 return; 666 } 667 668 if (!isConfirmDelete() || doConfirm(sel)) { 670 try { 672 if (manager != null) { 673 manager.setSelectedNodes(new Node[] { }); 674 } 675 } catch (java.beans.PropertyVetoException e) { 676 } 678 679 doDestroy(sel); 680 class Run implements Runnable { 681 public void run() { 682 if (attachPerformers) { 683 delete.setActionPerformer(null); } else { 685 setEnabled(false); 686 } 687 } 688 } 689 org.openide.util.Mutex.EVENT.readAccess(new Run()); 690 } 691 } 692 693 private boolean doConfirm(Node[] sel) { 694 String message; 695 String title; 696 boolean customDelete = true; 697 698 for (int i = 0; i < sel.length; i++) { 699 if (!Boolean.TRUE.equals(sel[i].getValue("customDelete"))) { customDelete = false; 701 702 break; 703 } 704 } 705 706 if (customDelete) { 707 return true; 708 } 709 710 if (sel.length == 1) { 711 message = NbBundle.getMessage( 712 ExplorerActions.class, "MSG_ConfirmDeleteObject", sel[0].getDisplayName() 713 ); 714 title = NbBundle.getMessage(ExplorerActions.class, "MSG_ConfirmDeleteObjectTitle"); 715 } else { 716 message = NbBundle.getMessage( 717 ExplorerActions.class, "MSG_ConfirmDeleteObjects", new Integer (sel.length) 718 ); 719 title = NbBundle.getMessage(ExplorerActions.class, "MSG_ConfirmDeleteObjectsTitle"); 720 } 721 722 NotifyDescriptor desc = new NotifyDescriptor.Confirmation(message, title, NotifyDescriptor.YES_NO_OPTION); 723 724 return NotifyDescriptor.YES_OPTION.equals(DialogDisplayer.getDefault().notify(desc)); 725 } 726 727 741 private void doDestroy(final Node[] sel) { 742 try { 743 Repository.getDefault().getDefaultFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 744 745 public void run() throws IOException { 746 for (int i = 0; i < 747 sel.length; i++) { 748 try { 749 sel[i].destroy(); 750 } 751 catch (IOException e) { 752 Exceptions.printStackTrace(e); 753 } 754 } 755 } 756 }); 757 } catch (IOException ioe) { 758 throw (IllegalStateException ) new IllegalStateException (ioe.toString()).initCause(ioe); 759 } 760 } 761 762 765 public void actionPerformed(ActionEvent e) { 766 performAction(null); 767 } 768 } 769 770 772 private class ActionStateUpdater implements PropertyChangeListener , ClipboardListener, ActionListener { 773 private final Timer timer; 774 private boolean planned; 775 776 ActionStateUpdater() { 777 timer = new FixIssue29405Timer(150, this); 778 timer.setCoalesce(true); 779 timer.setRepeats(false); 780 } 781 782 public synchronized void propertyChange(PropertyChangeEvent e) { 783 timer.restart(); 784 planned = true; 785 } 786 787 public void clipboardChanged(ClipboardEvent ev) { 788 final ExplorerManager em = manager; 789 790 if (!ev.isConsumed() && (em != null)) { 791 Mutex.EVENT.writeAccess( 792 new Runnable () { 793 public void run() { 794 updatePasteAction(em.getSelectedNodes()); 795 } 796 } 797 ); 798 } 799 } 800 801 public void actionPerformed(ActionEvent evt) { 802 updateActions(); 803 804 synchronized (this) { 805 timer.stop(); 806 planned = false; 807 } 808 } 809 810 811 public void update() { 812 boolean update; 813 814 synchronized (this) { 815 update = planned; 816 planned = false; 817 } 818 819 if (update) { 820 timer.stop(); 821 updateActions(); 822 } 823 } 824 } 825 826 827 private static class FixIssue29405Timer extends javax.swing.Timer { 828 private boolean running; 829 830 public FixIssue29405Timer(int delay, ActionListener l) { 831 super(delay, l); 832 } 833 834 public void restart() { 835 super.restart(); 836 running = true; 837 } 838 839 public void stop() { 840 running = false; 841 super.stop(); 842 } 843 844 public boolean isRunning() { 845 return running; 846 } 847 } 848 } 850 | Popular Tags |