/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.action; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.io.StringReader; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.w3c.dom.Document; import icy.clipboard.Clipboard; import icy.file.FileUtil; import icy.gui.dialog.MessageDialog; import icy.gui.dialog.OpenDialog; import icy.gui.dialog.SaveDialog; import icy.gui.inspector.RoisPanel; import icy.main.Icy; import icy.preferences.GeneralPreferences; import icy.resource.ResourceUtil; import icy.resource.icon.IcyIcon; import icy.roi.ROI; import icy.roi.ROI2D; import icy.roi.ROI3D; import icy.roi.ROI4D; import icy.roi.ROIUtil; import icy.sequence.Sequence; import icy.sequence.edit.ROIAddSequenceEdit; import icy.sequence.edit.ROIAddsSequenceEdit; import icy.sequence.edit.ROIReplacesSequenceEdit; import icy.system.SystemUtil; import icy.util.ClassUtil; import icy.util.StringUtil; import icy.util.XLSUtil; import icy.util.XMLUtil; import jxl.write.WritableSheet; import jxl.write.WritableWorkbook; import plugins.kernel.roi.roi2d.ROI2DRectangle; import plugins.kernel.roi.roi3d.ROI3DStackRectangle; import plugins.kernel.roi.roi4d.ROI4DStackRectangle; import plugins.kernel.roi.roi5d.ROI5DStackRectangle; /** * Roi actions (open / save / copy / paste / merge...) * * @author Stephane */ public class RoiActions { public static final String DEFAULT_ROI_DIR = "roi"; public static final String DEFAULT_ROI_NAME = "roi.xml"; public static IcyAbstractAction loadAction = new IcyAbstractAction("Load", new IcyIcon(ResourceUtil.ICON_OPEN), "Load ROI(s) from file", "Load ROI(s) from a XML file and add them to the active sequence") { /** * */ private static final long serialVersionUID = 2378084039864016238L; @Override public boolean doAction(ActionEvent e) { final String filename = OpenDialog.chooseFile("Load roi(s)...", DEFAULT_ROI_DIR, DEFAULT_ROI_NAME); final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if ((filename != null) && (sequence != null)) { final Document doc = XMLUtil.loadDocument(filename); if (doc != null) { final List<ROI> rois = ROI.loadROIsFromXML(XMLUtil.getRootElement(doc)); sequence.beginUpdate(); try { // add to sequence for (ROI roi : rois) sequence.addROI(roi); } finally { sequence.endUpdate(); } // add to undo manager sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, rois) { @Override public String getPresentationName() { if (getROIs().size() > 1) return "ROIs loaded from XML file"; return "ROI loaded from XML file"; }; }); return true; } } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction saveAction = new IcyAbstractAction("Save", new IcyIcon(ResourceUtil.ICON_SAVE), "Save selected ROI(s) to file", "Save the selected ROI(s) from active sequence into a XML file") { /** * */ private static final long serialVersionUID = 349358870716619748L; @Override public boolean doAction(ActionEvent e) { final String filename = SaveDialog.chooseFile("Save roi(s)...", DEFAULT_ROI_DIR, DEFAULT_ROI_NAME); final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if ((filename != null) && (sequence != null)) { final List<ROI> rois = sequence.getSelectedROIs(); if (rois.size() > 0) { final Document doc = XMLUtil.createDocument(true); if (doc != null) { ROI.saveROIsToXML(XMLUtil.getRootElement(doc), rois); XMLUtil.saveDocument(doc, filename); return true; } } } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction copyAction = new IcyAbstractAction("Copy", new IcyIcon(ResourceUtil.ICON_COPY), "Copy selected ROI to clipboard (Ctrl+C)", KeyEvent.VK_C, SystemUtil.getMenuCtrlMask()) { /** * */ private static final long serialVersionUID = -4716027958152503425L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { final List<ROI> rois = sequence.getSelectedROIs(); if (rois.size() > 0) { // need to get a copy of the ROI (as it can change meanwhile) for (int i = 0; i < rois.size(); i++) { final ROI roi = rois.get(i).getCopy(); if (roi != null) rois.set(i, roi); } // save in the Icy clipboard Clipboard.put(Clipboard.TYPE_ROILIST, rois); // clear system clipboard Clipboard.clearSystem(); pasteAction.setEnabled(true); return true; } } return false; } @Override public boolean isEnabled() { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); return super.isEnabled() && (sequence != null) && (sequence.getSelectedROIs().size() > 0); } }; public static IcyAbstractAction copyLinkAction = new IcyAbstractAction("Copy link", new IcyIcon(ResourceUtil.ICON_LINK_COPY), "Copy link of selected ROI to clipboard (Alt+C)", KeyEvent.VK_C, InputEvent.ALT_MASK) { /** * */ private static final long serialVersionUID = -4716027958152503425L; @Override public boolean doAction(ActionEvent e) { final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if (roisPanel != null) { final List<ROI> rois = roisPanel.getSelectedRois(); if (rois.size() > 0) { // save in the Icy clipboard Clipboard.put(Clipboard.TYPE_ROILINKLIST, rois); // clear system clipboard Clipboard.clearSystem(); pasteLinkAction.setEnabled(true); return true; } } return false; } @Override public boolean isEnabled() { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); return super.isEnabled() && (sequence != null) && (sequence.getSelectedROIs().size() > 0); } }; public static IcyAbstractAction pasteAction = new IcyAbstractAction("Paste", new IcyIcon(ResourceUtil.ICON_PASTE), "Paste ROI from clipboard (Ctrl+V)", KeyEvent.VK_V, SystemUtil.getMenuCtrlMask()) { /** * */ private static final long serialVersionUID = 4878585451006567513L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { @SuppressWarnings("unchecked") final List<ROI> rois = (List<ROI>) Clipboard.get(Clipboard.TYPE_ROILIST); if ((rois != null) && (rois.size() > 0)) { final List<ROI> copyRois = new ArrayList<ROI>(); sequence.beginUpdate(); try { // unselect all rois sequence.setSelectedROI(null); // add copy to sequence (so we can do the paste operation severals time) for (ROI roi : rois) { final ROI newROI = roi.getCopy(); if (newROI != null) { copyRois.add(newROI); // select the ROI newROI.setSelected(true); // and add it sequence.addROI(newROI); } } } finally { sequence.endUpdate(); } // add to undo manager sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, copyRois) { @Override public String getPresentationName() { if (getROIs().size() > 1) return "ROIs added from clipboard"; return "ROI added from clipboard"; }; }); return true; } } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null) && Clipboard.getType().equals(Clipboard.TYPE_ROILIST); } }; public static IcyAbstractAction pasteLinkAction = new IcyAbstractAction("Paste link", new IcyIcon(ResourceUtil.ICON_LINK_PASTE), "Paste ROI link from clipboard (Alt+V)", KeyEvent.VK_V, InputEvent.ALT_MASK) { /** * */ private static final long serialVersionUID = 4878585451006567513L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { @SuppressWarnings("unchecked") final List<ROI> rois = (List<ROI>) Clipboard.get(Clipboard.TYPE_ROILINKLIST); if ((rois != null) && (rois.size() > 0)) { sequence.beginUpdate(); try { // add to sequence for (ROI roi : rois) sequence.addROI(roi); } finally { sequence.endUpdate(); } // add to undo manager sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, rois) { @Override public String getPresentationName() { if (getROIs().size() > 1) return "ROIs linked from clipboard"; return "ROI linked from clipboard"; }; }); return true; } } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null) && Clipboard.getType().equals(Clipboard.TYPE_ROILINKLIST); } }; // public static IcyAbstractAction clearClipboardAction = new IcyAbstractAction("Clear", new // IcyIcon( // ResourceUtil.ICON_CLIPBOARD_CLEAR), "Remove ROI saved in clipboard") // { // /** // * // */ // private static final long serialVersionUID = 4878585451006567513L; // // @Override // public boolean doAction(ActionEvent e) // { // Clipboard.remove(ID_ROI_COPY_CLIPBOARD, false); // pasteAction.setEnabled(false); // } // // @Override // public boolean isEnabled() // { // return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null) // && Clipboard.hasObjects(RoiActions.ID_ROI_COPY_CLIPBOARD, false); // } // }; public static IcyAbstractAction selectAllAction = new IcyAbstractAction("SelectAll", (IcyIcon) null, "Select all ROI(s)") { /** * */ private static final long serialVersionUID = 3219000949426093919L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { sequence.setSelectedROIs((List<ROI>) sequence.getROIs()); return true; } return false; } @Override public boolean isEnabled() { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); return super.isEnabled() && (sequence != null) && (sequence.getROIs().size() > 0); } }; public static IcyAbstractAction unselectAction = new IcyAbstractAction("Unselect", (IcyIcon) null, "Unselect ROI(s)", KeyEvent.VK_ESCAPE) { /** * */ private static final long serialVersionUID = -6136680076368815566L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { sequence.setSelectedROI(null); return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction deleteAction = new IcyAbstractAction("Delete", new IcyIcon(ResourceUtil.ICON_DELETE), "Delete selected ROI(s)", "Delete selected ROI(s) from the active sequence", KeyEvent.VK_DELETE, 0) { /** * */ private static final long serialVersionUID = 9079403002834893222L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { sequence.removeSelectedROIs(false, true); return true; } return false; } @Override public boolean isEnabled() { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); return super.isEnabled() && (sequence != null) && (sequence.getSelectedROIs().size() > 0); } }; public static IcyAbstractAction boolNotAction = new IcyAbstractAction("Inversion", new IcyIcon(ResourceUtil.ICON_ROI_NOT), "Boolean inversion operation", "Create a new ROI representing the inverse of selected ROI", true, "Computing inverse...") { /** * */ private static final long serialVersionUID = 6360796066188754099L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if ((sequence != null) && (roisPanel != null)) { // NOT operation sequence.beginUpdate(); try { final List<ROI> selectedROI = roisPanel.getSelectedRois(); // work only on single ROI if (selectedROI.size() != 1) return false; final ROI roi = selectedROI.get(0); final ROI seqRoi; switch (roi.getDimension()) { case 2: final ROI2D roi2d = (ROI2D) roi; final ROI2DRectangle seqRoi2d = new ROI2DRectangle(sequence.getBounds2D()); // set on same position seqRoi2d.setZ(roi2d.getZ()); seqRoi2d.setT(roi2d.getT()); seqRoi2d.setC(roi2d.getC()); seqRoi = seqRoi2d; break; case 3: final ROI3D roi3d = (ROI3D) roi; final ROI3DStackRectangle seqRoi3d = new ROI3DStackRectangle( sequence.getBounds5D().toRectangle3D()); // set on same position seqRoi3d.setT(roi3d.getT()); seqRoi3d.setC(roi3d.getC()); seqRoi = seqRoi3d; break; case 4: final ROI4D roi4d = (ROI4D) roi; final ROI4DStackRectangle seqRoi4d = new ROI4DStackRectangle( sequence.getBounds5D().toRectangle4D()); // set on same position seqRoi4d.setC(roi4d.getC()); seqRoi = seqRoi4d; break; case 5: seqRoi = new ROI5DStackRectangle(sequence.getBounds5D()); break; default: seqRoi = null; break; } if (seqRoi != null) { // we do the NOT operation by subtracting current ROI to sequence bounds ROI final ROI mergeROI = ROIUtil.subtract(seqRoi, roi); if (mergeROI != null) { mergeROI.setName("Inverse"); sequence.addROI(mergeROI); sequence.setSelectedROI(mergeROI); // add to undo manager sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Inverse")); } } else MessageDialog.showDialog("Operation not supported", "Input ROI has incorrect dimension !", MessageDialog.ERROR_MESSAGE); } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction boolOrAction = new IcyAbstractAction("Union", new IcyIcon(ResourceUtil.ICON_ROI_OR), "Boolean union operation", "Create a new ROI representing the union of selected ROIs", true, "Computing union...") { /** * */ private static final long serialVersionUID = 1861052712498233441L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if ((sequence != null) && (roisPanel != null)) { // OR operation sequence.beginUpdate(); try { final List<ROI> selectedROIs = roisPanel.getSelectedRois(); final ROI mergeROI = ROIUtil.getUnion(selectedROIs); if (mergeROI != null) { mergeROI.setName("Union"); sequence.addROI(mergeROI); sequence.setSelectedROI(mergeROI); // add to undo manager sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Union")); } } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction boolAndAction = new IcyAbstractAction("Intersection", new IcyIcon(ResourceUtil.ICON_ROI_AND), "Boolean intersection operation", "Create a new ROI representing the intersection of selected ROIs", true, "Computing intersection...") { /** * */ private static final long serialVersionUID = -9103158044679039413L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if ((sequence != null) && (roisPanel != null)) { // AND operation sequence.beginUpdate(); try { final List<ROI> selectedROIs = roisPanel.getSelectedRois(); final ROI mergeROI = ROIUtil.getIntersection(selectedROIs); if (mergeROI != null) { mergeROI.setName("Intersection"); sequence.addROI(mergeROI); sequence.setSelectedROI(mergeROI); // add to undo manager sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Intersection")); } } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction boolXorAction = new IcyAbstractAction("Exclusive union", new IcyIcon(ResourceUtil.ICON_ROI_XOR), "Boolean exclusive union operation", "Create a new ROI representing the exclusive union of selected ROIs", true, "Computing exclusive union...") { /** * */ private static final long serialVersionUID = 1609345474914807703L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if ((sequence != null) && (roisPanel != null)) { // XOR operation sequence.beginUpdate(); try { final List<ROI> selectedROIs = roisPanel.getSelectedRois(); final ROI mergeROI = ROIUtil.getExclusiveUnion(selectedROIs); if (mergeROI != null) { mergeROI.setName("Exclusive union"); sequence.addROI(mergeROI); sequence.setSelectedROI(mergeROI); // add to undo manager sequence.addUndoableEdit(new ROIAddSequenceEdit(sequence, mergeROI, "ROI Exclusive Union")); } } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction boolSubtractAction = new IcyAbstractAction("Subtraction", new IcyIcon(ResourceUtil.ICON_ROI_SUB), "Boolean subtraction", "Create 2 ROIs representing the result of (A - B) and (B - A)", true, "Computing subtraction...") { /** * */ private static final long serialVersionUID = 9094641559971542667L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if ((sequence != null) && (roisPanel != null)) { // SUB operation sequence.beginUpdate(); try { final List<ROI> selectedROI = roisPanel.getSelectedRois(); final List<ROI> generatedROIs = new ArrayList<ROI>(); // Subtraction work only when 2 ROI are selected if (selectedROI.size() != 2) return false; final ROI subtractAB = ROIUtil.subtract(selectedROI.get(0), selectedROI.get(1)); final ROI subtractBA = ROIUtil.subtract(selectedROI.get(1), selectedROI.get(0)); subtractAB.setName("Subtract A-B"); subtractBA.setName("Subtract B-A"); generatedROIs.add(subtractAB); generatedROIs.add(subtractBA); sequence.beginUpdate(); try { for (ROI roi : generatedROIs) sequence.addROI(roi); sequence.setSelectedROIs(generatedROIs); // add to undo manager sequence.addUndoableEdit(new ROIAddsSequenceEdit(sequence, generatedROIs, "ROI Subtraction")); } finally { sequence.endUpdate(); } } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.getLocalizedMessage(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction xlsExportAction = new IcyAbstractAction("Export", new IcyIcon(ResourceUtil.ICON_XLS_EXPORT), "ROI Excel export", "Export the content of the ROI table into a XLS/CSV file", true, "Exporting ROI informations...") { /** * */ private static final long serialVersionUID = 9094641559971542667L; @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if ((sequence != null) && (roisPanel != null)) { final String content = roisPanel.getCSVFormattedInfos(); if (StringUtil.isEmpty(content) || roisPanel.getVisibleRois().isEmpty()) { MessageDialog.showDialog("Nothing to export !", MessageDialog.INFORMATION_MESSAGE); return true; } // get the global result folder final String dir = GeneralPreferences.getResultFolder(); // create it if needed FileUtil.createDir(dir); final String filename = SaveDialog.chooseFile("Export ROIs...", dir, "result", ".xls"); if (filename != null) { // update result folder GeneralPreferences.setResultFolder(FileUtil.getDirectory(filename)); // CSV format wanted ? if (FileUtil.getFileExtension(filename, false).equalsIgnoreCase("csv")) { try { // just write CSV content final PrintWriter out = new PrintWriter(filename); out.println(content); out.close(); } catch (FileNotFoundException e1) { MessageDialog.showDialog("Error", e1.getMessage(), MessageDialog.ERROR_MESSAGE); } } // XLS export else { try { final WritableWorkbook workbook = XLSUtil.createWorkbook(filename); final WritableSheet sheet = XLSUtil.createNewPage(workbook, "ROIS"); final BufferedReader br = new BufferedReader(new StringReader(content)); String line; int y = 0; while ((line = br.readLine()) != null) { int x = 0; // use tab as separator for (String col : line.split("\t")) { XLSUtil.setCellString(sheet, x, y, col); x++; } y++; } XLSUtil.saveAndClose(workbook); } catch (Exception e1) { MessageDialog.showDialog("Error", e1.getMessage(), MessageDialog.ERROR_MESSAGE); } } } return true; } return false; } @Override public boolean isEnabled() { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); return super.isEnabled() && (sequence != null); } }; public static IcyAbstractAction settingAction = new IcyAbstractAction("Preferences", new IcyIcon(ResourceUtil.ICON_COG), "ROI table preferences") { @Override public boolean doAction(ActionEvent e) { final RoisPanel roisPanel = Icy.getMainInterface().getRoisPanel(); if (roisPanel != null) { roisPanel.showSettingPanel(); return true; } return false; } }; public static IcyAbstractAction convertToStackAction = new IcyAbstractAction("to 3D stack", new IcyIcon(ResourceUtil.ICON_LAYER_V2), "Convert to 3D stack ROI", "Convert selected 2D ROI to 3D stack ROI by stacking it along the Z axis") { @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { final int maxZ = sequence.getSizeZ() - 1; // ROI Z stack conversion sequence.beginUpdate(); try { final List<ROI2D> selectedROIs = sequence.getSelectedROI2Ds(); final List<ROI> removedROIs = new ArrayList<ROI>(); final List<ROI> addedROIs = new ArrayList<ROI>(); for (ROI2D roi : selectedROIs) { final ROI stackedRoi = ROIUtil.convertToStack(roi, 0, maxZ); if (stackedRoi != null) { // select it by default stackedRoi.setSelected(true); sequence.removeROI(roi); sequence.addROI(stackedRoi); // add to undo manager removedROIs.add(roi); addedROIs.add(stackedRoi); } } if (!addedROIs.isEmpty()) sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, (addedROIs.size() > 1) ? "ROIs 3D stack conversion" : "ROI 3D stack conversion")); } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction convertToMaskAction = new IcyAbstractAction("to Mask", new IcyIcon(ResourceUtil.ICON_BOOL_MASK), "Convert Shape ROI to Mask ROI", "Convert selected Shape ROI to Mask ROI by using their boolean mask") { @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { // ROI mask conversion sequence.beginUpdate(); try { final List<ROI> selectedROIs = sequence.getSelectedROIs(); final List<ROI> removedROIs = new ArrayList<ROI>(); final List<ROI> addedROIs = new ArrayList<ROI>(); for (ROI roi : selectedROIs) { final ROI maskRoi = ROIUtil.convertToMask(roi); if (maskRoi != null) { // select it by default maskRoi.setSelected(true); sequence.removeROI(roi); sequence.addROI(maskRoi); // add to undo manager removedROIs.add(roi); addedROIs.add(maskRoi); } } if (!addedROIs.isEmpty()) sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, (addedROIs.size() > 1) ? "ROIs mask conversion" : "ROI mask conversion")); } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction convertToShapeAction = new IcyAbstractAction("to Shape", new IcyIcon(ResourceUtil.ICON_ROI_POLYGON), "Convert Mask ROI to Polygon shape ROI", "Convert selected Mask ROI to Shape ROI using polygon approximation") { @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { // ROI shape conversion sequence.beginUpdate(); try { final List<ROI> selectedROIs = sequence.getSelectedROIs(); final List<ROI> removedROIs = new ArrayList<ROI>(); final List<ROI> addedROIs = new ArrayList<ROI>(); for (ROI roi : selectedROIs) { final ROI shapeRoi = ROIUtil.convertToShape(roi, -1); if (shapeRoi != null) { // select it by default shapeRoi.setSelected(true); sequence.removeROI(roi); sequence.addROI(shapeRoi); // add to undo manager removedROIs.add(roi); addedROIs.add(shapeRoi); } } if (!addedROIs.isEmpty()) sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, (addedROIs.size() > 1) ? "ROIs shape conversion" : "ROI shape conversion")); } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; public static IcyAbstractAction separateObjectsAction = new IcyAbstractAction("Separate", new IcyIcon(ResourceUtil.ICON_ROI_COMP), "Separate objects from selected Mask ROI", "Separate objects (connected components) from selected Mask ROI.") { @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { sequence.beginUpdate(); try { final List<ROI> selectedROIs = sequence.getSelectedROIs(); final List<ROI> removedROIs = new ArrayList<ROI>(); final List<ROI> addedROIs = new ArrayList<ROI>(); for (ROI roi : selectedROIs) { final List<ROI> components = ROIUtil.getConnectedComponents(roi); // nothing to do if we obtain only 1 component if (components.size() > 1) { sequence.removeROI(roi); removedROIs.add(roi); for (ROI component : components) { sequence.addROI(component); // add to undo manager addedROIs.add(component); } } } if (!removedROIs.isEmpty()) sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, (removedROIs.size() > 1) ? "ROIs separate objects" : "ROI separate objects")); } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; // public static IcyAbstractAction manualCutAction = new IcyAbstractAction("Manual cut", // new IcyIcon(ResourceUtil.ICON_CUT), "Manual cut/split ROI", // "Manual cut/split ROI by drawing a straight 2D line over it.") // { // @Override // public boolean doAction(ActionEvent e) // { // // we do nothing here, ROI cut is done simulating a specific ROI // final Viewer viewer = Icy.getMainInterface().getActiveViewer(); // if (viewer == null) return false; // // // // // return false; // } // // @Override // public boolean isEnabled() // { // return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); // } // }; public static IcyAbstractAction autoSplitAction = new IcyAbstractAction("Auto split", new IcyIcon("split_roi", true), "Automatic split selected ROI", "Automatic split selected ROI using shape and size information.") { @Override public boolean doAction(ActionEvent e) { final Sequence sequence = Icy.getMainInterface().getActiveSequence(); if (sequence != null) { sequence.beginUpdate(); try { final List<ROI2D> selectedROIs = sequence.getSelectedROI2Ds(); final List<ROI> removedROIs = new ArrayList<ROI>(); final List<ROI> addedROIs = new ArrayList<ROI>(); for (ROI2D roi : selectedROIs) { // --> TODO // final List<ROI> components = ROIUtil.split(roi); // // nothing to do if we obtain only 1 component // if (components.size() > 1) // { // sequence.removeROI(roi); // removedROIs.add(roi); // // for (ROI component : components) // { // sequence.addROI(component); // // add to undo manager // addedROIs.add(component); // } // } } if (!removedROIs.isEmpty()) sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROIs, addedROIs, (removedROIs.size() > 1) ? "ROIs automatic split" : "ROI automatic split")); } catch (UnsupportedOperationException ex) { MessageDialog.showDialog("Operation not supported", ex.toString(), MessageDialog.ERROR_MESSAGE); } finally { sequence.endUpdate(); } return true; } return false; } @Override public boolean isEnabled() { return super.isEnabled() && (Icy.getMainInterface().getActiveSequence() != null); } }; /** * Return all actions of this class */ public static List<IcyAbstractAction> getAllActions() { final List<IcyAbstractAction> result = new ArrayList<IcyAbstractAction>(); for (Field field : RoiActions.class.getFields()) { final Class<?> type = field.getType(); try { if (ClassUtil.isSubClass(type, IcyAbstractAction[].class)) result.addAll(Arrays.asList(((IcyAbstractAction[]) field.get(null)))); else if (ClassUtil.isSubClass(type, IcyAbstractAction.class)) result.add((IcyAbstractAction) field.get(null)); } catch (Exception e) { // ignore } } return result; } }