001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.action; 020 021import java.awt.event.ActionEvent; 022import java.awt.event.InputEvent; 023import java.awt.event.KeyEvent; 024import java.io.PrintWriter; 025import java.lang.reflect.Field; 026import java.util.ArrayList; 027import java.util.Arrays; 028import java.util.List; 029 030import org.w3c.dom.Document; 031 032import icy.clipboard.Clipboard; 033import icy.file.FileUtil; 034import icy.gui.dialog.IdConfirmDialog; 035import icy.gui.dialog.MessageDialog; 036import icy.gui.dialog.OpenDialog; 037import icy.gui.dialog.SaveDialog; 038import icy.gui.inspector.RoisPanel; 039import icy.gui.main.MainFrame; 040import icy.main.Icy; 041import icy.resource.ResourceUtil; 042import icy.resource.icon.IcyIcon; 043import icy.roi.ROI; 044import icy.roi.ROI2D; 045import icy.roi.ROI3D; 046import icy.roi.ROI4D; 047import icy.roi.ROIUtil; 048import icy.sequence.Sequence; 049import icy.sequence.SequenceDataIterator; 050import icy.sequence.edit.ROIAddSequenceEdit; 051import icy.sequence.edit.ROIAddsSequenceEdit; 052import icy.sequence.edit.ROIReplacesSequenceEdit; 053import icy.system.SystemUtil; 054import icy.type.DataIteratorUtil; 055import icy.util.ClassUtil; 056import icy.util.ShapeUtil.BooleanOperator; 057import icy.util.StringUtil; 058import icy.util.XLSUtil; 059import icy.util.XMLUtil; 060import jxl.write.WritableSheet; 061import jxl.write.WritableWorkbook; 062import plugins.kernel.roi.roi2d.ROI2DRectangle; 063import plugins.kernel.roi.roi3d.ROI3DStackRectangle; 064import plugins.kernel.roi.roi4d.ROI4DStackRectangle; 065import plugins.kernel.roi.roi5d.ROI5DStackRectangle; 066 067/** 068 * Roi actions (open / save / copy / paste / merge...) 069 * 070 * @author Stephane 071 */ 072public class RoiActions 073{ 074 public static final String DEFAULT_ROI_DIR = "roi"; 075 public static final String DEFAULT_ROI_NAME = "roi.xml"; 076 077 public static class SequenceRoiList 078 { 079 public final Sequence sequence; 080 public final List<ROI> rois; 081 082 public SequenceRoiList(Sequence sequence, List<ROI> rois) 083 { 084 super(); 085 086 this.sequence = sequence; 087 this.rois = rois; 088 } 089 } 090 091 public static IcyAbstractAction loadAction = new IcyAbstractAction("Load ROI(s)", 092 new IcyIcon(ResourceUtil.ICON_OPEN), "Load ROI(s) from file", 093 "Load ROI(s) from a XML file and add them to the active sequence") 094 { 095 /** 096 * 097 */ 098 private static final long serialVersionUID = 2378084039864016238L; 099 100 @Override 101 public boolean doAction(ActionEvent e) 102 { 103 final String filename = OpenDialog.chooseFile("Load roi(s)...", DEFAULT_ROI_DIR, DEFAULT_ROI_NAME); 104 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 105 106 if ((filename != null) && (sequence != null)) 107 { 108 final Document doc = XMLUtil.loadDocument(filename); 109 110 if (doc != null) 111 { 112 final List<ROI> rois = ROI.loadROIsFromXML(XMLUtil.getRootElement(doc)); 113 114 sequence.beginUpdate(); 115 try 116 { 117 // add to sequence 118 for (ROI roi : rois) 119 sequence.addROI(roi); 120 } 121 finally 122 { 123 sequence.endUpdate(); 124 } 125 126 // add to undo manager 127 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, rois) 128 { 129 @Override 130 public String getPresentationName() 131 { 132 if (getROIs().size() > 1) 133 return "ROIs loaded from XML file"; 134 135 return "ROI loaded from XML file"; 136 }; 137 }); 138 139 return true; 140 } 141 } 142 143 return false; 144 } 145 146 @Override 147 public boolean isEnabled() 148 { 149 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 150 } 151 }; 152 153 public static IcyAbstractAction saveAction = new IcyAbstractAction("Save ROI(s)", 154 new IcyIcon(ResourceUtil.ICON_SAVE), "Save selected ROI(s) to file", 155 "Save the selected ROI(s) from active sequence into a XML file") 156 { 157 /** 158 * 159 */ 160 private static final long serialVersionUID = 349358870716619748L; 161 162 @Override 163 public boolean doAction(ActionEvent e) 164 { 165 final String filename = SaveDialog.chooseFile("Save roi(s)...", DEFAULT_ROI_DIR, DEFAULT_ROI_NAME); 166 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 167 168 if ((filename != null) && (sequence != null)) 169 { 170 final List<ROI> rois = sequence.getSelectedROIs(); 171 172 if (rois.size() > 0) 173 { 174 final Document doc = XMLUtil.createDocument(true); 175 176 if (doc != null) 177 { 178 ROI.saveROIsToXML(XMLUtil.getRootElement(doc), rois); 179 XMLUtil.saveDocument(doc, filename); 180 return true; 181 } 182 } 183 } 184 185 return false; 186 } 187 188 @Override 189 public boolean isEnabled() 190 { 191 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 192 } 193 }; 194 195 public static IcyAbstractAction copyAction = new IcyAbstractAction("Copy", new IcyIcon(ResourceUtil.ICON_COPY), 196 "Copy selected ROI to clipboard (Ctrl+C)", KeyEvent.VK_C, SystemUtil.getMenuCtrlMask()) 197 { 198 /** 199 * 200 */ 201 private static final long serialVersionUID = -4716027958152503425L; 202 203 @Override 204 public boolean doAction(ActionEvent e) 205 { 206 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 207 208 if (sequence != null) 209 { 210 final List<ROI> rois = sequence.getSelectedROIs(); 211 212 if (rois.size() > 0) 213 { 214 // need to get a copy of the ROI (as it can change meanwhile) 215 for (int i = 0; i < rois.size(); i++) 216 { 217 final ROI roi = rois.get(i).getCopy(); 218 219 if (roi != null) 220 rois.set(i, roi); 221 } 222 223 // save in the Icy clipboard 224 Clipboard.put(Clipboard.TYPE_SEQUENCEROILIST, new SequenceRoiList(sequence, rois)); 225 // clear system clipboard 226 Clipboard.clearSystem(); 227 228 pasteAction.setEnabled(true); 229 230 return true; 231 } 232 } 233 234 return false; 235 } 236 237 @Override 238 public boolean isEnabled() 239 { 240 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 241 return super.isEnabled() && (sequence != null) && (sequence.getSelectedROIs().size() > 0); 242 } 243 }; 244 245 public static IcyAbstractAction copyLinkAction = new IcyAbstractAction("Copy link", 246 new IcyIcon(ResourceUtil.ICON_LINK_COPY), "Copy link of selected ROI to clipboard (Alt+C)", KeyEvent.VK_C, 247 InputEvent.ALT_MASK) 248 { 249 /** 250 * 251 */ 252 private static final long serialVersionUID = -4716027958152503425L; 253 254 @Override 255 public boolean doAction(ActionEvent e) 256 { 257 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 258 259 if (roisPanel != null) 260 { 261 final List<ROI> rois = roisPanel.getSelectedRois(); 262 263 if (rois.size() > 0) 264 { 265 // save in the Icy clipboard 266 Clipboard.put(Clipboard.TYPE_ROILINKLIST, rois); 267 // clear system clipboard 268 Clipboard.clearSystem(); 269 270 pasteLinkAction.setEnabled(true); 271 272 return true; 273 } 274 } 275 276 return false; 277 } 278 279 @Override 280 public boolean isEnabled() 281 { 282 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 283 return super.isEnabled() && (sequence != null) && (sequence.getSelectedROIs().size() > 0); 284 } 285 }; 286 287 public static IcyAbstractAction pasteAction = new IcyAbstractAction("Paste", new IcyIcon(ResourceUtil.ICON_PASTE), 288 "Paste ROI from clipboard (Ctrl+V)", KeyEvent.VK_V, SystemUtil.getMenuCtrlMask()) 289 { 290 /** 291 * 292 */ 293 private static final long serialVersionUID = 4878585451006567513L; 294 295 @Override 296 public boolean doAction(ActionEvent e) 297 { 298 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 299 300 if (sequence != null) 301 { 302 final SequenceRoiList sequenceRoiList = (SequenceRoiList) Clipboard.get(Clipboard.TYPE_SEQUENCEROILIST); 303 final Sequence sequenceSrc = sequenceRoiList.sequence; 304 final List<ROI> rois = sequenceRoiList.rois; 305 306 if ((rois != null) && (rois.size() > 0)) 307 { 308 final List<ROI> copyRois = new ArrayList<ROI>(); 309 sequence.beginUpdate(); 310 try 311 { 312 // unselect all rois 313 sequence.setSelectedROI(null); 314 315 // add copy to sequence (so we can do the paste operation severals time) 316 for (ROI roi : rois) 317 { 318 // final ROI newROI = roi.getCopy(); 319 final ROI newROI = ROIUtil.adjustToSequence(roi, sequenceSrc, sequence, true, true, true); 320 321 if (newROI != null) 322 { 323 copyRois.add(newROI); 324 325 // select the ROI 326 newROI.setSelected(true); 327 // and add it 328 sequence.addROI(newROI); 329 } 330 } 331 } 332 finally 333 { 334 sequence.endUpdate(); 335 } 336 337 // add to undo manager 338 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, copyRois) 339 { 340 @Override 341 public String getPresentationName() 342 { 343 if (getROIs().size() > 1) 344 return "ROIs added from clipboard"; 345 346 return "ROI added from clipboard"; 347 }; 348 }); 349 350 return true; 351 } 352 } 353 354 return false; 355 } 356 357 @Override 358 public boolean isEnabled() 359 { 360 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null) 361 && Clipboard.getType().equals(Clipboard.TYPE_SEQUENCEROILIST); 362 } 363 }; 364 365 public static IcyAbstractAction pasteLinkAction = new IcyAbstractAction("Paste link", 366 new IcyIcon(ResourceUtil.ICON_LINK_PASTE), "Paste ROI link from clipboard (Alt+V)", KeyEvent.VK_V, 367 InputEvent.ALT_MASK) 368 { 369 /** 370 * 371 */ 372 private static final long serialVersionUID = 4878585451006567513L; 373 374 @Override 375 public boolean doAction(ActionEvent e) 376 { 377 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 378 379 if (sequence != null) 380 { 381 @SuppressWarnings("unchecked") 382 final List<ROI> rois = (List<ROI>) Clipboard.get(Clipboard.TYPE_ROILINKLIST); 383 384 if ((rois != null) && (rois.size() > 0)) 385 { 386 sequence.beginUpdate(); 387 try 388 { 389 // add to sequence 390 for (ROI roi : rois) 391 sequence.addROI(roi); 392 } 393 finally 394 { 395 sequence.endUpdate(); 396 } 397 398 // add to undo manager 399 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, rois) 400 { 401 @Override 402 public String getPresentationName() 403 { 404 if (getROIs().size() > 1) 405 return "ROIs linked from clipboard"; 406 407 return "ROI linked from clipboard"; 408 }; 409 }); 410 411 return true; 412 } 413 } 414 415 return false; 416 } 417 418 @Override 419 public boolean isEnabled() 420 { 421 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null) 422 && Clipboard.getType().equals(Clipboard.TYPE_ROILINKLIST); 423 } 424 }; 425 426 // public static IcyAbstractAction clearClipboardAction = new IcyAbstractAction("Clear", new 427 // IcyIcon( 428 // ResourceUtil.ICON_CLIPBOARD_CLEAR), "Remove ROI saved in clipboard") 429 // { 430 // /** 431 // * 432 // */ 433 // private static final long serialVersionUID = 4878585451006567513L; 434 // 435 // @Override 436 // public boolean doAction(ActionEvent e) 437 // { 438 // Clipboard.remove(ID_ROI_COPY_CLIPBOARD, false); 439 // pasteAction.setEnabled(false); 440 // } 441 // 442 // @Override 443 // public boolean isEnabled() 444 // { 445 // return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null) 446 // && Clipboard.hasObjects(RoiActions.ID_ROI_COPY_CLIPBOARD, false); 447 // } 448 // }; 449 450 public static IcyAbstractAction selectAllAction = new IcyAbstractAction("SelectAll", (IcyIcon) null, 451 "Select all ROI(s)") 452 { 453 /** 454 * 455 */ 456 private static final long serialVersionUID = 3219000949426093919L; 457 458 @Override 459 public boolean doAction(ActionEvent e) 460 { 461 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 462 463 if (sequence != null) 464 { 465 sequence.setSelectedROIs((List<ROI>) sequence.getROIs()); 466 return true; 467 } 468 469 return false; 470 } 471 472 @Override 473 public boolean isEnabled() 474 { 475 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 476 477 return super.isEnabled() && (sequence != null) && (sequence.getROIs().size() > 0); 478 } 479 }; 480 481 public static IcyAbstractAction unselectAction = new IcyAbstractAction("Unselect", (IcyIcon) null, 482 "Unselect ROI(s)", KeyEvent.VK_ESCAPE) 483 { 484 /** 485 * 486 */ 487 private static final long serialVersionUID = -6136680076368815566L; 488 489 @Override 490 public boolean doAction(ActionEvent e) 491 { 492 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 493 494 if (sequence != null) 495 { 496 sequence.setSelectedROI(null); 497 return true; 498 } 499 500 return false; 501 } 502 503 @Override 504 public boolean isEnabled() 505 { 506 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 507 } 508 }; 509 510 public static IcyAbstractAction deleteAction = new IcyAbstractAction("Delete", 511 new IcyIcon(ResourceUtil.ICON_DELETE), "Delete selected ROI(s)", 512 "Delete selected ROI(s) from the active sequence", KeyEvent.VK_DELETE, 0) 513 { 514 /** 515 * 516 */ 517 private static final long serialVersionUID = 9079403002834893222L; 518 519 @Override 520 public boolean doAction(ActionEvent e) 521 { 522 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 523 524 if (sequence != null) 525 { 526 sequence.removeSelectedROIs(false, true); 527 return true; 528 } 529 530 return false; 531 } 532 533 @Override 534 public boolean isEnabled() 535 { 536 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 537 return super.isEnabled() && (sequence != null) && (sequence.getSelectedROIs().size() > 0); 538 } 539 }; 540 541 public static IcyAbstractAction boolNotAction = new IcyAbstractAction("Inversion", 542 new IcyIcon(ResourceUtil.ICON_ROI_NOT), "Boolean inversion operation", 543 "Create a new ROI representing the inverse of selected ROI", true, "Computing inverse...") 544 { 545 /** 546 * 547 */ 548 private static final long serialVersionUID = 6360796066188754099L; 549 550 @Override 551 public boolean doAction(ActionEvent e) 552 { 553 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 554 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 555 556 if ((sequence != null) && (roisPanel != null)) 557 { 558 // NOT operation 559 sequence.beginUpdate(); 560 try 561 { 562 final List<ROI> selectedROI = roisPanel.getSelectedRois(); 563 564 // work only on single ROI 565 if (selectedROI.size() != 1) 566 return false; 567 568 final ROI roi = selectedROI.get(0); 569 final ROI seqRoi; 570 571 switch (roi.getDimension()) 572 { 573 case 2: 574 final ROI2D roi2d = (ROI2D) roi; 575 final ROI2DRectangle seqRoi2d = new ROI2DRectangle(sequence.getBounds2D()); 576 // set on same position 577 seqRoi2d.setZ(roi2d.getZ()); 578 seqRoi2d.setT(roi2d.getT()); 579 seqRoi2d.setC(roi2d.getC()); 580 seqRoi = seqRoi2d; 581 break; 582 583 case 3: 584 final ROI3D roi3d = (ROI3D) roi; 585 final ROI3DStackRectangle seqRoi3d = new ROI3DStackRectangle( 586 sequence.getBounds5D().toRectangle3D()); 587 // set on same position 588 seqRoi3d.setT(roi3d.getT()); 589 seqRoi3d.setC(roi3d.getC()); 590 seqRoi = seqRoi3d; 591 break; 592 593 case 4: 594 final ROI4D roi4d = (ROI4D) roi; 595 final ROI4DStackRectangle seqRoi4d = new ROI4DStackRectangle( 596 sequence.getBounds5D().toRectangle4D()); 597 // set on same position 598 seqRoi4d.setC(roi4d.getC()); 599 seqRoi = seqRoi4d; 600 break; 601 602 case 5: 603 seqRoi = new ROI5DStackRectangle(sequence.getBounds5D()); 604 break; 605 606 default: 607 seqRoi = null; 608 break; 609 } 610 611 if (seqRoi != null) 612 { 613 // we do the NOT operation by subtracting current ROI to sequence bounds ROI 614 final ROI mergeROI = ROIUtil.subtract(seqRoi, roi); 615 616 if (mergeROI != null) 617 { 618 mergeROI.setName("Inverse"); 619 620 sequence.addROI(mergeROI); 621 sequence.setSelectedROI(mergeROI); 622 623 // add to undo manager 624 sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Inverse")); 625 } 626 } 627 else 628 MessageDialog.showDialog("Operation not supported", "Input ROI has incorrect dimension !", 629 MessageDialog.ERROR_MESSAGE); 630 } 631 catch (UnsupportedOperationException ex) 632 { 633 MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), 634 MessageDialog.ERROR_MESSAGE); 635 } 636 finally 637 { 638 sequence.endUpdate(); 639 } 640 641 return true; 642 } 643 644 return false; 645 } 646 647 @Override 648 public boolean isEnabled() 649 { 650 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 651 } 652 }; 653 654 public static IcyAbstractAction boolOrAction = new IcyAbstractAction("Union", new IcyIcon(ResourceUtil.ICON_ROI_OR), 655 "Boolean union operation", "Create a new ROI representing the union of selected ROIs", true, 656 "Computing union...") 657 { 658 /** 659 * 660 */ 661 private static final long serialVersionUID = 1861052712498233441L; 662 663 @Override 664 public boolean doAction(ActionEvent e) 665 { 666 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 667 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 668 669 if ((sequence != null) && (roisPanel != null)) 670 { 671 // OR operation 672 sequence.beginUpdate(); 673 try 674 { 675 final List<ROI> selectedROIs = roisPanel.getSelectedRois(); 676 final ROI mergeROI = ROIUtil.getUnion(selectedROIs); 677 678 if (mergeROI != null) 679 { 680 mergeROI.setName("Union"); 681 682 sequence.addROI(mergeROI); 683 sequence.setSelectedROI(mergeROI); 684 685 // add to undo manager 686 sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Union")); 687 } 688 } 689 catch (UnsupportedOperationException ex) 690 { 691 MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), 692 MessageDialog.ERROR_MESSAGE); 693 } 694 finally 695 { 696 sequence.endUpdate(); 697 } 698 699 return true; 700 } 701 702 return false; 703 } 704 705 @Override 706 public boolean isEnabled() 707 { 708 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 709 } 710 }; 711 712 public static IcyAbstractAction boolAndAction = new IcyAbstractAction("Intersection", 713 new IcyIcon(ResourceUtil.ICON_ROI_AND), "Boolean intersection operation", 714 "Create a new ROI representing the intersection of selected ROIs", true, "Computing intersection...") 715 { 716 /** 717 * 718 */ 719 private static final long serialVersionUID = -9103158044679039413L; 720 721 @Override 722 public boolean doAction(ActionEvent e) 723 { 724 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 725 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 726 727 if ((sequence != null) && (roisPanel != null)) 728 { 729 // AND operation 730 sequence.beginUpdate(); 731 try 732 { 733 final List<ROI> selectedROIs = roisPanel.getSelectedRois(); 734 final ROI mergeROI = ROIUtil.getIntersection(selectedROIs); 735 736 if (mergeROI != null) 737 { 738 mergeROI.setName("Intersection"); 739 740 sequence.addROI(mergeROI); 741 sequence.setSelectedROI(mergeROI); 742 743 // add to undo manager 744 sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Intersection")); 745 } 746 } 747 catch (UnsupportedOperationException ex) 748 { 749 MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), 750 MessageDialog.ERROR_MESSAGE); 751 } 752 finally 753 { 754 sequence.endUpdate(); 755 } 756 757 return true; 758 } 759 760 return false; 761 } 762 763 @Override 764 public boolean isEnabled() 765 { 766 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 767 } 768 }; 769 770 public static IcyAbstractAction boolXorAction = new IcyAbstractAction("Exclusive union", 771 new IcyIcon(ResourceUtil.ICON_ROI_XOR), "Boolean exclusive union operation", 772 "Create a new ROI representing the exclusive union of selected ROIs", true, "Computing exclusive union...") 773 { 774 /** 775 * 776 */ 777 private static final long serialVersionUID = 1609345474914807703L; 778 779 @Override 780 public boolean doAction(ActionEvent e) 781 { 782 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 783 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 784 785 if ((sequence != null) && (roisPanel != null)) 786 { 787 // XOR operation 788 sequence.beginUpdate(); 789 try 790 { 791 final List<ROI> selectedROIs = roisPanel.getSelectedRois(); 792 final ROI mergeROI = ROIUtil.getExclusiveUnion(selectedROIs); 793 794 if (mergeROI != null) 795 { 796 mergeROI.setName("Exclusive union"); 797 798 sequence.addROI(mergeROI); 799 sequence.setSelectedROI(mergeROI); 800 801 // add to undo manager 802 sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Exclusive Union")); 803 } 804 } 805 catch (UnsupportedOperationException ex) 806 { 807 MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), 808 MessageDialog.ERROR_MESSAGE); 809 } 810 finally 811 { 812 sequence.endUpdate(); 813 } 814 815 return true; 816 } 817 818 return false; 819 } 820 821 @Override 822 public boolean isEnabled() 823 { 824 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 825 } 826 }; 827 828 public static IcyAbstractAction boolSubtractAction = new IcyAbstractAction("Subtraction", 829 new IcyIcon(ResourceUtil.ICON_ROI_SUB), "Boolean subtraction", 830 "Create 2 ROIs representing the result of (A - B) and (B - A)", true, "Computing subtraction...") 831 { 832 /** 833 * 834 */ 835 private static final long serialVersionUID = 9094641559971542667L; 836 837 @Override 838 public boolean doAction(ActionEvent e) 839 { 840 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 841 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 842 843 if ((sequence != null) && (roisPanel != null)) 844 { 845 // SUB operation 846 sequence.beginUpdate(); 847 try 848 { 849 final List<ROI> selectedROI = roisPanel.getSelectedRois(); 850 final List<ROI> generatedROIs = new ArrayList<ROI>(); 851 852 // Subtraction work only when 2 ROI are selected 853 if (selectedROI.size() != 2) 854 return false; 855 856 final ROI subtractAB = ROIUtil.subtract(selectedROI.get(0), selectedROI.get(1)); 857 final ROI subtractBA = ROIUtil.subtract(selectedROI.get(1), selectedROI.get(0)); 858 859 subtractAB.setName("Subtract A-B"); 860 subtractBA.setName("Subtract B-A"); 861 862 generatedROIs.add(subtractAB); 863 generatedROIs.add(subtractBA); 864 865 sequence.beginUpdate(); 866 try 867 { 868 for (ROI roi : generatedROIs) 869 sequence.addROI(roi); 870 871 sequence.setSelectedROIs(generatedROIs); 872 873 // add to undo manager 874 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, generatedROIs, "ROI Subtraction")); 875 } 876 finally 877 { 878 sequence.endUpdate(); 879 } 880 } 881 catch (UnsupportedOperationException ex) 882 { 883 MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), 884 MessageDialog.ERROR_MESSAGE); 885 } 886 finally 887 { 888 sequence.endUpdate(); 889 } 890 891 return true; 892 } 893 894 return false; 895 } 896 897 @Override 898 public boolean isEnabled() 899 { 900 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 901 } 902 }; 903 904 public static IcyAbstractAction fillInteriorAction = new IcyAbstractAction("Fill interior", 905 new IcyIcon(ResourceUtil.ICON_ROI_INTERIOR), "Fill ROI(s) interior", 906 "Fill interior of the selected ROI(s) with specified value", true, "Fill ROI(s) interior...") 907 { 908 @Override 909 public boolean doAction(ActionEvent e) 910 { 911 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 912 913 if (sequence != null) 914 { 915 final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); 916 917 if (mainFrame != null) 918 { 919 final double value = mainFrame.getMainRibbon().getROIRibbonTask().getFillValue(); 920 // create undo point 921 final boolean canUndo = sequence.createUndoDataPoint("ROI fill interior"); 922 923 // cannot backup 924 if (!canUndo) 925 { 926 // ask confirmation to continue 927 if (!IdConfirmDialog.confirm( 928 "Not enough memory to undo the operation, do you want to continue ?", 929 "ROIFillInteriorConfirm")) 930 return false; 931 } 932 933 for (ROI roi : sequence.getSelectedROIs()) 934 DataIteratorUtil.set(new SequenceDataIterator(sequence, roi, true), value); 935 936 sequence.dataChanged(); 937 938 // no undo, clear undo manager after modification 939 if (!canUndo) 940 sequence.clearUndoManager(); 941 942 return true; 943 } 944 } 945 946 return false; 947 } 948 949 @Override 950 public boolean isEnabled() 951 { 952 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 953 954 return super.isEnabled() && (sequence != null) && !sequence.isEmpty(); 955 } 956 }; 957 958 public static IcyAbstractAction fillExteriorAction = new IcyAbstractAction("Fill exterior", 959 new IcyIcon(ResourceUtil.ICON_ROI_NOT), "Fill ROI(s) exterior", 960 "Fill exterior of the selected ROI(s) with specified value", true, "Fill ROI(s) exterior...") 961 { 962 @Override 963 public boolean doAction(ActionEvent e) 964 { 965 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 966 967 if (sequence != null) 968 { 969 final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); 970 971 if (mainFrame != null) 972 { 973 final double value = mainFrame.getMainRibbon().getROIRibbonTask().getFillValue(); 974 // create undo point 975 final boolean canUndo = sequence.createUndoDataPoint("ROI fill exterior"); 976 977 // cannot backup 978 if (!canUndo) 979 { 980 // ask confirmation to continue 981 if (!IdConfirmDialog.confirm( 982 "Not enough memory to undo the operation, do you want to continue ?", 983 "ROIFillExteriorConfirm")) 984 return false; 985 } 986 987 try 988 { 989 final ROI roiUnion = ROIUtil.merge(sequence.getSelectedROIs(), BooleanOperator.OR); 990 final ROI roiSeq = new ROI5DStackRectangle(sequence.getBounds5D()); 991 final ROI roi = roiSeq.getSubtraction(roiUnion); 992 993 DataIteratorUtil.set(new SequenceDataIterator(sequence, roi), value); 994 995 sequence.dataChanged(); 996 997 // no undo, clear undo manager after modification 998 if (!canUndo) 999 sequence.clearUndoManager(); 1000 1001 return true; 1002 } 1003 catch (UnsupportedOperationException ex) 1004 { 1005 // undo operation if possible 1006 if (canUndo) 1007 sequence.undo(); 1008 1009 MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), 1010 MessageDialog.ERROR_MESSAGE); 1011 1012 return false; 1013 } 1014 } 1015 } 1016 1017 return false; 1018 } 1019 1020 @Override 1021 public boolean isEnabled() 1022 { 1023 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1024 1025 return super.isEnabled() && (sequence != null) && !sequence.isEmpty(); 1026 } 1027 }; 1028 1029 public static IcyAbstractAction xlsExportAction = new IcyAbstractAction("Excel export", 1030 new IcyIcon(ResourceUtil.ICON_XLS_EXPORT), "ROI Excel export", 1031 "Export the content of the ROI table into a XLS/CSV file", true, "Exporting ROI informations...") 1032 { 1033 /** 1034 * 1035 */ 1036 private static final long serialVersionUID = 9094641559971542667L; 1037 1038 @Override 1039 public boolean doAction(ActionEvent e) 1040 { 1041 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1042 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 1043 1044 if ((sequence != null) && (roisPanel != null)) 1045 { 1046 final String content = roisPanel.getCSVFormattedInfos(); 1047 1048 if (StringUtil.isEmpty(content) || roisPanel.getVisibleRois().isEmpty()) 1049 { 1050 MessageDialog.showDialog("Nothing to export !", MessageDialog.INFORMATION_MESSAGE); 1051 return true; 1052 } 1053 1054 final String filename = SaveDialog.chooseFileForResult("Export ROIs...", "result", ".xls"); 1055 1056 if (filename != null) 1057 { 1058 try 1059 { 1060 // CSV format wanted ? 1061 if (!FileUtil.getFileExtension(filename, false).toLowerCase().startsWith("xls")) 1062 { 1063 // just write CSV content 1064 final PrintWriter out = new PrintWriter(filename); 1065 out.println(content); 1066 out.close(); 1067 } 1068 // XLS export 1069 else 1070 { 1071 final WritableWorkbook workbook = XLSUtil.createWorkbook(filename); 1072 final WritableSheet sheet = XLSUtil.createNewPage(workbook, "ROIS"); 1073 1074 if (XLSUtil.setFromCSV(sheet, content)) 1075 XLSUtil.saveAndClose(workbook); 1076 else 1077 { 1078 MessageDialog.showDialog("Error", 1079 "Error while exporting ROIs table content to XLS file.", 1080 MessageDialog.ERROR_MESSAGE); 1081 return false; 1082 } 1083 } 1084 } 1085 catch (Exception e1) 1086 { 1087 MessageDialog.showDialog("Error", e1.getMessage(), MessageDialog.ERROR_MESSAGE); 1088 return false; 1089 } 1090 } 1091 1092 return true; 1093 } 1094 1095 return false; 1096 } 1097 1098 @Override 1099 public boolean isEnabled() 1100 { 1101 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1102 1103 return super.isEnabled() && (sequence != null); 1104 } 1105 }; 1106 1107 public static IcyAbstractAction settingAction = new IcyAbstractAction("Preferences", 1108 new IcyIcon(ResourceUtil.ICON_COG), "ROI table preferences") 1109 { 1110 @Override 1111 public boolean doAction(ActionEvent e) 1112 { 1113 final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); 1114 1115 if (roisPanel != null) 1116 { 1117 roisPanel.showSettingPanel(); 1118 1119 return true; 1120 } 1121 1122 return false; 1123 } 1124 }; 1125 1126 public static IcyAbstractAction convertToStackAction = new IcyAbstractAction("to 3D stack", 1127 new IcyIcon(ResourceUtil.ICON_LAYER_V2), "Convert to 3D stack ROI", 1128 "Convert selected 2D ROI to 3D stack ROI by stacking it along the Z axis") 1129 { 1130 @Override 1131 public boolean doAction(ActionEvent e) 1132 { 1133 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1134 1135 if (sequence != null) 1136 { 1137 final int maxZ = sequence.getSizeZ() - 1; 1138 1139 // ROI Z stack conversion 1140 sequence.beginUpdate(); 1141 try 1142 { 1143 final List<ROI2D> selectedROIs = sequence.getSelectedROI2Ds(); 1144 final List<ROI> removedROIs = new ArrayList<ROI>(); 1145 final List<ROI> addedROIs = new ArrayList<ROI>(); 1146 1147 for (ROI2D roi : selectedROIs) 1148 { 1149 final ROI stackedRoi = ROIUtil.convertToStack(roi, 0, maxZ); 1150 1151 if (stackedRoi != null) 1152 { 1153 // select it by default 1154 stackedRoi.setSelected(true); 1155 1156 sequence.removeROI(roi); 1157 sequence.addROI(stackedRoi); 1158 1159 // add to undo manager 1160 removedROIs.add(roi); 1161 addedROIs.add(stackedRoi); 1162 } 1163 } 1164 1165 if (!addedROIs.isEmpty()) 1166 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1167 (addedROIs.size() > 1) ? "ROIs 3D stack conversion" : "ROI 3D stack conversion")); 1168 } 1169 catch (UnsupportedOperationException ex) 1170 { 1171 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1172 } 1173 finally 1174 { 1175 sequence.endUpdate(); 1176 } 1177 1178 return true; 1179 } 1180 1181 return false; 1182 } 1183 1184 @Override 1185 public boolean isEnabled() 1186 { 1187 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1188 } 1189 }; 1190 1191 public static IcyAbstractAction convertToMaskAction = new IcyAbstractAction("to Mask", 1192 new IcyIcon(ResourceUtil.ICON_BOOL_MASK), "Convert Shape ROI to Mask ROI", 1193 "Convert selected Shape ROI to Mask ROI by using their boolean mask") 1194 { 1195 @Override 1196 public boolean doAction(ActionEvent e) 1197 { 1198 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1199 1200 if (sequence != null) 1201 { 1202 // ROI mask conversion 1203 sequence.beginUpdate(); 1204 try 1205 { 1206 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1207 final List<ROI> removedROIs = new ArrayList<ROI>(); 1208 final List<ROI> addedROIs = new ArrayList<ROI>(); 1209 1210 for (ROI roi : selectedROIs) 1211 { 1212 final ROI maskRoi = ROIUtil.convertToMask(roi); 1213 1214 if (maskRoi != null) 1215 { 1216 // select it by default 1217 maskRoi.setSelected(true); 1218 1219 sequence.removeROI(roi); 1220 sequence.addROI(maskRoi); 1221 1222 // add to undo manager 1223 removedROIs.add(roi); 1224 addedROIs.add(maskRoi); 1225 } 1226 } 1227 1228 if (!addedROIs.isEmpty()) 1229 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1230 (addedROIs.size() > 1) ? "ROIs mask conversion" : "ROI mask conversion")); 1231 } 1232 catch (UnsupportedOperationException ex) 1233 { 1234 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1235 } 1236 finally 1237 { 1238 sequence.endUpdate(); 1239 } 1240 1241 return true; 1242 } 1243 1244 return false; 1245 } 1246 1247 @Override 1248 public boolean isEnabled() 1249 { 1250 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1251 } 1252 }; 1253 1254 public static IcyAbstractAction convertToPointAction = new IcyAbstractAction("to Point", 1255 new IcyIcon(ResourceUtil.ICON_ROI_POINT), "Convert ROI to Point ROI", 1256 "Converts selected ROI(s) to ROI Point (2D or 3D) representing the mass center of the input ROI(s)") 1257 { 1258 @Override 1259 public boolean doAction(ActionEvent e) 1260 { 1261 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1262 1263 if (sequence != null) 1264 { 1265 // ROI point conversion 1266 sequence.beginUpdate(); 1267 try 1268 { 1269 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1270 final List<ROI> removedROIs = new ArrayList<ROI>(); 1271 final List<ROI> addedROIs = new ArrayList<ROI>(); 1272 1273 for (ROI roi : selectedROIs) 1274 { 1275 final ROI roiPoint = ROIUtil.convertToPoint(roi); 1276 1277 if (roiPoint != null) 1278 { 1279 // select it by default 1280 roiPoint.setSelected(true); 1281 1282 sequence.removeROI(roi); 1283 sequence.addROI(roiPoint); 1284 1285 // add to undo manager 1286 removedROIs.add(roi); 1287 addedROIs.add(roiPoint); 1288 } 1289 } 1290 1291 if (!addedROIs.isEmpty()) 1292 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1293 (addedROIs.size() > 1) ? "ROIs point conversion" : "ROI point conversion")); 1294 } 1295 catch (UnsupportedOperationException ex) 1296 { 1297 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1298 } 1299 finally 1300 { 1301 sequence.endUpdate(); 1302 } 1303 1304 return true; 1305 } 1306 1307 return false; 1308 } 1309 1310 @Override 1311 public boolean isEnabled() 1312 { 1313 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1314 } 1315 }; 1316 1317 public static IcyAbstractAction convertToEllipseAction = new IcyAbstractAction("to Circle", 1318 new IcyIcon(ResourceUtil.ICON_ROI_OVAL), "Convert ROI to Circle ROI", 1319 "Converts selected ROI(s) to Circle ROI centered on the mass center of the input ROI(s)") 1320 { 1321 @Override 1322 public boolean doAction(ActionEvent e) 1323 { 1324 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1325 1326 if (sequence != null) 1327 { 1328 final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); 1329 1330 if (mainFrame != null) 1331 { 1332 final double radius = mainFrame.getMainRibbon().getROIRibbonTask().getRadius(); 1333 1334 // ROI point conversion 1335 sequence.beginUpdate(); 1336 try 1337 { 1338 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1339 final List<ROI> removedROIs = new ArrayList<ROI>(); 1340 final List<ROI> addedROIs = new ArrayList<ROI>(); 1341 1342 for (ROI roi : selectedROIs) 1343 { 1344 final ROI resultRoi; 1345 1346 if (radius == 0) 1347 resultRoi = ROIUtil.convertToPoint(roi); 1348 else 1349 resultRoi = ROIUtil.convertToEllipse(roi, radius, radius); 1350 1351 if (resultRoi != null) 1352 { 1353 // select it by default 1354 resultRoi.setSelected(true); 1355 1356 sequence.removeROI(roi); 1357 sequence.addROI(resultRoi); 1358 1359 // add to undo manager 1360 removedROIs.add(roi); 1361 addedROIs.add(resultRoi); 1362 } 1363 } 1364 1365 if (!addedROIs.isEmpty()) 1366 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1367 (addedROIs.size() > 1) ? "ROIs circle conversion" : "ROI circle conversion")); 1368 } 1369 catch (UnsupportedOperationException ex) 1370 { 1371 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1372 } 1373 finally 1374 { 1375 sequence.endUpdate(); 1376 } 1377 } 1378 1379 return true; 1380 } 1381 1382 return false; 1383 } 1384 1385 @Override 1386 public boolean isEnabled() 1387 { 1388 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1389 } 1390 }; 1391 1392 public static IcyAbstractAction convertToRectangleAction = new IcyAbstractAction("to Square", 1393 new IcyIcon(ResourceUtil.ICON_ROI_RECTANGLE), "Convert ROI to Square ROI", 1394 "Converts selected ROI(s) to Square ROI centered on the mass center of the input ROI(s)") 1395 { 1396 @Override 1397 public boolean doAction(ActionEvent e) 1398 { 1399 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1400 1401 if (sequence != null) 1402 { 1403 final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); 1404 1405 if (mainFrame != null) 1406 { 1407 final double size = mainFrame.getMainRibbon().getROIRibbonTask().getRadius() * 2; 1408 1409 // ROI point conversion 1410 sequence.beginUpdate(); 1411 try 1412 { 1413 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1414 final List<ROI> removedROIs = new ArrayList<ROI>(); 1415 final List<ROI> addedROIs = new ArrayList<ROI>(); 1416 1417 for (ROI roi : selectedROIs) 1418 { 1419 final ROI resultRoi; 1420 1421 if (size == 0) 1422 resultRoi = ROIUtil.convertToPoint(roi); 1423 else 1424 resultRoi = ROIUtil.convertToRectangle(roi, size, size); 1425 1426 if (resultRoi != null) 1427 { 1428 // select it by default 1429 resultRoi.setSelected(true); 1430 1431 sequence.removeROI(roi); 1432 sequence.addROI(resultRoi); 1433 1434 // add to undo manager 1435 removedROIs.add(roi); 1436 addedROIs.add(resultRoi); 1437 } 1438 } 1439 1440 if (!addedROIs.isEmpty()) 1441 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1442 (addedROIs.size() > 1) ? "ROIs square conversion" : "ROI square conversion")); 1443 } 1444 catch (UnsupportedOperationException ex) 1445 { 1446 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1447 } 1448 finally 1449 { 1450 sequence.endUpdate(); 1451 } 1452 } 1453 1454 return true; 1455 } 1456 1457 return false; 1458 } 1459 1460 @Override 1461 public boolean isEnabled() 1462 { 1463 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1464 } 1465 }; 1466 1467 public static IcyAbstractAction convertToShapeAction = new IcyAbstractAction("to Shape", 1468 new IcyIcon(ResourceUtil.ICON_ROI_POLYGON), "Convert Mask ROI to Polygon shape ROI", 1469 "Convert selected Mask ROI to Shape ROI using polygon approximation") 1470 { 1471 @Override 1472 public boolean doAction(ActionEvent e) 1473 { 1474 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1475 1476 if (sequence != null) 1477 { 1478 // ROI shape conversion 1479 sequence.beginUpdate(); 1480 try 1481 { 1482 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1483 final List<ROI> removedROIs = new ArrayList<ROI>(); 1484 final List<ROI> addedROIs = new ArrayList<ROI>(); 1485 1486 for (ROI roi : selectedROIs) 1487 { 1488 final ROI shapeRoi = ROIUtil.convertToShape(roi, -1); 1489 1490 if (shapeRoi != null) 1491 { 1492 // select it by default 1493 shapeRoi.setSelected(true); 1494 1495 sequence.removeROI(roi); 1496 sequence.addROI(shapeRoi); 1497 1498 // add to undo manager 1499 removedROIs.add(roi); 1500 addedROIs.add(shapeRoi); 1501 } 1502 } 1503 1504 if (!addedROIs.isEmpty()) 1505 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1506 (addedROIs.size() > 1) ? "ROIs shape conversion" : "ROI shape conversion")); 1507 } 1508 catch (UnsupportedOperationException ex) 1509 { 1510 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1511 } 1512 finally 1513 { 1514 sequence.endUpdate(); 1515 } 1516 1517 return true; 1518 } 1519 1520 return false; 1521 } 1522 1523 @Override 1524 public boolean isEnabled() 1525 { 1526 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1527 } 1528 }; 1529 1530 public static IcyAbstractAction separateObjectsAction = new IcyAbstractAction("Separate", 1531 new IcyIcon(ResourceUtil.ICON_ROI_COMP), "Separate regions from selected Mask ROI(s)", 1532 "Separate unconnected regions from selected Mask ROI(s)") 1533 { 1534 @Override 1535 public boolean doAction(ActionEvent e) 1536 { 1537 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1538 1539 if (sequence != null) 1540 { 1541 sequence.beginUpdate(); 1542 try 1543 { 1544 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1545 final List<ROI> removedROIs = new ArrayList<ROI>(); 1546 final List<ROI> addedROIs = new ArrayList<ROI>(); 1547 1548 for (ROI roi : selectedROIs) 1549 { 1550 final List<ROI> components = ROIUtil.getConnectedComponents(roi); 1551 1552 // nothing to do if we obtain only 1 component 1553 if (components.size() > 1) 1554 { 1555 sequence.removeROI(roi); 1556 removedROIs.add(roi); 1557 1558 for (ROI component : components) 1559 { 1560 sequence.addROI(component); 1561 // add to undo manager 1562 addedROIs.add(component); 1563 } 1564 } 1565 } 1566 1567 if (!removedROIs.isEmpty()) 1568 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1569 (removedROIs.size() > 1) ? "ROIs separate objects" : "ROI separate objects")); 1570 } 1571 catch (UnsupportedOperationException ex) 1572 { 1573 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1574 } 1575 finally 1576 { 1577 sequence.endUpdate(); 1578 } 1579 1580 return true; 1581 } 1582 1583 return false; 1584 } 1585 1586 @Override 1587 public boolean isEnabled() 1588 { 1589 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1590 } 1591 }; 1592 1593 public static IcyAbstractAction upscale2dAction = new IcyAbstractAction("Scale x2 (2D)", 1594 new IcyIcon(ResourceUtil.ICON_ROI_UPSCALE), "Create up scaled version of selected ROI(s) (2D)", 1595 "Create 2x factor up scaled version of selected ROI(s) (2D)") 1596 { 1597 @Override 1598 public boolean doAction(ActionEvent e) 1599 { 1600 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1601 1602 if (sequence != null) 1603 { 1604 sequence.beginUpdate(); 1605 try 1606 { 1607 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1608 final List<ROI> newROIs = new ArrayList<ROI>(); 1609 1610 for (ROI roi : selectedROIs) 1611 newROIs.add(ROIUtil.getUpscaled(roi, false)); 1612 1613 if (!newROIs.isEmpty()) 1614 { 1615 for (ROI roi : newROIs) 1616 sequence.addROI(roi); 1617 1618 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, newROIs, 1619 (newROIs.size() > 1) ? "ROIs scale x2" : "ROI scale x2")); 1620 } 1621 } 1622 catch (UnsupportedOperationException ex) 1623 { 1624 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1625 } 1626 finally 1627 { 1628 sequence.endUpdate(); 1629 } 1630 1631 return true; 1632 } 1633 1634 return false; 1635 } 1636 1637 @Override 1638 public boolean isEnabled() 1639 { 1640 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1641 } 1642 }; 1643 1644 public static IcyAbstractAction upscaleAction = new IcyAbstractAction("Scale x2", 1645 new IcyIcon(ResourceUtil.ICON_ROI_UPSCALE), "Create x2 scaled version of selected ROI(s)", 1646 "Create x2 factor scaled version of selected ROI(s)") 1647 { 1648 @Override 1649 public boolean doAction(ActionEvent e) 1650 { 1651 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1652 1653 if (sequence != null) 1654 { 1655 sequence.beginUpdate(); 1656 try 1657 { 1658 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1659 final List<ROI> newROIs = new ArrayList<ROI>(); 1660 1661 for (ROI roi : selectedROIs) 1662 newROIs.add(ROIUtil.getUpscaled(roi, true)); 1663 1664 if (!newROIs.isEmpty()) 1665 { 1666 for (ROI roi : newROIs) 1667 sequence.addROI(roi); 1668 1669 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, newROIs, 1670 (newROIs.size() > 1) ? "ROIs scale x2" : "ROI scale x2")); 1671 } 1672 } 1673 catch (UnsupportedOperationException ex) 1674 { 1675 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1676 } 1677 finally 1678 { 1679 sequence.endUpdate(); 1680 } 1681 1682 return true; 1683 } 1684 1685 return false; 1686 } 1687 1688 @Override 1689 public boolean isEnabled() 1690 { 1691 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1692 } 1693 }; 1694 1695 public static IcyAbstractAction downscale2dAction = new IcyAbstractAction("Scale /2 (2D)", 1696 new IcyIcon(ResourceUtil.ICON_ROI_DOWNSCALE), "Create /2 scaled version of selected ROI(s) (2D)", 1697 "Create /2 factor scaled version of selected ROI(s) (2D)") 1698 { 1699 @Override 1700 public boolean doAction(ActionEvent e) 1701 { 1702 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1703 1704 if (sequence != null) 1705 { 1706 sequence.beginUpdate(); 1707 try 1708 { 1709 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1710 final List<ROI> newROIs = new ArrayList<ROI>(); 1711 1712 for (ROI roi : newROIs) 1713 newROIs.add(ROIUtil.getDownscaled(roi, false)); 1714 1715 if (!newROIs.isEmpty()) 1716 { 1717 for (ROI roi : selectedROIs) 1718 sequence.addROI(roi); 1719 1720 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, newROIs, 1721 (newROIs.size() > 1) ? "ROIs scale /2" : "ROI scale /2")); 1722 } 1723 } 1724 catch (UnsupportedOperationException ex) 1725 { 1726 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1727 } 1728 finally 1729 { 1730 sequence.endUpdate(); 1731 } 1732 1733 return true; 1734 } 1735 1736 return false; 1737 } 1738 1739 @Override 1740 public boolean isEnabled() 1741 { 1742 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1743 } 1744 }; 1745 1746 public static IcyAbstractAction downscaleAction = new IcyAbstractAction("Scale /2", 1747 new IcyIcon(ResourceUtil.ICON_ROI_DOWNSCALE), "Create down scaled version of selected ROI(s)", 1748 "Create 2x factor down scaled version of selected ROI(s)") 1749 { 1750 @Override 1751 public boolean doAction(ActionEvent e) 1752 { 1753 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1754 1755 if (sequence != null) 1756 { 1757 sequence.beginUpdate(); 1758 try 1759 { 1760 final List<ROI> selectedROIs = sequence.getSelectedROIs(); 1761 final List<ROI> newROIs = new ArrayList<ROI>(); 1762 1763 for (ROI roi : selectedROIs) 1764 newROIs.add(ROIUtil.getDownscaled(roi, true)); 1765 1766 if (!newROIs.isEmpty()) 1767 { 1768 for (ROI roi : newROIs) 1769 sequence.addROI(roi); 1770 1771 sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, newROIs, 1772 (newROIs.size() > 1) ? "ROIs scale /2" : "ROI scale /2")); 1773 } 1774 } 1775 catch (UnsupportedOperationException ex) 1776 { 1777 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1778 } 1779 finally 1780 { 1781 sequence.endUpdate(); 1782 } 1783 1784 return true; 1785 } 1786 1787 return false; 1788 } 1789 1790 @Override 1791 public boolean isEnabled() 1792 { 1793 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1794 } 1795 }; 1796 1797 public static IcyAbstractAction autoSplitAction = new IcyAbstractAction("Auto split", 1798 new IcyIcon("split_roi", true), "Automatic split selected ROI", 1799 "Automatic split selected ROI using shape and size information.") 1800 { 1801 @Override 1802 public boolean doAction(ActionEvent e) 1803 { 1804 final Sequence sequence = Icy.getMainInterface().getActiveSequence(); 1805 1806 if (sequence != null) 1807 { 1808 sequence.beginUpdate(); 1809 try 1810 { 1811 final List<ROI2D> selectedROIs = sequence.getSelectedROI2Ds(); 1812 final List<ROI> removedROIs = new ArrayList<ROI>(); 1813 final List<ROI> addedROIs = new ArrayList<ROI>(); 1814 1815 for (ROI2D roi : selectedROIs) 1816 { 1817 // --> TODO 1818 // final List<ROI> components = ROIUtil.split(roi); 1819 // 1820 // nothing to do if we obtain only 1 component 1821 // if (components.size() > 1) 1822 // { 1823 // sequence.removeROI(roi); 1824 // removedROIs.add(roi); 1825 // 1826 // for (ROI component : components) 1827 // { 1828 // sequence.addROI(component); 1829 // // add to undo manager 1830 // addedROIs.add(component); 1831 // } 1832 // } 1833 } 1834 1835 if (!removedROIs.isEmpty()) 1836 sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, 1837 (removedROIs.size() > 1) ? "ROIs automatic split" : "ROI automatic split")); 1838 } 1839 catch (UnsupportedOperationException ex) 1840 { 1841 MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); 1842 } 1843 finally 1844 { 1845 sequence.endUpdate(); 1846 } 1847 1848 return true; 1849 } 1850 1851 return false; 1852 } 1853 1854 @Override 1855 public boolean isEnabled() 1856 { 1857 return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); 1858 } 1859 }; 1860 1861 /** 1862 * Return all actions of this class 1863 */ 1864 public static List<IcyAbstractAction> getAllActions() 1865 { 1866 final List<IcyAbstractAction> result = new ArrayList<IcyAbstractAction>(); 1867 1868 for (Field field : RoiActions.class.getFields()) 1869 { 1870 final Class<?> type = field.getType(); 1871 1872 try 1873 { 1874 if (ClassUtil.isSubClass(type, IcyAbstractAction[].class)) 1875 result.addAll(Arrays.asList(((IcyAbstractAction[]) field.get(null)))); 1876 else if (ClassUtil.isSubClass(type, IcyAbstractAction.class)) 1877 result.add((IcyAbstractAction) field.get(null)); 1878 } 1879 catch (Exception e) 1880 { 1881 // ignore 1882 } 1883 } 1884 1885 return result; 1886 } 1887}