Package ij.plugin.frame

Source Code of ij.plugin.frame.RoiManager

package ij.plugin.frame;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.awt.List;
import java.util.zip.*;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.io.*;
import ij.plugin.filter.*;
import ij.plugin.Colors;
import ij.util.*;
import ij.macro.*;
import ij.measure.*;

/** This plugin implements the Analyze/Tools/ROI Manager command. */
public class RoiManager extends PlugInFrame implements ActionListener, ItemListener, MouseListener, MouseWheelListener {
  public static final String LOC_KEY = "manager.loc";
  private static final int BUTTONS = 11;
  private static final int DRAW=0, FILL=1, LABEL=2;
  private static final int SHOW_ALL=0, SHOW_NONE=1, LABELS=2, NO_LABELS=3;
  private static final int MENU=0, COMMAND=1;
  private static int rows = 15;
  private static int lastNonShiftClick = -1;
  private static boolean allowMultipleSelections = true;
  private static String moreButtonLabel = "More "+'\u00bb';
  private Panel panel;
  private static Frame instance;
  private static int colorIndex = 4;
  private java.awt.List list;
  private Hashtable rois = new Hashtable();
  private boolean canceled;
  private boolean macro;
  private boolean ignoreInterrupts;
  private PopupMenu pm;
  private Button moreButton, colorButton;
  private Checkbox showAllCheckbox = new Checkbox("Show All", false);
  private Checkbox labelsCheckbox = new Checkbox("Edit Mode", false);

  private static boolean measureAll = true;
  private static boolean onePerSlice = true;
  private static boolean restoreCentered;
  private int prevID;
  private boolean noUpdateMode;
  private int defaultLineWidth = 1;
  private Color defaultColor;
  private boolean firstTime = true;
  private int[] selectedIndexes;
 
  public RoiManager() {
    super("ROI Manager");
    if (instance!=null) {
      WindowManager.toFront(instance);
      return;
    }
    instance = this;
    list = new List(rows, allowMultipleSelections);
    showWindow();
  }
 
  public RoiManager(boolean hideWindow) {
    super("ROI Manager");
    list = new List(rows, allowMultipleSelections);
  }

  void showWindow() {
    ImageJ ij = IJ.getInstance();
     addKeyListener(ij);
     addMouseListener(this);
    addMouseWheelListener(this);
    WindowManager.addWindow(this);
    //setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
    setLayout(new BorderLayout());
    list.add("012345678901234");
    list.addItemListener(this);
     list.addKeyListener(ij);
     list.addMouseListener(this);
     list.addMouseWheelListener(this);
    if (IJ.isLinux()) list.setBackground(Color.white);
    add("Center", list);
    panel = new Panel();
    int nButtons = BUTTONS;
    panel.setLayout(new GridLayout(nButtons, 1, 5, 0));
    addButton("Add [t]");
    addButton("Update");
    addButton("Delete");
    addButton("Rename...");
    addButton("Measure");
    addButton("Deselect");
    addButton("Properties...");
    addButton("Flatten [F]");
    addButton(moreButtonLabel);
    showAllCheckbox.addItemListener(this);
    panel.add(showAllCheckbox);
    labelsCheckbox.addItemListener(this);
    panel.add(labelsCheckbox);
    add("East", panel);   
    addPopupMenu();
    pack();
    Dimension size = getSize();
    if (size.width>270)
      setSize(size.width-40, size.height);
    list.remove(0);
    Point loc = Prefs.getLocation(LOC_KEY);
    if (loc!=null)
      setLocation(loc);
    else
      GUI.center(this);
    show();
    if (IJ.isMacOSX() && IJ.isJava16()) {
      list.setMultipleMode(false);
      list.setMultipleMode(true);
      //EventQueue.invokeLater(new Runnable() {
      //  public void run() {
      //    list.setMultipleMode(false);
      //    list.setMultipleMode(true);
      //  }
      //});
    }
  }

  void addButton(String label) {
    Button b = new Button(label);
    b.addActionListener(this);
    b.addKeyListener(IJ.getInstance());
     b.addMouseListener(this);
     if (label.equals(moreButtonLabel)) moreButton = b;
    panel.add(b);
  }

  void addPopupMenu() {
    pm=new PopupMenu();
    //addPopupItem("Select All");
    addPopupItem("Open...");
    addPopupItem("Save...");
    addPopupItem("Fill");
    addPopupItem("Draw");
    addPopupItem("AND");
    addPopupItem("OR (Combine)");
    addPopupItem("XOR");
    addPopupItem("Split");
    addPopupItem("Add Particles");
    addPopupItem("Multi Measure");
    addPopupItem("Multi Plot");
    addPopupItem("Sort");
    addPopupItem("Specify...");
    addPopupItem("Remove Slice Info");
    addPopupItem("Help");
    addPopupItem("Options...");
    add(pm);
  }

  void addPopupItem(String s) {
    MenuItem mi=new MenuItem(s);
    mi.addActionListener(this);
    pm.add(mi);
  }
 
  public void actionPerformed(ActionEvent e) {
    String label = e.getActionCommand();
    if (label==null)
      return;
    String command = label;
    if (command.equals("Add [t]"))
      runCommand("add");
    else if (command.equals("Update"))
      update(true);
    else if (command.equals("Delete"))
      delete(false);
    else if (command.equals("Rename..."))
      rename(null);
    else if (command.equals("Properties..."))
      setProperties(null, 0, null);
    else if (command.equals("Flatten [F]"))
      flatten();
    else if (command.equals("Measure"))
      measure(MENU);
    else if (command.equals("Open..."))
      open(null);
    else if (command.equals("Save..."))
      save();
    else if (command.equals("Fill"))
      drawOrFill(FILL);
    else if (command.equals("Draw"))
      drawOrFill(DRAW);
    else if (command.equals("Deselect"))
      select(-1);
    else if (command.equals(moreButtonLabel)) {
      Point ploc = panel.getLocation();
      Point bloc = moreButton.getLocation();
      pm.show(this, ploc.x, bloc.y);
    } else if (command.equals("OR (Combine)"))
      combine();
    else if (command.equals("Split"))
      split();
    else if (command.equals("AND"))
      and();
    else if (command.equals("XOR"))
      xor();
    else if (command.equals("Add Particles"))
      addParticles();
    else if (command.equals("Multi Measure"))
      multiMeasure();
    else if (command.equals("Multi Plot"))
      multiPlot();
    else if (command.equals("Sort"))
      sort();
    else if (command.equals("Specify..."))
      specify();
    else if (command.equals("Remove Slice Info"))
      removeSliceInfo();
    else if (command.equals("Help"))
      help();
    else if (command.equals("Options..."))
      options();
    else if (command.equals("\"Show All\" Color..."))
      setShowAllColor();
  }

  public void itemStateChanged(ItemEvent e) {
    Object source = e.getSource();
    if (source==showAllCheckbox) {
      if (firstTime)
        labelsCheckbox.setState(true);
      showAll(showAllCheckbox.getState()?SHOW_ALL:SHOW_NONE);
      firstTime = false;
      return;
    }
    if (source==labelsCheckbox) {
      if (firstTime)
        showAllCheckbox.setState(true);
      boolean editState = labelsCheckbox.getState();
      boolean showAllState = showAllCheckbox.getState();
      if (!showAllState && !editState)
        showAll(SHOW_NONE);
      else {
        showAll(editState?LABELS:NO_LABELS);
        if (editState) showAllCheckbox.setState(true);
      }
      firstTime = false;
      return;
    }
    if (e.getStateChange()==ItemEvent.SELECTED && !ignoreInterrupts) {
      int index = 0;
      //IJ.log("item="+e.getItem()+" shift="+IJ.shiftKeyDown()+" ctrl="+IJ. controlKeyDown());
            try {index = Integer.parseInt(e.getItem().toString());}
            catch (NumberFormatException ex) {}
      if (index<0) index = 0;
            if (!IJ.isMacintosh()) {      //handle shift-click, ctrl-click (on Mac, OS takes care of this)
                if (!IJ.shiftKeyDown()) lastNonShiftClick = index;
          if (!IJ.shiftKeyDown() && !IJ.controlKeyDown()) {  //simple click, deselect everything else
            int[] indexes = getSelectedIndexes();
            for (int i=0; i<indexes.length; i++) {
              if (indexes[i]!=index)
                list.deselect(indexes[i]);
            }
          } else if (IJ.shiftKeyDown() && lastNonShiftClick>=0 && lastNonShiftClick<list.getItemCount()) {
                    int firstIndex = Math.min(index, lastNonShiftClick);
                    int lastIndex = Math.max(index, lastNonShiftClick);
            int[] indexes = getSelectedIndexes();
            for (int i=0; i<indexes.length; i++)
              if (indexes[i]<firstIndex || indexes[i]>lastIndex)
                list.deselect(indexes[i]);      //deselect everything else
                    for (int i=firstIndex; i<=lastIndex; i++)
                        list.select(i);                     //select range
                }
            }
      if (WindowManager.getCurrentImage()!=null) {
        restore(getImage(), index, true);
        if (record()) {
          if (Recorder.scriptMode())
            Recorder.recordCall("rm.select(imp, "+index+");");
          else
            Recorder.record("roiManager", "Select", index);
        }
      }
    }
  }
 
  void add(boolean shiftKeyDown, boolean altKeyDown) {
    if (shiftKeyDown)
      addAndDraw(altKeyDown);
    else if (altKeyDown)
      addRoi(true);
    else
      addRoi(false);
  }
 
  /** Adds the specified ROI. */
  public void addRoi(Roi roi) {
    addRoi(roi, false, null, -1);
  }
 
  boolean addRoi(boolean promptForName) {
    return addRoi(null, promptForName, null, -1);
  }

  boolean addRoi(Roi roi, boolean promptForName, Color color, int lineWidth) {
    ImagePlus imp = roi==null?getImage():WindowManager.getCurrentImage();
    if (roi==null) {
      if (imp==null)
        return false;
      roi = imp.getRoi();
      if (roi==null) {
        error("The active image does not have a selection.");
        return false;
      }
    }
    if (color==null && roi.getStrokeColor()!=null)
      color = roi.getStrokeColor();
    else if (color==null && defaultColor!=null)
      color = defaultColor;
    if (lineWidth<0) {
      int sw = (int)roi.getStrokeWidth();
      lineWidth = sw>1?sw:defaultLineWidth;
    }
    if (lineWidth>100) lineWidth = 1;
    int n = list.getItemCount();
    if (n>0 && !IJ.isMacro() && imp!=null) {
      // check for duplicate
      String label = list.getItem(n-1);
      Roi roi2 = (Roi)rois.get(label);
      if (roi2!=null) {
        int slice2 = getSliceNumber(roi2, label);
        if (roi.equals(roi2) && (slice2==-1||slice2==imp.getCurrentSlice()) && imp.getID()==prevID && !Interpreter.isBatchMode())
          return false;
      }
    }
    prevID = imp!=null?imp.getID():0;
    String name = roi.getName();
    if (isStandardName(name))
      name = null;
    String label = name!=null?name:getLabel(imp, roi, -1);
    if (promptForName)
      label = promptForName(label);
    else
      label = getUniqueName(label);
    if (label==null) return false;
    list.add(label);
    roi.setName(label);
    Roi roiCopy = (Roi)roi.clone();
    if (lineWidth>1)
      roiCopy.setStrokeWidth(lineWidth);
    if (color!=null)
      roiCopy.setStrokeColor(color);
    rois.put(label, roiCopy);
    updateShowAll();
    if (record())
      recordAdd(defaultColor, defaultLineWidth);
    return true;
  }
 
  void recordAdd(Color color, int lineWidth) {
    if (Recorder.scriptMode())
      Recorder.recordCall("rm.addRoi(imp.getRoi());");
    else if (color!=null && lineWidth==1)
      Recorder.recordString("roiManager(\"Add\", \""+getHex(color)+"\");\n");
    else if (lineWidth>1)
      Recorder.recordString("roiManager(\"Add\", \""+getHex(color)+"\", "+lineWidth+");\n");
    else
      Recorder.record("roiManager", "Add");
  }
 
  String getHex(Color color) {
    if (color==null) color = ImageCanvas.getShowAllColor();
    String hex = Integer.toHexString(color.getRGB());
    if (hex.length()==8) hex = hex.substring(2);
    return hex;
  }
 
  /** Adds the specified ROI to the list. The third argument ('n') will
    be used to form the first part of the ROI label if it is >= 0. */
  public void add(ImagePlus imp, Roi roi, int n) {
    if (roi==null) return;
    String label = getLabel(imp, roi, n);
    if (label==null) return;
    list.add(label);
    roi.setName(label);
    rois.put(label, (Roi)roi.clone());
  }

  boolean isStandardName(String name) {
    if (name==null) return false;
    boolean isStandard = false;
    int len = name.length();
    if (len>=14 && name.charAt(4)=='-' && name.charAt(9)=='-' )
      isStandard = true;
    else if (len>=17 && name.charAt(5)=='-' && name.charAt(11)=='-' )
      isStandard = true;
    else if (len>=9 && name.charAt(4)=='-')
      isStandard = true;
    else if (len>=11 && name.charAt(5)=='-')
      isStandard = true;
    return isStandard;
  }
 
  String getLabel(ImagePlus imp, Roi roi, int n) {
    Rectangle r = roi.getBounds();
    int xc = r.x + r.width/2;
    int yc = r.y + r.height/2;
    if (n>=0)
      {xc = yc; yc=n;}
    if (xc<0) xc = 0;
    if (yc<0) yc = 0;
    int digits = 4;
    String xs = "" + xc;
    if (xs.length()>digits) digits = xs.length();
    String ys = "" + yc;
    if (ys.length()>digits) digits = ys.length();
    if (digits==4 && imp!=null && imp.getStackSize()>=10000) digits = 5;
    xs = "000000" + xc;
    ys = "000000" + yc;
    String label = ys.substring(ys.length()-digits) + "-" + xs.substring(xs.length()-digits);
    if (imp!=null && imp.getStackSize()>1) {
      int slice = roi.getPosition();
      if (slice==0)
        slice = imp.getCurrentSlice();
      String zs = "000000" + slice;
      label = zs.substring(zs.length()-digits) + "-" + label;
      roi.setPosition(slice);
    }
    return label;
  }

  void addAndDraw(boolean altKeyDown) {
    if (altKeyDown) {
      if (!addRoi(true)) return;
    } else if (!addRoi(false))
      return;
    ImagePlus imp = WindowManager.getCurrentImage();
    if (imp!=null) {
      Undo.setup(Undo.COMPOUND_FILTER, imp);
      IJ.run(imp, "Draw", "slice");
      Undo.setup(Undo.COMPOUND_FILTER_DONE, imp);
    }
    if (record()) Recorder.record("roiManager", "Add & Draw");
  }
 
  boolean delete(boolean replacing) {
    int count = list.getItemCount();
    if (count==0)
      return error("The list is empty.");
    int index[] = getSelectedIndexes();
    if (index.length==0 || (replacing&&count>1)) {
      String msg = "Delete all items on the list?";
      if (replacing)
        msg = "Replace items on the list?";
      canceled = false;
      if (!IJ.isMacro() && !macro) {
        YesNoCancelDialog d = new YesNoCancelDialog(this, "ROI Manager", msg);
        if (d.cancelPressed())
          {canceled = true; return false;}
        if (!d.yesPressed()) return false;
      }
      index = getAllIndexes();
    }
    for (int i=count-1; i>=0; i--) {
      boolean delete = false;
      for (int j=0; j<index.length; j++) {
        if (index[j]==i)
          delete = true;
      }
      if (delete) {
        rois.remove(list.getItem(i));
        list.remove(i);
      }
    }
    ImagePlus imp = WindowManager.getCurrentImage();
    if (count>1 && index.length==1 && imp!=null)
      imp.killRoi();
    updateShowAll();
    if (record()) Recorder.record("roiManager", "Delete");
    return true;
  }
 
  boolean update(boolean clone) {
    ImagePlus imp = getImage();
    if (imp==null) return false;
    ImageCanvas ic = imp.getCanvas();
    boolean showingAll = ic!=null &&  ic.getShowAllROIs();
    Roi roi = imp.getRoi();
    if (roi==null) {
      error("The active image does not have a selection.");
      return false;
    }
    int index = list.getSelectedIndex();
    if (index<0 && !showingAll)
      return error("Exactly one item in the list must be selected.");
    if (index>=0) {
      String name = list.getItem(index);
      rois.remove(name);
      if (clone) {
        Roi roi2 = (Roi)roi.clone();
        int position = roi.getPosition();
        if (imp.getStackSize()>1)
          roi2.setPosition(imp.getCurrentSlice());
        rois.put(name, roi2);
      } else
        rois.put(name, roi);
    }
    if (record()) Recorder.record("roiManager", "Update");
    if (showingAll) imp.draw();
    return true;
  }

  boolean rename(String name2) {
    int index = list.getSelectedIndex();
    if (index<0)
      return error("Exactly one item in the list must be selected.");
    String name = list.getItem(index);
    if (name2==null) name2 = promptForName(name);
    if (name2==null) return false;
    Roi roi = (Roi)rois.get(name);
    rois.remove(name);
    roi.setName(name2);
    rois.put(name2, roi);
    list.replaceItem(name2, index);
    list.select(index);
    if (Prefs.useNamesAsLabels && labelsCheckbox.getState()) {
      ImagePlus imp = WindowManager.getCurrentImage();
      if (imp!=null) imp.draw();
    }
    if (record())
      Recorder.record("roiManager", "Rename", name2);
    return true;
  }
 
  String promptForName(String name) {
    GenericDialog gd = new GenericDialog("ROI Manager");
    gd.addStringField("Rename As:", name, 20);
    gd.showDialog();
    if (gd.wasCanceled())
      return null;
    String name2 = gd.getNextString();
    name2 = getUniqueName(name2);
    return name2;
  }

  boolean restore(ImagePlus imp, int index, boolean setSlice) {
    String label = list.getItem(index);
    Roi roi = (Roi)rois.get(label);
    if (imp==null || roi==null)
      return false;
        if (setSlice) {
            int n = getSliceNumber(roi, label);
            if (n>=1 && n<=imp.getStackSize()) {
              if (imp.isHyperStack()||imp.isComposite())
                  imp.setPosition(n);
                else
                  imp.setSlice(n);
            }
        }
        Roi roi2 = (Roi)roi.clone();
    Calibration cal = imp.getCalibration();
    Rectangle r = roi2.getBounds();
    int width= imp.getWidth(), height=imp.getHeight();
    if (restoreCentered) {
      ImageCanvas ic = imp.getCanvas();
      if (ic!=null) {
        Rectangle r1 = ic.getSrcRect();
        Rectangle r2 = roi2.getBounds();
        roi2.setLocation(r1.x+r1.width/2-r2.width/2, r1.y+r1.height/2-r2.height/2);
      }
    }
    if (r.x>=width || r.y>=height || (r.x+r.width)<=0 || (r.y+r.height)<=0)
      roi2.setLocation((width-r.width)/2, (height-r.height)/2);
    if (noUpdateMode) {
      imp.setRoi(roi2, false);
      noUpdateMode = false;
    } else
      imp.setRoi(roi2, true);
    return true;
  }
 
  boolean restoreWithoutUpdate(int index) {
    noUpdateMode = true;
    return restore(getImage(), index, false);
  }
 
  /** Returns the slice number associated with the specified name,
    or -1 if the name does not include a slice number. */
  public int getSliceNumber(String label) {
    int slice = -1;
    if (label.length()>=14 && label.charAt(4)=='-' && label.charAt(9)=='-')
      slice = (int)Tools.parseDouble(label.substring(0,4),-1);
    else if (label.length()>=17 && label.charAt(5)=='-' && label.charAt(11)=='-')
      slice = (int)Tools.parseDouble(label.substring(0,5),-1);
    else if (label.length()>=20 && label.charAt(6)=='-' && label.charAt(13)=='-')
      slice = (int)Tools.parseDouble(label.substring(0,6),-1);
    return slice;
  }
 
  /** Returns the slice number associated with the specified ROI or name,
    or -1 if the ROI or name does not include a slice number. */
  int getSliceNumber(Roi roi, String label) {
    int slice = roi!=null?roi.getPosition():-1;
    if (slice==0)
      slice=-1;
    if (slice==-1)
      slice = getSliceNumber(label);
    return slice;
  }

  void open(String path) {
    Macro.setOptions(null);
    String name = null;
    if (path==null || path.equals("")) {
      OpenDialog od = new OpenDialog("Open Selection(s)...", "");
      String directory = od.getDirectory();
      name = od.getFileName();
      if (name==null)
        return;
      path = directory + name;
    }
    if (record()) Recorder.record("roiManager", "Open", path);
    if (path.endsWith(".zip")) {
      openZip(path);
      return;
    }
    Opener o = new Opener();
    if (name==null) name = o.getName(path);
    Roi roi = o.openRoi(path);
    if (roi!=null) {
      if (name.endsWith(".roi"))
        name = name.substring(0, name.length()-4);
      name = getUniqueName(name);
      list.add(name);
      rois.put(name, roi);
    }   
    updateShowAll();
  }
 
  // Modified on 2005/11/15 by Ulrik Stervbo to only read .roi files and to not empty the current list
  void openZip(String path) {
    ZipInputStream in = null;
    ByteArrayOutputStream out;
    int nRois = 0;
    try {
      in = new ZipInputStream(new FileInputStream(path));
      byte[] buf = new byte[1024];
      int len;
      ZipEntry entry = in.getNextEntry();
      while (entry!=null) {
        String name = entry.getName();
        if (name.endsWith(".roi")) {
          out = new ByteArrayOutputStream();
          while ((len = in.read(buf)) > 0)
            out.write(buf, 0, len);
          out.close();
          byte[] bytes = out.toByteArray();
          RoiDecoder rd = new RoiDecoder(bytes, name);
          Roi roi = rd.getRoi();
          if (roi!=null) {
            name = name.substring(0, name.length()-4);
            name = getUniqueName(name);
            list.add(name);
            rois.put(name, roi);
            nRois++;
          }
        }
        entry = in.getNextEntry();
      }
      in.close();
    } catch (IOException e) {error(e.toString());}
    if(nRois==0)
        error("This ZIP archive does not appear to contain \".roi\" files");
    updateShowAll();
  }


  String getUniqueName(String name) {
      String name2 = name;
      int n = 1;
      Roi roi2 = (Roi)rois.get(name2);
      while (roi2!=null) {
        roi2 = (Roi)rois.get(name2);
        if (roi2!=null) {
          int lastDash = name2.lastIndexOf("-");
          if (lastDash!=-1 && name2.length()-lastDash<5)
            name2 = name2.substring(0, lastDash);
          name2 = name2+"-"+n;
          n++;
        }
        roi2 = (Roi)rois.get(name2);
      }
      return name2;
  }
 
  boolean save() {
    if (list.getItemCount()==0)
      return error("The selection list is empty.");
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0)
      indexes = getAllIndexes();
    if (indexes.length>1)
      return saveMultiple(indexes, null);
    String name = list.getItem(indexes[0]);
    Macro.setOptions(null);
    SaveDialog sd = new SaveDialog("Save Selection...", name, ".roi");
    String name2 = sd.getFileName();
    if (name2 == null)
      return false;
    String dir = sd.getDirectory();
    Roi roi = (Roi)rois.get(name);
    rois.remove(name);
    if (!name2.endsWith(".roi")) name2 = name2+".roi";
    String newName = name2.substring(0, name2.length()-4);
    rois.put(newName, roi);
    roi.setName(newName);
    list.replaceItem(newName, indexes[0]);
    RoiEncoder re = new RoiEncoder(dir+name2);
    try {
      re.write(roi);
    } catch (IOException e) {
      IJ.error("ROI Manager", e.getMessage());
    }
    return true;
  }

  boolean saveMultiple(int[] indexes, String path) {
    Macro.setOptions(null);
    if (path==null) {
      SaveDialog sd = new SaveDialog("Save ROIs...", "RoiSet", ".zip");
      String name = sd.getFileName();
      if (name == null)
        return false;
      if (!(name.endsWith(".zip") || name.endsWith(".ZIP")))
        name = name + ".zip";
      String dir = sd.getDirectory();
      path = dir+name;
    }
    try {
      ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(path));
      DataOutputStream out = new DataOutputStream(new BufferedOutputStream(zos));
      RoiEncoder re = new RoiEncoder(out);
      for (int i=0; i<indexes.length; i++) {
        String label = list.getItem(indexes[i]);
        Roi roi = (Roi)rois.get(label);
        if (!label.endsWith(".roi")) label += ".roi";
            zos.putNextEntry(new ZipEntry(label));
        re.write(roi);
        out.flush();
      }
      out.close();
    }
    catch (IOException e) {
      error(""+e);
      return false;
    }
    if (record()) Recorder.record("roiManager", "Save", path);
    return true;
  }
   
  boolean measure(int mode) {
    ImagePlus imp = getImage();
    if (imp==null)
      return false;
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0)
      indexes = getAllIndexes();
        if (indexes.length==0) return false;
    boolean allSliceOne = true;
    for (int i=0; i<indexes.length; i++) {
      String label = list.getItem(indexes[i]);
      Roi roi = (Roi)rois.get(label);
      if (getSliceNumber(roi,label)>1) allSliceOne = false;
    }
    int measurements = Analyzer.getMeasurements();
    if (imp.getStackSize()>1)
      Analyzer.setMeasurements(measurements|Measurements.SLICE);
    int currentSlice = imp.getCurrentSlice();
    for (int i=0; i<indexes.length; i++) {
      if (restore(getImage(), indexes[i], !allSliceOne))
        IJ.run("Measure");
      else
        break;
    }
    imp.setSlice(currentSlice);
    Analyzer.setMeasurements(measurements);
    if (indexes.length>1)
      IJ.run("Select None");
    if (record()) Recorder.record("roiManager", "Measure");
    return true;
 
 
  /*
  void showIndexes(int[] indexes) {
    for (int i=0; i<indexes.length; i++) {
      String label = list.getItem(indexes[i]);
      Roi roi = (Roi)rois.get(label);
      IJ.log(i+" "+roi.getName());
    }
  }
  */

  /* This method performs measurements for several ROI's in a stack
    and arranges the results with one line per slice.  By constast, the
    measure() method produces several lines per slice.  The results
    from multiMeasure() may be easier to import into a spreadsheet
    program for plotting or additional analysis. Based on the multi()
    method in Bob Dougherty's Multi_Measure plugin
    (http://www.optinav.com/Multi-Measure.htm).
  */
   boolean multiMeasure() {
    ImagePlus imp = getImage();
    if (imp==null) return false;
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0)
      indexes = getAllIndexes();
        if (indexes.length==0) return false;
    int measurements = Analyzer.getMeasurements();

    int nSlices = imp.getStackSize();
    if (IJ.isMacro()) {
      if (nSlices>1) measureAll = true;
      onePerSlice = true;
    } else {
      GenericDialog gd = new GenericDialog("Multi Measure");
      if (nSlices>1)
        gd.addCheckbox("Measure All "+nSlices+" Slices", measureAll);
      gd.addCheckbox("One Row Per Slice", onePerSlice);
      int columns = getColumnCount(imp, measurements)*indexes.length;
      String str = nSlices==1?"this option":"both options";
      gd.setInsets(10, 25, 0);
      gd.addMessage(
        "Enabling "+str+" will result\n"+
        "in a table with "+columns+" columns."
      );
      gd.showDialog();
      if (gd.wasCanceled()) return false;
      if (nSlices>1)
        measureAll = gd.getNextBoolean();
      onePerSlice = gd.getNextBoolean();
    }
    if (!measureAll) nSlices = 1;
    int currentSlice = imp.getCurrentSlice();
   
    if (!onePerSlice) {
      int measurements2 = nSlices>1?measurements|Measurements.SLICE:measurements;
      ResultsTable rt = new ResultsTable();
      Analyzer analyzer = new Analyzer(imp, measurements2, rt);
      for (int slice=1; slice<=nSlices; slice++) {
        if (nSlices>1) imp.setSliceWithoutUpdate(slice);
        for (int i=0; i<indexes.length; i++) {
          if (restoreWithoutUpdate(indexes[i]))
            analyzer.measure();
          else
            break;
        }
      }
      rt.show("Results");
      if (nSlices>1) imp.setSlice(currentSlice);
      return true;
    }

    Analyzer aSys = new Analyzer(imp); //System Analyzer
    ResultsTable rtSys = Analyzer.getResultsTable();
    ResultsTable rtMulti = new ResultsTable();
    Analyzer aMulti = new Analyzer(imp, measurements, rtMulti); //Private Analyzer

    for (int slice=1; slice<=nSlices; slice++) {
      int sliceUse = slice;
      if(nSlices == 1)sliceUse = currentSlice;
      imp.setSliceWithoutUpdate(sliceUse);
      rtMulti.incrementCounter();
      int roiIndex = 0;
      for (int i=0; i<indexes.length; i++) {
        if (restoreWithoutUpdate(indexes[i])) {
          roiIndex++;
          aSys.measure();
          for (int j=0; j<=rtSys.getLastColumn(); j++){
            float[] col = rtSys.getColumn(j);
            String head = rtSys.getColumnHeading(j);
            String suffix = ""+roiIndex;
            Roi roi = imp.getRoi();
            if (roi!=null) {
              String name = roi.getName();
              if (name!=null && name.length()>0 && (name.length()<9||!Character.isDigit(name.charAt(0))))
                suffix = "("+name+")";
            }
            if (head!=null && col!=null && !head.equals("Slice"))
              rtMulti.addValue(head+suffix,rtSys.getValue(j,rtSys.getCounter()-1));
          }
        } else
          break;
      }
      //aMulti.displayResults();
      //aMulti.updateHeadings();
    }
    rtMulti.show("Results");

    imp.setSlice(currentSlice);
    if (indexes.length>1)
      IJ.run("Select None");
    if (record()) Recorder.record("roiManager", "Multi Measure");
    return true;
  }
 
  int getColumnCount(ImagePlus imp, int measurements) {
    ImageStatistics stats = imp.getStatistics(measurements);
    ResultsTable rt = new ResultsTable();
    Analyzer analyzer = new Analyzer(imp, measurements, rt);
    analyzer.saveResults(stats, null);
    int count = 0;
    for (int i=0; i<=rt.getLastColumn(); i++) {
      float[] col = rt.getColumn(i);
      String head = rt.getColumnHeading(i);
      if (head!=null && col!=null)
        count++;
    }
    return count;
  }
 
  void multiPlot() {
    ImagePlus imp = getImage();
    if (imp==null) return;
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0) indexes = getAllIndexes();
    int n = indexes.length;
        if (n==0) return;
    Color[] colors = {Color.blue, Color.green, Color.magenta, Color.red, Color.cyan, Color.yellow};
    if (n>colors.length) {
      colors = new Color[n];
      double c = 0;
      double inc =150.0/n;
      for (int i=0; i<n; i++) {
        colors[i] = new Color((int)c, (int)c, (int)c);
        c += inc;
      }
    }
    int currentSlice = imp.getCurrentSlice();
    double[][] x = new double[n][];
    double[][] y = new double[n][];
    double minY = Double.MAX_VALUE;
    double maxY = -Double.MAX_VALUE;
    int maxX = 0;
    Calibration cal = imp.getCalibration();
    double xinc = cal.pixelWidth;
    for (int i=0; i<indexes.length; i++) {
      if (!restore(getImage(), indexes[i], true)) break;
      Roi roi = imp.getRoi();
      if (roi==null) break;
      if (roi.isArea() && roi.getType()!=Roi.RECTANGLE)
        IJ.run(imp, "Area to Line", "");
      ProfilePlot pp = new ProfilePlot(imp, IJ.altKeyDown());
      y[i] = pp.getProfile();
      if (y[i]==null) break;
      if (y[i].length>maxX) maxX = y[i].length;
      double[] a = Tools.getMinMax(y[i]);
      if (a[0]<minY) minY=a[0];
      if (a[1]>maxY) maxY = a[1];
      double[] xx = new double[y[i].length];
      for (int j=0; j<xx.length; j++)
        xx[j] = j*xinc;
      x[i] = xx;
    }
    String xlabel = "Distance ("+cal.getUnits()+")";
    Plot plot = new Plot("Profiles",xlabel, "Value", x[0], y[0]);
    plot.setLimits(0, maxX*xinc, minY, maxY);
    for (int i=1; i<indexes.length; i++) {
      plot.setColor(colors[i]);
      if (x[i]!=null)
        plot.addPoints(x[i], y[i], Plot.LINE);
    }
    plot.setColor(colors[0]);
    if (x[0]!=null)
      plot.show();
    imp.setSlice(currentSlice);
    if (indexes.length>1)
      IJ.run("Select None");
    if (record()) Recorder.record("roiManager", "Multi Plot");
 

  boolean drawOrFill(int mode) {
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0)
      indexes = getAllIndexes();
    ImagePlus imp = WindowManager.getCurrentImage();
    imp.killRoi();
    ImageProcessor ip = imp.getProcessor();
    ip.setColor(Toolbar.getForegroundColor());
    ip.snapshot();
    Undo.setup(Undo.FILTER, imp);
    Filler filler = mode==LABEL?new Filler():null;
    int slice = imp.getCurrentSlice();
    for (int i=0; i<indexes.length; i++) {
      String name = list.getItem(indexes[i]);
      Roi roi = (Roi)rois.get(name);
      int type = roi.getType();
      if (roi==null) continue;
      if (mode==FILL&&(type==Roi.POLYLINE||type==Roi.FREELINE||type==Roi.ANGLE))
        mode = DRAW;
            int slice2 = getSliceNumber(roi, name);
            if (slice2>=1 && slice2<=imp.getStackSize()) {
                imp.setSlice(slice2);
        ip = imp.getProcessor();
        ip.setColor(Toolbar.getForegroundColor());
        if (slice2!=slice) Undo.reset();
            }
       switch (mode) {
        case DRAW: roi.drawPixels(ip); break;
        case FILL: ip.fill(roi); break;
        case LABEL:
          roi.drawPixels(ip);
          filler.drawLabel(imp, ip, i+1, roi.getBounds());
          break;
      }
    }
    ImageCanvas ic = imp.getCanvas();
    if (ic!=null) ic.setShowAllROIs(false);
    imp.updateAndDraw();
    return true;
  }

  void setProperties(Color color, int lineWidth, Color fillColor) {
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0)
      indexes = getAllIndexes();
    int n = indexes.length;
        if (n==0) return;
    Roi rpRoi = null;
    String rpName = null;
    Font font = null;
    int justification = TextRoi.LEFT;
    double opacity = -1;
        if (color==null && lineWidth==0 && fillColor==null) {
      String label = list.getItem(indexes[0]);
      rpRoi = (Roi)rois.get(label);
      if (n==1) {
        fillColor =  rpRoi.getFillColor();
        rpName = rpRoi.getName();
      }
      if (rpRoi.getStrokeColor()==null)
        rpRoi.setStrokeColor(ImageCanvas.getShowAllColor());
      rpRoi = (Roi) rpRoi.clone();
      if (n>1)
        rpRoi.setName("range: "+(indexes[0]+1)+"-"+(indexes[n-1]+1));
      rpRoi.setFillColor(fillColor);
      RoiProperties rp = new RoiProperties("Properties", rpRoi);
      if (!rp.showDialog())
        return;
      lineWidth =  (int)rpRoi.getStrokeWidth();
      defaultLineWidth = lineWidth;
      color =  rpRoi.getStrokeColor();
      fillColor =  rpRoi.getFillColor();
      defaultColor = color;
      if (rpRoi instanceof TextRoi) {
        font = ((TextRoi)rpRoi).getCurrentFont();
        justification = ((TextRoi)rpRoi).getJustification();
      }
      if (rpRoi instanceof ImageRoi)
        opacity = ((ImageRoi)rpRoi).getOpacity();
    }
    ImagePlus imp = WindowManager.getCurrentImage();
    if (n==list.getItemCount() && n>1 && !IJ.isMacro()) {
      GenericDialog gd = new GenericDialog("ROI Manager");
      gd.addMessage("Apply changes to all "+n+" selections?");
      gd.showDialog();
      if (gd.wasCanceled()) return;
    }
    for (int i=0; i<n; i++) {
      String label = list.getItem(indexes[i]);
      Roi roi = (Roi)rois.get(label);
      //IJ.log("set "+color+"  "+lineWidth+"  "+fillColor);
      if (color!=null) roi.setStrokeColor(color);
      if (lineWidth>1) roi.setStrokeWidth(lineWidth);
      roi.setFillColor(fillColor);
      if (roi!=null && (roi instanceof TextRoi)) {
        roi.setImage(imp);
        if (font!=null)
          ((TextRoi)roi).setCurrentFont(font);
        ((TextRoi)roi).setJustification(justification);
        roi.setImage(null);
      }
      if (roi!=null && (roi instanceof ImageRoi) && opacity!=-1)
        ((ImageRoi)roi).setOpacity(opacity);
    }
    if (rpRoi!=null && rpName!=null && !rpRoi.getName().equals(rpName))
      rename(rpRoi.getName());
    ImageCanvas ic = imp!=null?imp.getCanvas():null;
    Roi roi = imp!=null?imp.getRoi():null;
    boolean showingAll = ic!=null &&  ic.getShowAllROIs();
    if (roi!=null && (n==1||!showingAll)) {
      if (lineWidth>1) roi.setStrokeWidth(lineWidth);
      if (color!=null) roi.setStrokeColor(color);
      if (fillColor!=null) roi.setFillColor(fillColor);
      if (roi!=null && (roi instanceof TextRoi)) {
        ((TextRoi)roi).setCurrentFont(font);
        ((TextRoi)roi).setJustification(justification);
      }
      if (roi!=null && (roi instanceof ImageRoi) && opacity!=-1)
        ((ImageRoi)roi).setOpacity(opacity);
    }
    if (lineWidth>1 && !showingAll && roi==null) {
      showAll(SHOW_ALL);
      showingAll = true;
    }
    if (imp!=null) imp.draw();
    if (record()) {
      if (fillColor!=null)
        Recorder.record("roiManager", "Set Fill Color", Colors.colorToString(fillColor));
      else {
        Recorder.record("roiManager", "Set Color", Colors.colorToString(color!=null?color:Color.red));
        Recorder.record("roiManager", "Set Line Width", lineWidth);
      }
    }
  }
 
  void flatten() {
    ImagePlus imp = WindowManager.getCurrentImage();
    if (imp==null)
      {IJ.noImage(); return;}
    ImageCanvas ic = imp.getCanvas();
    if (!ic.getShowAllROIs() && ic.getDisplayList()==null && imp.getRoi()==null)
      error("Image does not have an overlay or ROI");
    else
      IJ.doCommand("Flatten"); // run Image>Flatten in separate thread
  }
     
  public boolean getDrawLabels() {
    return labelsCheckbox.getState();
  }

  void combine() {
    ImagePlus imp = getImage();
    if (imp==null) return;
    int[] indexes = getSelectedIndexes();
    if (indexes.length==1) {
      error("More than one item must be selected, or none");
      return;
    }
    if (indexes.length==0)
      indexes = getAllIndexes();
    int nPointRois = 0;
    for (int i=0; i<indexes.length; i++) {
      Roi roi = (Roi)rois.get(list.getItem(indexes[i]));
      if (roi.getType()==Roi.POINT)
        nPointRois++;
      else
        break;
    }
    if (nPointRois==indexes.length)
      combinePoints(imp, indexes);
    else
      combineRois(imp, indexes);
    if (record()) Recorder.record("roiManager", "Combine");
  }
 
  void combineRois(ImagePlus imp, int[] indexes) {
    ShapeRoi s1=null, s2=null;
    for (int i=0; i<indexes.length; i++) {
      Roi roi = (Roi)rois.get(list.getItem(indexes[i]));
      if (roi.isLine() || roi.getType()==Roi.POINT)
        continue;
      if (s1==null) {
        if (roi instanceof ShapeRoi)
          s1 = (ShapeRoi)roi;
        else
          s1 = new ShapeRoi(roi);
        if (s1==null) return;
      } else {
        if (roi instanceof ShapeRoi)
          s2 = (ShapeRoi)roi;
        else
          s2 = new ShapeRoi(roi);
        if (s2==null) continue;
        if (roi.isArea())
          s1.or(s2);
      }
    }
    if (s1!=null)
      imp.setRoi(s1);
  }

  void combinePoints(ImagePlus imp, int[] indexes) {
    int n = indexes.length;
    Polygon[] p = new Polygon[n];
    int points = 0;
    for (int i=0; i<n; i++) {
      Roi roi = (Roi)rois.get(list.getItem(indexes[i]));
      p[i] = roi.getPolygon();
      points += p[i].npoints;
    }
    if (points==0) return;
    int[] xpoints = new int[points];
    int[] ypoints = new int[points];
    int index = 0;
    for (int i=0; i<p.length; i++) {
      for (int j=0; j<p[i].npoints; j++) {
        xpoints[index] = p[i].xpoints[j];
        ypoints[index] = p[i].ypoints[j];
        index++;
     
    }
    imp.setRoi(new PointRoi(xpoints, ypoints, xpoints.length));
  }

  void and() {
    ImagePlus imp = getImage();
    if (imp==null) return;
    int[] indexes = getSelectedIndexes();
    if (indexes.length==1) {
      error("More than one item must be selected, or none");
      return;
    }
    if (indexes.length==0)
      indexes = getAllIndexes();
    ShapeRoi s1=null, s2=null;
    for (int i=0; i<indexes.length; i++) {
      Roi roi = (Roi)rois.get(list.getItem(indexes[i]));
      if (!roi.isArea()) continue;
      if (s1==null) {
        if (roi instanceof ShapeRoi)
          s1 = (ShapeRoi)roi.clone();
        else
          s1 = new ShapeRoi(roi);
        if (s1==null) return;
      } else {
        if (roi instanceof ShapeRoi)
          s2 = (ShapeRoi)roi.clone();
        else
          s2 = new ShapeRoi(roi);
        if (s2==null) continue;
        s1.and(s2);
      }
    }
    if (s1!=null) imp.setRoi(s1);
    if (record()) Recorder.record("roiManager", "AND");
  }

  void xor() {
    ImagePlus imp = getImage();
    if (imp==null) return;
    int[] indexes = getSelectedIndexes();
    if (indexes.length==1) {
      error("More than one item must be selected, or none");
      return;
    }
    if (indexes.length==0)
      indexes = getAllIndexes();
    ShapeRoi s1=null, s2=null;
    for (int i=0; i<indexes.length; i++) {
      Roi roi = (Roi)rois.get(list.getItem(indexes[i]));
      if (!roi.isArea()) continue;
      if (s1==null) {
        if (roi instanceof ShapeRoi)
          s1 = (ShapeRoi)roi.clone();
        else
          s1 = new ShapeRoi(roi);
        if (s1==null) return;
      } else {
        if (roi instanceof ShapeRoi)
          s2 = (ShapeRoi)roi.clone();
        else
          s2 = new ShapeRoi(roi);
        if (s2==null) continue;
        s1.xor(s2);
      }
    }
    if (s1!=null) imp.setRoi(s1);
    if (record()) Recorder.record("roiManager", "XOR");
  }

  void addParticles() {
    String err = IJ.runMacroFile("ij.jar:AddParticles", null);
    if (err!=null && err.length()>0)
      error(err);
  }

  void sort() {
    int n = rois.size();
    if (n==0) return;
    String[] labels = new String[n];
    int index = 0;
    for (Enumeration en=rois.keys(); en.hasMoreElements();)
      labels[index++] = (String)en.nextElement();
    list.removeAll();
    StringSorter.sort(labels);
    for (int i=0; i<labels.length; i++)
      list.add(labels[i]);
    if (record()) Recorder.record("roiManager", "Sort");
  }
 
  void specify() {
    try {IJ.run("Specify...");}
    catch (Exception e) {return;}
    runCommand("add");
  }
 
  void removeSliceInfo() {
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0)
      indexes = getAllIndexes();
    for (int i=0; i<indexes.length; i++) {
      int index = indexes[i];
      String name = list.getItem(index);
      int n = getSliceNumber(name);
      if (n==-1) continue;
      String name2 = name.substring(5, name.length());
      name2 = getUniqueName(name2);
      Roi roi = (Roi)rois.get(name);
      rois.remove(name);
      roi.setName(name2);
      roi.setPosition(0);
      rois.put(name2, roi);
      list.replaceItem(name2, index);
    }
  }

  void help() {
    String macro = "run('URL...', 'url="+IJ.URL+"/docs/menus/analyze.html#manager');";
    new MacroRunner(macro);
  }

  void options() {
    Color c = ImageCanvas.getShowAllColor();
    GenericDialog gd = new GenericDialog("Options");
    gd.addPanel(makeButtonPanel(gd), GridBagConstraints.CENTER, new Insets(5, 0, 0, 0));
    gd.addCheckbox("Associate \"Show All\" ROIs with slices", Prefs.showAllSliceOnly);
    gd.addCheckbox("Restore ROIs centered", restoreCentered);
    gd.addCheckbox("Use ROI names as labels", Prefs.useNamesAsLabels);
    gd.showDialog();
    if (gd.wasCanceled()) {
      if (c!=ImageCanvas.getShowAllColor())
        ImageCanvas.setShowAllColor(c);
      return;
    }
    Prefs.showAllSliceOnly = gd.getNextBoolean();
    restoreCentered = gd.getNextBoolean();
    Prefs.useNamesAsLabels = gd.getNextBoolean();
    ImagePlus imp = WindowManager.getCurrentImage();
    if (imp!=null) imp.draw();
    if (record()) {
      Recorder.record("roiManager", "Associate", Prefs.showAllSliceOnly?"true":"false");
      Recorder.record("roiManager", "Centered", restoreCentered?"true":"false");
      Recorder.record("roiManager", "UseNames", Prefs.useNamesAsLabels?"true":"false");
    }
  }

  Panel makeButtonPanel(GenericDialog gd) {
    Panel panel = new Panel();
      //buttons.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 0));
    colorButton = new Button("\"Show All\" Color...");
    colorButton.addActionListener(this);
    panel.add(colorButton);
    return panel;
  }
 
  void setShowAllColor() {
            ColorChooser cc = new ColorChooser("\"Show All\" Color", ImageCanvas.getShowAllColor()false);
            ImageCanvas.setShowAllColor(cc.getColor());
  }

  void split() {
    ImagePlus imp = getImage();
    if (imp==null) return;
    Roi roi = imp.getRoi();
    if (roi==null || roi.getType()!=Roi.COMPOSITE) {
      error("Image with composite selection required");
      return;
    }
    boolean record = Recorder.record;
    Recorder.record = false;
    Roi[] rois = ((ShapeRoi)roi).getRois();
    for (int i=0; i<rois.length; i++) {
      imp.setRoi(rois[i]);
      addRoi(false);
    }
    Recorder.record = record;
    if (record()) Recorder.record("roiManager", "Split");
  }
 
  void showAll(int mode) {
    ImagePlus imp = WindowManager.getCurrentImage();
    if (imp==null)
      {error("There are no images open."); return;}
    ImageCanvas ic = imp.getCanvas();
    if (ic==null) return;
    boolean showAll = mode==SHOW_ALL;
    if (mode==LABELS) {
      showAll = true;
      if (record())
        Recorder.record("roiManager", "Show All with labels");
    } else if (mode==NO_LABELS) {
      showAll = true;
      if (record())
        Recorder.record("roiManager", "Show All without labels");
    }
    if (showAll) imp.killRoi();
    ic.setShowAllROIs(showAll);
    if (record())
      Recorder.record("roiManager", showAll?"Show All":"Show None");
    imp.draw();
  }

  void updateShowAll() {
    ImagePlus imp = WindowManager.getCurrentImage();
    if (imp==null) return;
    ImageCanvas ic = imp.getCanvas();
    if (ic!=null && ic.getShowAllROIs())
      imp.draw();
  }

  int[] getAllIndexes() {
    int count = list.getItemCount();
    int[] indexes = new int[count];
    for (int i=0; i<count; i++)
      indexes[i] = i;
    return indexes;
  }
   
  ImagePlus getImage() {
    ImagePlus imp = WindowManager.getCurrentImage();
    if (imp==null) {
      error("There are no images open.");
      return null;
    } else
      return imp;
  }

  boolean error(String msg) {
    new MessageDialog(this, "ROI Manager", msg);
    Macro.abort();
    return false;
  }
 
  public void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID()==WindowEvent.WINDOW_CLOSING) {
      instance = null
    }
    if (!IJ.isMacro())
      ignoreInterrupts = false;
  }
 
  /** Returns a reference to the ROI Manager
    or null if it is not open. */
  public static RoiManager getInstance() {
    return (RoiManager)instance;
  }

  /**  Returns the ROI Hashtable.
    @see getCount
    @see getRoisAsArray
  */
  public Hashtable getROIs() {
    return rois;
  }

  /** Returns the selection list.
    @see getCount
    @see getRoisAsArray
  */
  public List getList() {
    return list;
  }
 
  /** Returns the ROI count. */
  public int getCount() {
    return list.getItemCount();
  }

  /** Returns the ROIs as an array. */
  public Roi[] getRoisAsArray() {
    int n = list.getItemCount();
    Roi[] array = new Roi[n];
    for (int i=0; i<n; i++) {
      String label = list.getItem(i);
      array[i] = (Roi)rois.get(label);
    }
    return array;
  }
 
  /** Returns the selected ROIs as an array, or
    all the ROIs if none are selected. */
  public Roi[] getSelectedRoisAsArray() {
    int[] indexes = getSelectedIndexes();
    if (indexes.length==0)
      indexes = getAllIndexes();
    int n = indexes.length;
    Roi[] array = new Roi[n];
    for (int i=0; i<n; i++) {
      String label = list.getItem(indexes[i]);
      array[i] = (Roi)rois.get(label);
    }
    return array;
  }
     
  /** Returns the name of the ROI with the specified index.
    Can be called from a macro using
    <pre>call("ij.plugin.frame.RoiManager.getName", index)</pre>
    Returns "null" if the Roi Manager is not open or index is
    out of range.
  */
  public static String getName(String index) {
    int i = (int)Tools.parseDouble(index, -1);
    RoiManager instance = getInstance();
    if (instance!=null && i>=0 && i<instance.list.getItemCount())
            return  instance.list.getItem(i);
    else
      return "null";
  }

  /** Executes the ROI Manager "Add", "Add & Draw", "Update", "Delete", "Measure", "Draw",
    "Show All", Show None", "Fill", "Deselect", "Select All", "Combine", "AND", "XOR", "Split",
    "Sort" or "Multi Measure" command.  Returns false if <code>cmd</code>
    is not one of these strings. */
  public boolean runCommand(String cmd) {
    cmd = cmd.toLowerCase();
    macro = true;
    boolean ok = true;
    if (cmd.equals("add")) {
      boolean shift = IJ.shiftKeyDown();
      boolean alt = IJ.altKeyDown();
      if (Interpreter.isBatchMode()) {
        shift = false;
        alt = false;
      }
      ImagePlus imp = WindowManager.getCurrentImage();
      Roi roi = imp!=null?imp.getRoi():null;
      if (roi!=null) roi.setPosition(0);
      add(shift, alt);
    } else if (cmd.equals("add & draw"))
      addAndDraw(false);
    else if (cmd.equals("update"))
      update(true);
    else if (cmd.equals("update2"))
      update(false);
    else if (cmd.equals("delete"))
      delete(false);
    else if (cmd.equals("measure"))
      measure(COMMAND);
    else if (cmd.equals("draw"))
      drawOrFill(DRAW);
    else if (cmd.equals("fill"))
      drawOrFill(FILL);
    else if (cmd.equals("label"))
      drawOrFill(LABEL);
    else if (cmd.equals("and"))
      and();
    else if (cmd.equals("or") || cmd.equals("combine"))
      combine();
    else if (cmd.equals("xor"))
      xor();
    else if (cmd.equals("split"))
      split();
    else if (cmd.equals("sort"))
      sort();
    else if (cmd.equals("multi measure"))
      multiMeasure();
    else if (cmd.equals("multi plot"))
      multiPlot();
    else if (cmd.startsWith("show all")) {
      if (WindowManager.getCurrentImage()!=null) {
        showAll(SHOW_ALL);
        showAllCheckbox.setState(true);
      }
    } else if (cmd.startsWith("show none")) {
      if (WindowManager.getCurrentImage()!=null) {
        showAll(SHOW_NONE);
        showAllCheckbox.setState(false);
      }
    } else if (cmd.equals("show all with labels")) {
      labelsCheckbox.setState(true);
      showAll(LABELS);
      if (Interpreter.isBatchMode()) IJ.wait(250);
    } else if (cmd.equals("show all without labels")) {
      labelsCheckbox.setState(false);
      showAll(NO_LABELS);
      if (Interpreter.isBatchMode()) IJ.wait(250);
    } else if (cmd.equals("deselect")||cmd.indexOf("all")!=-1) {
      if (IJ.isMacOSX()) ignoreInterrupts = true;
      select(-1);
      IJ.wait(50);
    } else if (cmd.equals("reset")) {
      if (IJ.isMacOSX() && IJ.isMacro())
        ignoreInterrupts = true;
      list.removeAll();
      rois.clear();
      updateShowAll();
    } else if (cmd.equals("debug")) {
      //IJ.log("Debug: "+debugCount);
      //for (int i=0; i<debugCount; i++)
        //  IJ.log(debug[i]);
    } else if (cmd.equals("enable interrupts")) {
      ignoreInterrupts = false;
    } else
      ok = false;
    macro = false;
    return ok;
  }

  /** Executes the ROI Manager "Open", "Save" or "Rename" command. Returns false if
  <code>cmd</code> is not "Open", "Save" or "Rename", or if an error occurs. */
  public boolean runCommand(String cmd, String name) {
    cmd = cmd.toLowerCase();
    macro = true;
    if (cmd.equals("open")) {
      open(name);
      macro = false;
      return true;
    } else if (cmd.equals("save")) {
      if (!name.endsWith(".zip") && !name.equals(""))
        return error("Name must end with '.zip'");
      if (list.getItemCount()==0)
        return error("The selection list is empty.");
      int[] indexes = getAllIndexes();
      boolean ok = false;
      if (name.equals(""))
        ok = saveMultiple(indexes, null);
      else
        ok = saveMultiple(indexes, name);
      macro = false;
      return ok;
    } else if (cmd.equals("rename")) {
      rename(name);
      macro = false;
      return true;
    } else if (cmd.equals("set color")) {
      Color color = Colors.decode(name, Color.cyan);
      setProperties(color, 0, null);
      macro = false;
      return true;
    } else if (cmd.equals("set fill color")) {
      Color fillColor = Colors.decode(name, Color.cyan);
      setProperties(null, 0, fillColor);
      macro = false;
      return true;
    } else if (cmd.equals("set line width")) {
      int lineWidth = (int)Tools.parseDouble(name, 0);
      if (lineWidth!=0) setProperties(null, lineWidth, null);
      macro = false;
      return true;
    } else if (cmd.equals("associate")) {
      Prefs.showAllSliceOnly = name.equals("true")?true:false;
      macro = false;
      return true;
    } else if (cmd.equals("centered")) {
      restoreCentered = name.equals("true")?true:false;
      macro = false;
      return true;
    } else if (cmd.equals("usenames")) {
      Prefs.useNamesAsLabels = name.equals("true")?true:false;
      macro = false;
      if (labelsCheckbox.getState()) {
        ImagePlus imp = WindowManager.getCurrentImage();
        if (imp!=null) imp.draw();
      }
      return true;
    }
    return false;
  }
 
  /** Adds the current selection to the ROI Manager, using the
    specified color (a 6 digit hex string) and line width. */
  public boolean runCommand(String cmd, String hexColor, double lineWidth) {
    if (hexColor==null && lineWidth==1.0 && (IJ.altKeyDown()&&!Interpreter.isBatchMode()))
      addRoi(true);
    else {
      Color color = hexColor!=null?Colors.decode(hexColor, Color.cyan):null;
      addRoi(null, false, color, (int)Math.round(lineWidth));
    }
    return true
  }
 
  /** Assigns the ROI at the specified index to the current image. */
  public void select(int index) {
    select(null, index);
  }
 
  /** Assigns the ROI at the specified index to 'imp'. */
  public void select(ImagePlus imp, int index) {
    selectedIndexes = null;
    int n = list.getItemCount();
    if (index<0) {
      for (int i=0; i<n; i++)
        if (list.isSelected(i)) list.deselect(i);
      if (record()) Recorder.record("roiManager", "Deselect");
      return;
    }
    if (index>=n) return;
    boolean mm = list.isMultipleMode();
    if (mm) list.setMultipleMode(false);
    int delay = 1;
    long start = System.currentTimeMillis();
    while (true) {
      list.select(index);
      if (delay>1) IJ.wait(delay);
      if (list.isIndexSelected(index))
        break;
      for (int i=0; i<n; i++)
        if (list.isSelected(i)) list.deselect(i);
      IJ.wait(delay);
      delay *= 2; if (delay>32) delay=32;
      if ((System.currentTimeMillis()-start)>1000L)
        error("Failed to select ROI "+index);
    }
    if (imp==null) imp=getImage();
    restore(imp, index, true)
    if (mm) list.setMultipleMode(true);
  }
 
  public void select(int index, boolean shiftKeyDown, boolean altKeyDown) {
    if (!(shiftKeyDown||altKeyDown))
      select(index);
    ImagePlus imp = IJ.getImage();
    if (imp==null) return;
    Roi previousRoi = imp.getRoi();
    if (previousRoi==null)
      {select(index); return;}
    Roi.previousRoi = (Roi)previousRoi.clone();
    String label = list.getItem(index);
    Roi roi = (Roi)rois.get(label);
    if (roi!=null) {
      roi.setImage(imp);
      roi.update(shiftKeyDown, altKeyDown);
    }
  }
 
  public void setEditMode(ImagePlus imp, boolean editMode) {
    ImageCanvas ic = imp.getCanvas();
    boolean showAll = false;
    if (ic!=null) {
      showAll = ic.getShowAllROIs() | editMode;
      ic.setShowAllROIs(showAll);
      imp.draw();
    }
    showAllCheckbox.setState(showAll);
    labelsCheckbox.setState(editMode);
  }
 
  /*
  void selectAll() {
    boolean allSelected = true;
    int count = list.getItemCount();
    for (int i=0; i<count; i++) {
      if (!list.isIndexSelected(i))
        allSelected = false;
    }
    if (allSelected)
      select(-1);
    else {
      for (int i=0; i<count; i++)
        if (!list.isSelected(i)) list.select(i);
    }
  }
  */

    /** Overrides PlugInFrame.close(). */
    public void close() {
      super.close();
      instance = null;
    Prefs.saveLocation(LOC_KEY, getLocation());
    }
   
    public void mousePressed (MouseEvent e) {
    int x=e.getX(), y=e.getY();
    if (e.isPopupTrigger() || e.isMetaDown())
      pm.show(e.getComponent(),x,y);
  }

  public void mouseWheelMoved(MouseWheelEvent event) {
    synchronized(this) {
      int index = list.getSelectedIndex();
      int rot = event.getWheelRotation();
      if (rot<-1) rot = -1;
      if (rot>1) rot = 1;
      index += rot;
      if (index<0) index = 0;
      if (index>=list.getItemCount()) index = list.getItemCount();
      //IJ.log(index+"  "+rot);
      select(index);
      if (IJ.isWindows())
        list.requestFocusInWindow();
    }
  }
 
  public void setSelectedIndexes(int[] indexes) {
    selectedIndexes = indexes;
  }
 
  private int[] getSelectedIndexes() {
    if (selectedIndexes!=null) {
      int[] indexes = selectedIndexes;
      selectedIndexes = null;
      return indexes;
    } else
      return list.getSelectedIndexes();
  }

  private boolean record() {
    return Recorder.record && !IJ.isMacro();
  }

   public void mouseReleased (MouseEvent e) {}
  public void mouseClicked (MouseEvent e) {}
  public void mouseEntered (MouseEvent e) {}
  public void mouseExited (MouseEvent e) {}

}
TOP

Related Classes of ij.plugin.frame.RoiManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.