Search in sources :

Example 1 with MatchIntensities

use of org.janelia.intensity.MatchIntensities in project TrakEM2 by trakem2.

the class Display method actionPerformed.

@Override
public void actionPerformed(final ActionEvent ae) {
    dispatcher.exec(new Runnable() {

        @Override
        public void run() {
            final String command = ae.getActionCommand();
            if (command.startsWith("Job")) {
                if (Utils.checkYN("Really cancel job?")) {
                    project.getLoader().quitJob(command);
                    repairGUI();
                }
                return;
            } else if (command.equals("Move to top")) {
                if (null == active)
                    return;
                canvas.setUpdateGraphics(true);
                getLayerSet().addUndoMoveStep(active);
                layer.getParent().move(LayerSet.TOP, active);
                getLayerSet().addUndoMoveStep(active);
                Display.repaint(layer.getParent(), active, 5);
            // Display.updatePanelIndex(layer, active);
            } else if (command.equals("Move up")) {
                if (null == active)
                    return;
                canvas.setUpdateGraphics(true);
                getLayerSet().addUndoMoveStep(active);
                layer.getParent().move(LayerSet.UP, active);
                getLayerSet().addUndoMoveStep(active);
                Display.repaint(layer.getParent(), active, 5);
            // Display.updatePanelIndex(layer, active);
            } else if (command.equals("Move down")) {
                if (null == active)
                    return;
                canvas.setUpdateGraphics(true);
                getLayerSet().addUndoMoveStep(active);
                layer.getParent().move(LayerSet.DOWN, active);
                getLayerSet().addUndoMoveStep(active);
                Display.repaint(layer.getParent(), active, 5);
            // Display.updatePanelIndex(layer, active);
            } else if (command.equals("Move to bottom")) {
                if (null == active)
                    return;
                canvas.setUpdateGraphics(true);
                getLayerSet().addUndoMoveStep(active);
                layer.getParent().move(LayerSet.BOTTOM, active);
                getLayerSet().addUndoMoveStep(active);
                Display.repaint(layer.getParent(), active, 5);
            // Display.updatePanelIndex(layer, active);
            } else if (command.equals("Duplicate, link and send to next layer")) {
                duplicateLinkAndSendTo(active, 1, layer.getParent().next(layer));
            } else if (command.equals("Duplicate, link and send to previous layer")) {
                duplicateLinkAndSendTo(active, 0, layer.getParent().previous(layer));
            } else if (command.equals("Duplicate, link and send to...")) {
                // fix non-scrolling popup menu
                Utils.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        final GenericDialog gd = new GenericDialog("Send to");
                        gd.addMessage("Duplicate, link and send to...");
                        final String[] sl = new String[layer.getParent().size()];
                        int next = 0;
                        for (final Layer la : layer.getParent().getLayers()) {
                            sl[next++] = project.findLayerThing(la).toString();
                        }
                        gd.addChoice("Layer: ", sl, sl[layer.getParent().indexOf(layer)]);
                        gd.showDialog();
                        if (gd.wasCanceled())
                            return;
                        final Layer la = layer.getParent().getLayer(gd.getNextChoiceIndex());
                        if (layer == la) {
                            Utils.showMessage("Can't duplicate, link and send to the same layer.");
                            return;
                        }
                        duplicateLinkAndSendTo(active, 0, la);
                    }
                });
            } else if (-1 != command.indexOf("z = ")) {
                // this is an item from the "Duplicate, link and send to" menu of layer z's
                final Layer target_layer = layer.getParent().getLayer(Double.parseDouble(command.substring(command.lastIndexOf(' ') + 1)));
                Utils.log2("layer: __" + command.substring(command.lastIndexOf(' ') + 1) + "__");
                if (null == target_layer)
                    return;
                duplicateLinkAndSendTo(active, 0, target_layer);
            } else if (-1 != command.indexOf("z=")) {
                // WARNING the indexOf is very similar to the previous one
                // Send the linked group to the selected layer
                final int iz = command.indexOf("z=") + 2;
                Utils.log2("iz=" + iz + "  other: " + command.indexOf(' ', iz + 2));
                int end = command.indexOf(' ', iz);
                if (-1 == end)
                    end = command.length();
                final double lz = Double.parseDouble(command.substring(iz, end));
                final Layer target = layer.getParent().getLayer(lz);
                // TODO what happens when ZDisplayable are selected?
                layer.getParent().move(selection.getAffected(), active.getLayer(), target);
            } else if (command.equals("Unlink")) {
                if (null == active || active instanceof Patch)
                    return;
                active.unlink();
                // selection.update();
                updateSelection();
            } else if (command.equals("Unlink from images")) {
                if (null == active)
                    return;
                try {
                    for (final Displayable displ : selection.getSelected()) {
                        displ.unlinkAll(Patch.class);
                    }
                    // selection.update();
                    updateSelection();
                } catch (final Exception e) {
                    IJError.print(e);
                }
            } else if (command.equals("Unlink slices")) {
                final YesNoCancelDialog yn = new YesNoCancelDialog(frame, "Attention", "Really unlink all slices from each other?\nThere is no undo.");
                if (!yn.yesPressed())
                    return;
                final ArrayList<Patch> pa = ((Patch) active).getStackPatches();
                for (int i = pa.size() - 1; i > 0; i--) {
                    pa.get(i).unlink(pa.get(i - 1));
                }
            } else if (command.equals("Send to next layer")) {
                final Rectangle box = selection.getBox();
                try {
                    // unlink Patch instances
                    for (final Displayable displ : selection.getSelected()) {
                        displ.unlinkAll(Patch.class);
                    }
                    // selection.update();
                    updateSelection();
                } catch (final Exception e) {
                    IJError.print(e);
                }
                // layer.getParent().moveDown(layer, active); // will repaint whatever appropriate layers
                selection.moveDown();
                repaint(layer.getParent(), box);
            } else if (command.equals("Send to previous layer")) {
                final Rectangle box = selection.getBox();
                try {
                    // unlink Patch instances
                    for (final Displayable displ : selection.getSelected()) {
                        displ.unlinkAll(Patch.class);
                    }
                    // selection.update();
                    updateSelection();
                } catch (final Exception e) {
                    IJError.print(e);
                }
                // layer.getParent().moveUp(layer, active); // will repaint whatever appropriate layers
                selection.moveUp();
                repaint(layer.getParent(), box);
            } else if (command.equals("Show centered")) {
                if (active == null)
                    return;
                showCentered(active);
            } else if (command.equals("Delete...")) {
                // remove all selected objects
                selection.deleteAll();
            } else if (command.equals("Color...")) {
                IJ.doCommand("Color Picker...");
            } else if (command.equals("Revert")) {
                if (null == active || active.getClass() != Patch.class)
                    return;
                final Patch p = (Patch) active;
                if (!p.revert()) {
                    if (null == p.getOriginalPath())
                        Utils.log("No editions to save for patch " + p.getTitle() + " #" + p.getId());
                    else
                        Utils.log("Could not revert Patch " + p.getTitle() + " #" + p.getId());
                }
            } else if (command.equals("Remove alpha mask")) {
                Display.removeAlphaMasks(selection.get(Patch.class));
            } else if (command.equals("Undo")) {
                Bureaucrat.createAndStart(new Worker.Task("Undo") {

                    @Override
                    public void exec() {
                        layer.getParent().undoOneStep();
                        Display.repaint(layer.getParent());
                    }
                }, project);
            } else if (command.equals("Redo")) {
                Bureaucrat.createAndStart(new Worker.Task("Redo") {

                    @Override
                    public void exec() {
                        layer.getParent().redoOneStep();
                        Display.repaint(layer.getParent());
                    }
                }, project);
            } else if (command.equals("Apply transform")) {
                canvas.applyTransform();
            } else if (command.equals("Apply transform propagating to last layer")) {
                if (mode.getClass() == AffineTransformMode.class || mode.getClass() == NonLinearTransformMode.class) {
                    final LayerSet ls = getLayerSet();
                    // +1 to exclude current layer
                    final HashSet<Layer> subset = new HashSet<Layer>(ls.getLayers(ls.indexOf(Display.this.layer) + 1, ls.size() - 1));
                    if (mode.getClass() == AffineTransformMode.class)
                        ((AffineTransformMode) mode).applyAndPropagate(subset);
                    else if (mode.getClass() == NonLinearTransformMode.class)
                        ((NonLinearTransformMode) mode).apply(subset);
                    setMode(new DefaultMode(Display.this));
                }
            } else if (command.equals("Apply transform propagating to first layer")) {
                if (mode.getClass() == AffineTransformMode.class || mode.getClass() == NonLinearTransformMode.class) {
                    final LayerSet ls = getLayerSet();
                    // -1 to exclude current layer
                    final HashSet<Layer> subset = new HashSet<Layer>(ls.getLayers(0, ls.indexOf(Display.this.layer) - 1));
                    if (mode.getClass() == AffineTransformMode.class)
                        ((AffineTransformMode) mode).applyAndPropagate(subset);
                    else if (mode.getClass() == NonLinearTransformMode.class)
                        ((NonLinearTransformMode) mode).apply(subset);
                    setMode(new DefaultMode(Display.this));
                }
            } else if (command.equals("Cancel transform")) {
                // calls getMode().cancel()
                canvas.cancelTransform();
            } else if (command.equals("Specify transform...")) {
                if (null == active)
                    return;
                selection.specify();
            } else if (command.equals("Exit inspection")) {
                getMode().cancel();
                setMode(new DefaultMode(Display.this));
            } else if (command.equals("Inspect image mesh triangles")) {
                setMode(new InspectPatchTrianglesMode(Display.this));
            } else if (command.equals("Hide all but images")) {
                final ArrayList<Class<?>> type = new ArrayList<Class<?>>();
                type.add(Patch.class);
                type.add(Stack.class);
                final Collection<Displayable> col = layer.getParent().hideExcept(type, false);
                selection.removeAll(col);
                Display.updateCheckboxes(col, DisplayablePanel.VISIBILITY_STATE);
                Display.update(layer.getParent(), false);
            } else if (command.equals("Unhide all")) {
                Display.updateCheckboxes(layer.getParent().setAllVisible(false), DisplayablePanel.VISIBILITY_STATE);
                Display.update(layer.getParent(), false);
            } else if (command.startsWith("Hide all ")) {
                // skip the ending plural 's'
                final String type = command.substring(9, command.length() - 1);
                final Collection<Displayable> col = layer.getParent().setVisible(type, false, true);
                selection.removeAll(col);
                Display.updateCheckboxes(col, DisplayablePanel.VISIBILITY_STATE);
            } else if (command.startsWith("Unhide all ")) {
                // skip the ending plural 's'
                String type = command.substring(11, command.length() - 1);
                type = type.substring(0, 1).toUpperCase() + type.substring(1);
                updateCheckboxes(layer.getParent().setVisible(type, true, true), DisplayablePanel.VISIBILITY_STATE);
            } else if (command.equals("Hide deselected")) {
                hideDeselected(0 != (ActionEvent.ALT_MASK & ae.getModifiers()));
            } else if (command.equals("Hide deselected except images")) {
                hideDeselected(true);
            } else if (command.equals("Hide selected")) {
                // TODO should deselect them too? I don't think so.
                selection.setVisible(false);
                Display.updateCheckboxes(selection.getSelected(), DisplayablePanel.VISIBILITY_STATE);
            } else if (command.equals("Resize canvas/LayerSet...")) {
                resizeCanvas();
            } else if (command.equals("Autoresize canvas/LayerSet")) {
                layer.getParent().setMinimumDimensions();
            } else if (command.equals("Resize canvas/LayerSet to ROI")) {
                final Roi roi = canvas.getFakeImagePlus().getRoi();
                if (null == roi) {
                    Utils.log("No ROI present!");
                    return;
                }
                resizeCanvas(roi.getBounds());
            } else if (command.equals("Import image")) {
                importImage();
            } else if (command.equals("Import next image")) {
                importNextImage();
            } else if (command.equals("Import stack...")) {
                Display.this.getLayerSet().addChangeTreesStep();
                final Rectangle sr = getCanvas().getSrcRect();
                final Bureaucrat burro = project.getLoader().importStack(layer, sr.x + sr.width / 2, sr.y + sr.height / 2, null, true, null, false);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        Display.this.getLayerSet().addChangeTreesStep();
                    }
                });
            } else if (command.equals("Import stack with landmarks...")) {
                // 1 - Find out if there's any other project open
                final List<Project> pr = Project.getProjects();
                if (1 == pr.size()) {
                    Utils.logAll("Need another project open!");
                    return;
                }
                // 2 - Ask for a "landmarks" type
                final GenericDialog gd = new GenericDialog("Landmarks");
                gd.addStringField("landmarks type:", "landmarks");
                final String[] none = { "-- None --" };
                final Hashtable<String, Project> mpr = new Hashtable<String, Project>();
                for (final Project p : pr) {
                    if (p == project)
                        continue;
                    mpr.put(p.toString(), p);
                }
                final String[] project_titles = mpr.keySet().toArray(new String[0]);
                final Hashtable<String, ProjectThing> map_target = findLandmarkNodes(project, "landmarks");
                final String[] target_landmark_titles = map_target.isEmpty() ? none : map_target.keySet().toArray(new String[0]);
                gd.addChoice("Landmarks node in this project:", target_landmark_titles, target_landmark_titles[0]);
                gd.addMessage("");
                gd.addChoice("Source project:", project_titles, project_titles[0]);
                final Hashtable<String, ProjectThing> map_source = findLandmarkNodes(mpr.get(project_titles[0]), "landmarks");
                final String[] source_landmark_titles = map_source.isEmpty() ? none : map_source.keySet().toArray(new String[0]);
                gd.addChoice("Landmarks node in source project:", source_landmark_titles, source_landmark_titles[0]);
                final List<Patch> stacks = Display.getPatchStacks(mpr.get(project_titles[0]).getRootLayerSet());
                String[] stack_titles;
                if (stacks.isEmpty()) {
                    if (1 == mpr.size()) {
                        IJ.showMessage("Project " + project_titles[0] + " does not contain any Stack.");
                        return;
                    }
                    stack_titles = none;
                } else {
                    stack_titles = new String[stacks.size()];
                    int next = 0;
                    for (final Patch pa : stacks) stack_titles[next++] = pa.toString();
                }
                gd.addChoice("Stacks:", stack_titles, stack_titles[0]);
                final Vector<?> vc = gd.getChoices();
                final Choice choice_target_landmarks = (Choice) vc.get(0);
                final Choice choice_source_projects = (Choice) vc.get(1);
                final Choice choice_source_landmarks = (Choice) vc.get(2);
                final Choice choice_stacks = (Choice) vc.get(3);
                final TextField input = (TextField) gd.getStringFields().get(0);
                input.addTextListener(new TextListener() {

                    @Override
                    public void textValueChanged(final TextEvent te) {
                        final String text = input.getText();
                        update(choice_target_landmarks, Display.this.project, text, map_target);
                        update(choice_source_landmarks, mpr.get(choice_source_projects.getSelectedItem()), text, map_source);
                    }

                    private void update(final Choice c, final Project p, final String type, final Hashtable<String, ProjectThing> table) {
                        table.clear();
                        table.putAll(findLandmarkNodes(p, type));
                        c.removeAll();
                        if (table.isEmpty())
                            c.add(none[0]);
                        else
                            for (final String t : table.keySet()) c.add(t);
                    }
                });
                choice_source_projects.addItemListener(new ItemListener() {

                    @Override
                    public void itemStateChanged(final ItemEvent e) {
                        final String item = (String) e.getItem();
                        final Project p = mpr.get(choice_source_projects.getSelectedItem());
                        // 1 - Update choice of landmark items
                        map_source.clear();
                        map_source.putAll(findLandmarkNodes(p, input.getText()));
                        choice_target_landmarks.removeAll();
                        if (map_source.isEmpty())
                            choice_target_landmarks.add(none[0]);
                        else
                            for (final String t : map_source.keySet()) choice_target_landmarks.add(t);
                        // 2 - Update choice of Stack items
                        stacks.clear();
                        choice_stacks.removeAll();
                        stacks.addAll(Display.getPatchStacks(mpr.get(project_titles[0]).getRootLayerSet()));
                        if (stacks.isEmpty())
                            choice_stacks.add(none[0]);
                        else
                            for (final Patch pa : stacks) choice_stacks.add(pa.toString());
                    }
                });
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final String type = gd.getNextString();
                if (null == type || 0 == type.trim().length()) {
                    Utils.log("Invalid landmarks node type!");
                    return;
                }
                final ProjectThing target_landmarks_node = map_target.get(gd.getNextChoice());
                final Project source = mpr.get(gd.getNextChoice());
                final ProjectThing source_landmarks_node = map_source.get(gd.getNextChoice());
                final Patch stack_patch = stacks.get(gd.getNextChoiceIndex());
                // Store current state
                Display.this.getLayerSet().addLayerContentStep(layer);
                // Insert stack
                insertStack(target_landmarks_node, source, source_landmarks_node, stack_patch);
                // Store new state
                Display.this.getLayerSet().addChangeTreesStep();
            } else if (command.equals("Import grid...")) {
                Display.this.getLayerSet().addLayerContentStep(layer);
                final Bureaucrat burro = project.getLoader().importGrid(layer);
                if (null != burro)
                    burro.addPostTask(new Runnable() {

                        @Override
                        public void run() {
                            Display.this.getLayerSet().addLayerContentStep(layer);
                        }
                    });
            } else if (command.equals("Import sequence as grid...")) {
                Display.this.getLayerSet().addChangeTreesStep();
                final Bureaucrat burro = project.getLoader().importSequenceAsGrid(layer);
                if (null != burro)
                    burro.addPostTask(new Runnable() {

                        @Override
                        public void run() {
                            Display.this.getLayerSet().addChangeTreesStep();
                        }
                    });
            } else if (command.equals("Import from text file...")) {
                Display.this.getLayerSet().addChangeTreesStep();
                final Bureaucrat burro = project.getLoader().importImages(layer);
                if (null != burro)
                    burro.addPostTask(new Runnable() {

                        @Override
                        public void run() {
                            Display.this.getLayerSet().addChangeTreesStep();
                        }
                    });
            } else if (command.equals("Import labels as arealists...")) {
                Display.this.getLayerSet().addChangeTreesStep();
                final Bureaucrat burro = project.getLoader().importLabelsAsAreaLists(layer, null, Double.MAX_VALUE, 0, 0.4f, false);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        Display.this.getLayerSet().addChangeTreesStep();
                    }
                });
            } else if (command.equals("Make flat image...")) {
                // if there's a ROI, just use that as cropping rectangle
                Rectangle srcRect = null;
                final Roi roi = canvas.getFakeImagePlus().getRoi();
                if (null != roi) {
                    srcRect = roi.getBounds();
                } else {
                    // otherwise, whatever is visible
                    // srcRect = canvas.getSrcRect();
                    // The above is confusing. That is what ROIs are for. So paint all:
                    srcRect = new Rectangle(0, 0, (int) Math.ceil(layer.getParent().getLayerWidth()), (int) Math.ceil(layer.getParent().getLayerHeight()));
                }
                double scale = 1.0;
                final String[] types = new String[] { "8-bit grayscale", "RGB Color" };
                int the_type = ImagePlus.GRAY8;
                final GenericDialog gd = new GenericDialog("Choose", frame);
                gd.addSlider("Scale: ", 1, 100, 100);
                gd.addNumericField("Width: ", srcRect.width, 0);
                gd.addNumericField("height: ", srcRect.height, 0);
                // connect the above 3 fields:
                final Vector<?> numfields = gd.getNumericFields();
                final UpdateDimensionField udf = new UpdateDimensionField(srcRect.width, srcRect.height, (TextField) numfields.get(1), (TextField) numfields.get(2), (TextField) numfields.get(0), (Scrollbar) gd.getSliders().get(0));
                for (final Object ob : numfields) ((TextField) ob).addTextListener(udf);
                gd.addChoice("Type: ", types, types[0]);
                if (layer.getParent().size() > 1) {
                    // / $#%! where are my lisp macros
                    Utils.addLayerRangeChoices(Display.this.layer, gd);
                    gd.addCheckbox("Include non-empty layers only", true);
                }
                gd.addMessage("Background color:");
                Utils.addRGBColorSliders(gd, Color.black);
                gd.addCheckbox("Best quality", false);
                gd.addMessage("");
                final String[] choices = new String[] { "Show", "Save to file", "Save for web (CATMAID)" };
                gd.addChoice("Export:", choices, choices[0]);
                final String[] formats = Saver.formats();
                gd.addChoice("Format:", formats, formats[0]);
                gd.addNumericField("Tile_side", 256, 0);
                final Choice cformats = (Choice) gd.getChoices().get(gd.getChoices().size() - 1);
                cformats.setEnabled(false);
                final Choice cchoices = (Choice) gd.getChoices().get(gd.getChoices().size() - 2);
                final TextField tf = (TextField) gd.getNumericFields().get(gd.getNumericFields().size() - 1);
                tf.setEnabled(false);
                cchoices.addItemListener(new ItemListener() {

                    @Override
                    public void itemStateChanged(final ItemEvent e) {
                        cformats.setEnabled(cchoices.getSelectedIndex() > 0);
                        if (2 == cchoices.getSelectedIndex()) {
                            cformats.select(".jpg");
                            tf.setEnabled(true);
                        } else {
                            tf.setEnabled(false);
                        }
                    }
                });
                gd.addCheckbox("Use original images", true);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                scale = gd.getNextNumber() / 100;
                the_type = (0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB);
                if (Double.isNaN(scale) || scale <= 0.0) {
                    Utils.showMessage("Invalid scale.");
                    return;
                }
                // consuming and ignoring width and height:
                gd.getNextNumber();
                gd.getNextNumber();
                Layer[] layer_array = null;
                boolean non_empty_only = false;
                if (layer.getParent().size() > 1) {
                    non_empty_only = gd.getNextBoolean();
                    final int i_start = gd.getNextChoiceIndex();
                    final int i_end = gd.getNextChoiceIndex();
                    final ArrayList<Layer> al = new ArrayList<Layer>();
                    final ArrayList<ZDisplayable> al_zd = layer.getParent().getZDisplayables();
                    final ZDisplayable[] zd = new ZDisplayable[al_zd.size()];
                    al_zd.toArray(zd);
                    for (int i = i_start, j = 0; i <= i_end; i++, j++) {
                        final Layer la = layer.getParent().getLayer(i);
                        // checks both the Layer and the ZDisplayable objects in the parent LayerSet
                        if (!la.isEmpty() || !non_empty_only)
                            al.add(la);
                    }
                    if (0 == al.size()) {
                        Utils.showMessage("All layers are empty!");
                        return;
                    }
                    layer_array = new Layer[al.size()];
                    al.toArray(layer_array);
                } else {
                    layer_array = new Layer[] { Display.this.layer };
                }
                final Color background = new Color((int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
                final boolean quality = gd.getNextBoolean();
                final int choice = gd.getNextChoiceIndex();
                final boolean save_to_file = 1 == choice;
                final boolean save_for_web = 2 == choice;
                final String format = gd.getNextChoice();
                final Saver saver = new Saver(format);
                final int tile_side = (int) gd.getNextNumber();
                final boolean use_original_images = gd.getNextBoolean();
                // in its own thread
                if (save_for_web)
                    project.getLoader().makePrescaledTiles(layer_array, Patch.class, srcRect, scale, c_alphas, the_type, null, use_original_images, saver, tile_side);
                else
                    project.getLoader().makeFlatImage(layer_array, srcRect, scale, c_alphas, the_type, save_to_file, format, quality, background);
            } else if (command.equals("Lock")) {
                selection.setLocked(true);
                Utils.revalidateComponent(tabs.getSelectedComponent());
            } else if (command.equals("Unlock")) {
                selection.setLocked(false);
                Utils.revalidateComponent(tabs.getSelectedComponent());
            } else if (command.equals("Properties...")) {
                switch(selection.getSelected().size()) {
                    case 0:
                        return;
                    case 1:
                        active.adjustProperties();
                        break;
                    default:
                        adjustGroupProperties(selection.getSelected());
                        break;
                }
                updateSelection();
            } else if (command.equals("Measurement options...")) {
                adjustMeasurementOptions();
            } else if (command.equals("Show current 2D position in 3D")) {
                final Point p = canvas.consumeLastPopupPoint();
                if (null == p)
                    return;
                Display3D.addFatPoint("Current 2D Position", getLayerSet(), p.x, p.y, layer.getZ(), 10, Color.magenta);
            } else if (command.equals("Show layers as orthoslices in 3D")) {
                final GenericDialog gd = new GenericDialog("Options");
                final Roi roi = canvas.getFakeImagePlus().getRoi();
                final Rectangle r = null == roi ? getLayerSet().get2DBounds() : roi.getBounds();
                gd.addMessage("ROI 2D bounds:");
                gd.addNumericField("x:", r.x, 0, 30, "pixels");
                gd.addNumericField("y:", r.y, 0, 30, "pixels");
                gd.addNumericField("width:", r.width, 0, 30, "pixels");
                gd.addNumericField("height:", r.height, 0, 30, "pixels");
                gd.addMessage("Layers to include:");
                Utils.addLayerRangeChoices(layer, gd);
                gd.addMessage("Constrain dimensions to:");
                gd.addNumericField("max width and height:", getLayerSet().getPixelsMaxDimension(), 0, 30, "pixels");
                gd.addMessage("Options:");
                final String[] types = { "Greyscale", "Color RGB" };
                gd.addChoice("Image type:", types, types[0]);
                gd.addCheckbox("Invert images", false);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final int x = (int) gd.getNextNumber(), y = (int) gd.getNextNumber(), width = (int) gd.getNextNumber(), height = (int) gd.getNextNumber();
                final int first = gd.getNextChoiceIndex(), last = gd.getNextChoiceIndex();
                final List<Layer> layers = getLayerSet().getLayers(first, last);
                final int max_dim = Math.min((int) gd.getNextNumber(), Math.max(width, height));
                float scale = 1;
                if (max_dim < Math.max(width, height)) {
                    scale = max_dim / (float) Math.max(width, height);
                }
                final int type = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB;
                final boolean invert = gd.getNextBoolean();
                final LayerStack stack = new LayerStack(layers, new Rectangle(x, y, width, height), scale, type, Patch.class, max_dim, invert);
                Display3D.showOrthoslices(stack.getImagePlus(), "LayerSet [" + x + "," + y + "," + width + "," + height + "] " + first + "--" + last, x, y, scale, layers.get(0));
            } else if (command.equals("Align stack slices")) {
                if (getActive() instanceof Patch) {
                    final Patch slice = (Patch) getActive();
                    if (slice.isStack()) {
                        // check linked group
                        final HashSet hs = slice.getLinkedGroup(new HashSet());
                        for (final Iterator it = hs.iterator(); it.hasNext(); ) {
                            if (it.next().getClass() != Patch.class) {
                                // labels should be fine, need to check that
                                Utils.showMessage("Images are linked to other objects, can't proceed to cross-correlate them.");
                                return;
                            }
                        }
                        final LayerSet ls = slice.getLayerSet();
                        final HashSet<Displayable> linked = slice.getLinkedGroup(null);
                        ls.addTransformStepWithData(linked);
                        // will repaint
                        final Bureaucrat burro = AlignTask.registerStackSlices((Patch) getActive());
                        burro.addPostTask(new Runnable() {

                            @Override
                            public void run() {
                                ls.enlargeToFit(linked);
                                // The current state when done
                                ls.addTransformStepWithData(linked);
                            }
                        });
                    } else {
                        Utils.log("Align stack slices: selected image is not part of a stack.");
                    }
                }
            } else if (command.equals("Align layers manually with landmarks")) {
                setMode(new ManualAlignMode(Display.this));
            } else if (command.equals("Align layers")) {
                Roi roi = canvas.getFakeImagePlus().getRoi();
                if (null != roi) {
                    final YesNoCancelDialog yn = new YesNoCancelDialog(frame, "Use ROI?", "Snapshot layers using the ROI bounds?\n" + roi.getBounds());
                    if (yn.cancelPressed())
                        return;
                    if (!yn.yesPressed()) {
                        roi = null;
                    }
                }
                // caching, since scroll wheel may change it
                final Layer la = layer;
                la.getParent().addTransformStep(la.getParent().getLayers());
                final Bureaucrat burro = AlignLayersTask.alignLayersTask(la, null == roi ? null : roi.getBounds());
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().enlargeToFit(getLayerSet().getDisplayables(Patch.class));
                        la.getParent().addTransformStep(la.getParent().getLayers());
                    }
                });
            } else if (command.equals("Align multi-layer mosaic")) {
                // caching, since scroll wheel may change it
                final Layer la = layer;
                la.getParent().addTransformStep();
                final Bureaucrat burro = AlignTask.alignMultiLayerMosaicTask(la, active instanceof Patch ? (Patch) active : null);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().enlargeToFit(getLayerSet().getDisplayables(Patch.class));
                        la.getParent().addTransformStep();
                    }
                });
            } else if (command.equals("Montage all images in this layer")) {
                final Layer la = layer;
                final List<Patch> patches = new ArrayList<Patch>((List<Patch>) (List) la.getDisplayables(Patch.class, true));
                if (patches.size() < 2) {
                    Utils.showMessage("Montage needs 2 or more visible images");
                    return;
                }
                final Collection<Displayable> col = la.getParent().addTransformStepWithDataForAll(Arrays.asList(new Layer[] { la }));
                // find any locked or selected patches
                final HashSet<Patch> fixed = new HashSet<Patch>();
                for (final Patch p : patches) {
                    if (p.isLocked2() || selection.contains(p))
                        fixed.add(p);
                }
                if (patches.size() == fixed.size()) {
                    Utils.showMessage("Can't do", "No montage possible: all images are selected,\nand hence all are considered locked.\nSelect only one image to be used as reference, or none.");
                    return;
                }
                Utils.log("Using " + fixed.size() + " image" + (fixed.size() == 1 ? "" : "s") + " as reference.");
                final Bureaucrat burro = AlignTask.alignPatchesTask(patches, fixed);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().enlargeToFit(patches);
                        la.getParent().addTransformStepWithData(col);
                    }
                });
            } else if (command.equals("Montage selected images")) {
                final Layer la = layer;
                if (selection.getSelected(Patch.class).size() < 2) {
                    Utils.showMessage("Montage needs 2 or more images selected");
                    return;
                }
                final Collection<Displayable> col = la.getParent().addTransformStepWithDataForAll(Arrays.asList(new Layer[] { la }));
                final Bureaucrat burro = AlignTask.alignSelectionTask(selection);
                if (null == burro)
                    return;
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        la.getParent().enlargeToFit(selection.getAffected());
                        la.getParent().addTransformStepWithData(col);
                    }
                });
            } else if (command.equals("Montage multiple layers")) {
                final GenericDialog gd = new GenericDialog("Choose range");
                Utils.addLayerRangeChoices(Display.this.layer, gd);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final List<Layer> layers = getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex());
                final Collection<Displayable> col = getLayerSet().addTransformStepWithDataForAll(layers);
                final Bureaucrat burro = AlignTask.montageLayersTask(layers);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        final Collection<Displayable> ds = new ArrayList<Displayable>();
                        for (final Layer la : layers) ds.addAll(la.getDisplayables(Patch.class));
                        getLayerSet().enlargeToFit(ds);
                        getLayerSet().addTransformStepWithData(col);
                    }
                });
            } else if (command.equals("Properties ...")) {
                // NOTE the space before the dots, to distinguish from the "Properties..." command that works on Displayable objects.
                adjustProperties();
            } else if (command.equals("Adjust snapping parameters...")) {
                AlignTask.p_snap.setup("Snap");
            } else if (command.equals("Adjust fast-marching parameters...")) {
                Segmentation.fmp.setup();
            } else if (command.equals("Adjust arealist paint parameters...")) {
                AreaWrapper.PP.setup();
            } else if (command.equals("Fill ROI in alpha mask")) {
                if (active.getClass() == Patch.class) {
                    ((Patch) active).keyPressed(new KeyEvent(getCanvas(), -1, System.currentTimeMillis(), 0, KeyEvent.VK_F, 'f'));
                }
            } else if (command.equals("Fill inverse ROI in alpha mask")) {
                if (active.getClass() == Patch.class) {
                    ((Patch) active).keyPressed(new KeyEvent(getCanvas(), -1, System.currentTimeMillis(), Event.SHIFT_MASK, KeyEvent.VK_F, 'f'));
                }
            } else if (command.equals("Search...")) {
                Search.showWindow();
            } else if (command.equals("Select all")) {
                selection.selectAll();
                repaint(Display.this.layer, selection.getBox(), 0);
            } else if (command.equals("Select all visible")) {
                selection.selectAllVisible();
                repaint(Display.this.layer, selection.getBox(), 0);
            } else if (command.equals("Select all that match...")) {
                final List<Displayable> ds = find();
                selection.selectAll(ds);
                Utils.showStatus("Added " + ds.size() + " to selection.");
            } else if (command.equals("Select none")) {
                final Rectangle box = selection.getBox();
                selection.clear();
                repaint(Display.this.layer, box, 0);
            } else if (command.equals("Restore selection")) {
                selection.restore();
            } else if (command.equals("Select under ROI")) {
                final Roi roi = canvas.getFakeImagePlus().getRoi();
                if (null == roi)
                    return;
                selection.selectAll(roi, true);
            } else if (command.equals("Merge") || command.equals("Split")) {
                final Bureaucrat burro = Bureaucrat.create(new Worker.Task(command + "ing AreaLists") {

                    @Override
                    public void exec() {
                        final ArrayList<Displayable> al_sel = selection.getSelected(AreaList.class);
                        // put active at the beginning, to work as the base on which other's will get merged
                        al_sel.remove(Display.this.active);
                        al_sel.add(0, Display.this.active);
                        final Set<DoStep> dataedits = new HashSet<DoStep>();
                        if (command.equals("Merge")) {
                            // Add data undo for active only, which will be edited
                            dataedits.add(new Displayable.DoEdit(Display.this.active).init(Display.this.active, new String[] { "data" }));
                            getLayerSet().addChangeTreesStep(dataedits);
                            final AreaList ali = AreaList.merge(al_sel);
                            if (null != ali) {
                                // remove all but the first from the selection
                                for (int i = 1; i < al_sel.size(); i++) {
                                    final Object ob = al_sel.get(i);
                                    if (ob.getClass() == AreaList.class) {
                                        selection.remove((Displayable) ob);
                                    }
                                }
                                selection.updateTransform(ali);
                                repaint(ali.getLayerSet(), ali, 0);
                            }
                        } else if (command.equals("Split")) {
                            // Add data undo for every AreaList
                            for (final Displayable d : al_sel) {
                                if (d.getClass() != AreaList.class)
                                    continue;
                                dataedits.add(new Displayable.DoEdit(d).init(d, new String[] { "data" }));
                            }
                            getLayerSet().addChangeTreesStep(dataedits);
                            try {
                                List<AreaList> alis = AreaList.split(al_sel);
                                for (AreaList ali : alis) {
                                    if (selection.contains(ali))
                                        continue;
                                    selection.add(ali);
                                }
                            } catch (Exception e) {
                                IJError.print(e);
                                getLayerSet().undoOneStep();
                            }
                        }
                    }
                }, Display.this.project);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        final Set<DoStep> dataedits = new HashSet<DoStep>();
                        dataedits.add(new Displayable.DoEdit(Display.this.active).init(Display.this.active, new String[] { "data" }));
                        getLayerSet().addChangeTreesStep(dataedits);
                    }
                });
                burro.goHaveBreakfast();
            } else if (command.equals("Reroot")) {
                if (!(active instanceof Tree<?>))
                    return;
                getLayerSet().addDataEditStep(active);
                if (((Tree) active).reRoot(((Tree) active).getLastVisited())) {
                    getLayerSet().addDataEditStep(active);
                    Display.repaint(getLayerSet());
                } else {
                    getLayerSet().removeLastUndoStep();
                }
            } else if (command.equals("Part subtree")) {
                if (!(active instanceof Tree<?>))
                    return;
                if (!Utils.check("Really part the subtree?"))
                    return;
                final LayerSet.DoChangeTrees step = getLayerSet().addChangeTreesStep();
                final Set<DoStep> deps = new HashSet<DoStep>();
                // I hate java
                deps.add(new Displayable.DoEdit(active).init(active, new String[] { "data" }));
                step.addDependents(deps);
                final List<ZDisplayable> ts = ((Tree) active).splitAt(((Tree) active).getLastVisited());
                if (null == ts) {
                    getLayerSet().removeLastUndoStep();
                    return;
                }
                final Displayable elder = Display.this.active;
                final HashSet<DoStep> deps2 = new HashSet<DoStep>();
                for (final ZDisplayable t : ts) {
                    deps2.add(new Displayable.DoEdit(t).init(t, new String[] { "data" }));
                    if (t == elder)
                        continue;
                    // will change Display.this.active !
                    getLayerSet().add(t);
                    project.getProjectTree().addSibling(elder, t);
                }
                selection.clear();
                selection.selectAll(ts);
                selection.add(elder);
                final LayerSet.DoChangeTrees step2 = getLayerSet().addChangeTreesStep();
                step2.addDependents(deps2);
                Display.repaint(getLayerSet());
            } else if (command.equals("Show tabular view")) {
                if (!(active instanceof Tree<?>))
                    return;
                ((Tree<?>) active).createMultiTableView();
            } else if (command.equals("Mark")) {
                if (!(active instanceof Tree<?>))
                    return;
                final Point p = canvas.consumeLastPopupPoint();
                if (null == p)
                    return;
                if (((Tree<?>) active).markNear(p.x, p.y, layer, canvas.getMagnification())) {
                    Display.repaint(getLayerSet());
                }
            } else if (command.equals("Clear marks (selected Trees)")) {
                for (final Tree<?> t : selection.get(Tree.class)) {
                    t.unmark();
                }
                Display.repaint(getLayerSet());
            } else if (command.equals("Join")) {
                if (!(active instanceof Tree<?>))
                    return;
                final List<Tree<?>> tlines = (List<Tree<?>>) selection.get(active.getClass());
                if (((Tree) active).canJoin(tlines)) {
                    final int nNodes_active = ((Tree) active).getRoot().getSubtreeNodes().size();
                    String warning = "";
                    for (final Tree<?> t : tlines) {
                        if (active == t)
                            continue;
                        if (null == t.getRoot()) {
                            Utils.log("Removed empty tree #" + t.getId() + " from those to join.");
                            tlines.remove(t);
                            continue;
                        }
                        if (t.getRoot().getSubtreeNodes().size() > nNodes_active) {
                            warning = "\nWARNING joining into a tree that is not the largest!";
                            break;
                        }
                    }
                    if (!Utils.check("Join these " + tlines.size() + " trees into the tree " + active + " ?" + warning))
                        return;
                    // Record current state
                    final Set<DoStep> dataedits = new HashSet<DoStep>(tlines.size());
                    for (final Tree<?> tl : tlines) {
                        dataedits.add(new Displayable.DoEdit(tl).init(tl, new String[] { "data" }));
                    }
                    getLayerSet().addChangeTreesStep(dataedits);
                    // 
                    ((Tree) active).join(tlines);
                    for (final Tree<?> tl : tlines) {
                        if (tl == active)
                            continue;
                        tl.remove2(false);
                    }
                    Display.repaint(getLayerSet());
                    // Again, to record current state (just the joined tree this time)
                    final Set<DoStep> dataedits2 = new HashSet<DoStep>(1);
                    dataedits2.add(new Displayable.DoEdit(active).init(active, new String[] { "data" }));
                    getLayerSet().addChangeTreesStep(dataedits2);
                } else {
                    Utils.showMessage("Can't do", "Only one tree is selected.\nSelect more than one tree to perform a join operation!");
                }
            } else if (command.equals("Previous branch node or start")) {
                if (!(active instanceof Tree<?>))
                    return;
                final Point p = canvas.consumeLastPopupPoint();
                if (null == p)
                    return;
                center(((Treeline) active).findPreviousBranchOrRootPoint(p.x, p.y, layer, canvas));
            } else if (command.equals("Next branch node or end")) {
                if (!(active instanceof Tree<?>))
                    return;
                final Point p = canvas.consumeLastPopupPoint();
                if (null == p)
                    return;
                center(((Tree<?>) active).findNextBranchOrEndPoint(p.x, p.y, layer, canvas));
            } else if (command.equals("Root")) {
                if (!(active instanceof Tree<?>))
                    return;
                final Point p = canvas.consumeLastPopupPoint();
                if (null == p)
                    return;
                center(((Tree) active).createCoordinate(((Tree<?>) active).getRoot()));
            } else if (command.equals("Last added node")) {
                if (!(active instanceof Tree<?>))
                    return;
                center(((Treeline) active).getLastAdded());
            } else if (command.equals("Last edited node")) {
                if (!(active instanceof Tree<?>))
                    return;
                center(((Treeline) active).getLastEdited());
            } else if (command.equals("Reverse point order")) {
                if (!(active instanceof Pipe))
                    return;
                getLayerSet().addDataEditStep(active);
                ((Pipe) active).reverse();
                Display.repaint(Display.this.layer);
                getLayerSet().addDataEditStep(active);
            } else if (command.equals("View orthoslices")) {
                if (!(active instanceof Patch))
                    return;
                Display3D.showOrthoslices(((Patch) active));
            } else if (command.equals("View volume")) {
                if (!(active instanceof Patch))
                    return;
                Display3D.showVolume(((Patch) active));
            } else if (command.equals("Show in 3D")) {
                for (final ZDisplayable zd : selection.get(ZDisplayable.class)) {
                    Display3D.show(zd.getProject().findProjectThing(zd));
                }
                // handle profile lists ...
                final HashSet<ProjectThing> hs = new HashSet<ProjectThing>();
                for (final Profile d : selection.get(Profile.class)) {
                    final ProjectThing profile_list = (ProjectThing) d.getProject().findProjectThing(d).getParent();
                    if (!hs.contains(profile_list)) {
                        Display3D.show(profile_list);
                        hs.add(profile_list);
                    }
                }
            } else if (command.equals("Snap")) {
                // Take the active if it's a Patch
                if (!(active instanceof Patch))
                    return;
                Display.snap((Patch) active);
            } else if (command.equals("Blend") || command.equals("Blend (selected images)...")) {
                final HashSet<Patch> patches = new HashSet<Patch>(selection.get(Patch.class));
                if (patches.size() > 1) {
                    final GenericDialog gd = new GenericDialog("Blending");
                    gd.addCheckbox("Respect current alpha mask", true);
                    gd.showDialog();
                    if (gd.wasCanceled())
                        return;
                    Blending.blend(patches, gd.getNextBoolean());
                } else {
                    IJ.log("Please select more than one overlapping image.");
                }
            } else if (command.equals("Blend (layer-wise)...")) {
                final GenericDialog gd = new GenericDialog("Blending");
                Utils.addLayerRangeChoices(Display.this.layer, gd);
                gd.addCheckbox("Respect current alpha mask", true);
                gd.addMessage("Filter:");
                gd.addStringField("Use only images whose title matches:", "", 30);
                gd.addCheckbox("Blend visible patches only", true);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final boolean respect_alpha_mask = gd.getNextBoolean();
                final String toMatch = gd.getNextString().trim();
                final String regex = 0 == toMatch.length() ? null : ".*" + toMatch + ".*";
                final boolean visible_only = gd.getNextBoolean();
                Blending.blendLayerWise(getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex()), respect_alpha_mask, new Filter<Patch>() {

                    @Override
                    public final boolean accept(final Patch patch) {
                        if (visible_only && !patch.isVisible())
                            return false;
                        if (null == regex)
                            return true;
                        return patch.getTitle().matches(regex);
                    }
                });
            } else if (command.equals("Match intensities (layer-wise)...")) {
                Bureaucrat.createAndStart(new Worker.Task("Match intensities") {

                    @Override
                    public void exec() {
                        final MatchIntensities matching = new MatchIntensities();
                        matching.invoke(getActive());
                    }
                }, project);
            } else if (command.equals("Remove intensity maps (layer-wise)...")) {
                final GenericDialog gd = new GenericDialog("Remove intensity maps");
                Utils.addLayerRangeChoices(Display.this.layer, gd);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                Bureaucrat.createAndStart(new Worker.Task("Match intensities") {

                    @Override
                    public void exec() {
                        for (final Layer layer : getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex())) {
                            for (final Displayable p : layer.getDisplayables(Patch.class)) {
                                final Patch patch = (Patch) p;
                                if (patch.clearIntensityMap()) {
                                    patch.updateMipMaps();
                                }
                            }
                        }
                    }
                }, project);
            } else if (command.equals("Montage")) {
                final Set<Displayable> affected = new HashSet<Displayable>(selection.getAffected());
                // make an undo step!
                final LayerSet ls = layer.getParent();
                ls.addTransformStepWithData(affected);
                final Bureaucrat burro = AlignTask.alignSelectionTask(selection);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        ls.enlargeToFit(affected);
                        ls.addTransformStepWithData(affected);
                    }
                });
            } else if (command.equals("Lens correction")) {
                final Layer la = layer;
                la.getParent().addDataEditStep(new HashSet<Displayable>(la.getParent().getDisplayables()));
                final Bureaucrat burro = DistortionCorrectionTask.correctDistortionFromSelection(selection);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        // no means to know which where modified and from which layers!
                        la.getParent().addDataEditStep(new HashSet<Displayable>(la.getParent().getDisplayables()));
                    }
                });
            } else if (command.equals("Link images...")) {
                final GenericDialog gd = new GenericDialog("Options");
                gd.addMessage("Linking images to images (within their own layer only):");
                final String[] options = { "all images to all images", "each image with any other overlapping image" };
                gd.addChoice("Link: ", options, options[1]);
                final String[] options2 = { "selected images only", "all images in this layer", "all images in all layers, within the layer only", "all images in all layers, within and across consecutive layers" };
                gd.addChoice("Apply to: ", options2, options2[0]);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final Layer lay = layer;
                final HashSet<Displayable> ds = new HashSet<Displayable>(lay.getParent().getDisplayables());
                lay.getParent().addDataEditStep(ds, new String[] { "data" });
                final boolean overlapping_only = 1 == gd.getNextChoiceIndex();
                Collection<Displayable> coll = null;
                switch(gd.getNextChoiceIndex()) {
                    case 0:
                        coll = selection.getSelected(Patch.class);
                        Patch.crosslink(coll, overlapping_only);
                        break;
                    case 1:
                        coll = lay.getDisplayables(Patch.class);
                        Patch.crosslink(coll, overlapping_only);
                        break;
                    case 2:
                        coll = new ArrayList<Displayable>();
                        for (final Layer la : lay.getParent().getLayers()) {
                            final Collection<Displayable> acoll = la.getDisplayables(Patch.class);
                            Patch.crosslink(acoll, overlapping_only);
                            coll.addAll(acoll);
                        }
                        break;
                    case 3:
                        final ArrayList<Layer> layers = lay.getParent().getLayers();
                        Collection<Displayable> lc1 = layers.get(0).getDisplayables(Patch.class);
                        if (lay == layers.get(0))
                            coll = lc1;
                        for (int i = 1; i < layers.size(); i++) {
                            final Collection<Displayable> lc2 = layers.get(i).getDisplayables(Patch.class);
                            if (null == coll && Display.this.layer == layers.get(i))
                                coll = lc2;
                            final Collection<Displayable> both = new ArrayList<Displayable>();
                            both.addAll(lc1);
                            both.addAll(lc2);
                            Patch.crosslink(both, overlapping_only);
                            lc1 = lc2;
                        }
                        break;
                }
                if (null != coll)
                    Display.updateCheckboxes(coll, DisplayablePanel.LINK_STATE, true);
                lay.getParent().addDataEditStep(ds);
            } else if (command.equals("Unlink all selected images")) {
                if (Utils.check("Really unlink selected images?")) {
                    final Collection<Displayable> ds = selection.getSelected(Patch.class);
                    for (final Displayable d : ds) {
                        d.unlink();
                    }
                    Display.updateCheckboxes(ds, DisplayablePanel.LINK_STATE);
                }
            } else if (command.equals("Unlink all")) {
                if (Utils.check("Really unlink all objects from all layers?")) {
                    final Collection<Displayable> ds = layer.getParent().getDisplayables();
                    for (final Displayable d : ds) {
                        d.unlink();
                    }
                    Display.updateCheckboxes(ds, DisplayablePanel.LINK_STATE);
                }
            } else if (command.equals("Calibration...")) {
                try {
                    IJ.run(canvas.getFakeImagePlus(), "Properties...", "");
                    Display.updateTitle(getLayerSet());
                    // repaint layer names
                    project.getLayerTree().updateUILater();
                } catch (final RuntimeException re) {
                    Utils.log2("Calibration dialog canceled.");
                }
            } else if (command.equals("Grid overlay...")) {
                if (null == gridoverlay)
                    gridoverlay = new GridOverlay();
                gridoverlay.setup(canvas.getFakeImagePlus().getRoi());
                canvas.repaint(false);
            } else if (command.equals("Enhance contrast (selected images)...")) {
                final Layer la = layer;
                final ArrayList<Displayable> selected = selection.getSelected(Patch.class);
                final HashSet<Displayable> ds = new HashSet<Displayable>(selected);
                la.getParent().addDataEditStep(ds);
                final Displayable active = Display.this.getActive();
                final Patch ref = active.getClass() == Patch.class ? (Patch) active : null;
                final Bureaucrat burro = getProject().getLoader().enhanceContrast(selected, ref);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        la.getParent().addDataEditStep(ds);
                    }
                });
            } else if (command.equals("Enhance contrast layer-wise...")) {
                // ask for range of layers
                final GenericDialog gd = new GenericDialog("Choose range");
                Utils.addLayerRangeChoices(Display.this.layer, gd);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                // exclusive end
                final java.util.List<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
                final HashSet<Displayable> ds = new HashSet<Displayable>();
                for (final Layer l : layers) ds.addAll(l.getDisplayables(Patch.class));
                getLayerSet().addDataEditStep(ds);
                final Bureaucrat burro = project.getLoader().enhanceContrast(layers);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().addDataEditStep(ds);
                    }
                });
            } else if (command.equals("Adjust image filters (selected images)")) {
                if (selection.isEmpty() || !(active instanceof Patch))
                    return;
                FilterEditor.GUI(selection.get(Patch.class), (Patch) active);
            } else if (command.equals("Set Min and Max layer-wise...")) {
                final Displayable active = getActive();
                double min = 0;
                double max = 0;
                if (null != active && active.getClass() == Patch.class) {
                    min = ((Patch) active).getMin();
                    max = ((Patch) active).getMax();
                }
                final GenericDialog gd = new GenericDialog("Min and Max");
                gd.addMessage("Set min and max to all images in the layer range");
                Utils.addLayerRangeChoices(Display.this.layer, gd);
                gd.addNumericField("min: ", min, 2);
                gd.addNumericField("max: ", max, 2);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                // 
                min = gd.getNextNumber();
                max = gd.getNextNumber();
                final ArrayList<Displayable> al = new ArrayList<Displayable>();
                for (final Layer la : layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1)) {
                    // exclusive end
                    al.addAll(la.getDisplayables(Patch.class));
                }
                final HashSet<Displayable> ds = new HashSet<Displayable>(al);
                getLayerSet().addDataEditStep(ds);
                final Bureaucrat burro = project.getLoader().setMinAndMax(al, min, max);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().addDataEditStep(ds);
                    }
                });
            } else if (command.equals("Set Min and Max (selected images)...")) {
                final Displayable active = getActive();
                double min = 0;
                double max = 0;
                if (null != active && active.getClass() == Patch.class) {
                    min = ((Patch) active).getMin();
                    max = ((Patch) active).getMax();
                }
                final GenericDialog gd = new GenericDialog("Min and Max");
                gd.addMessage("Set min and max to all selected images");
                gd.addNumericField("min: ", min, 2);
                gd.addNumericField("max: ", max, 2);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                // 
                min = gd.getNextNumber();
                max = gd.getNextNumber();
                final HashSet<Displayable> ds = new HashSet<Displayable>(selection.getSelected(Patch.class));
                getLayerSet().addDataEditStep(ds);
                final Bureaucrat burro = project.getLoader().setMinAndMax(selection.getSelected(Patch.class), min, max);
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().addDataEditStep(ds);
                    }
                });
            } else if (command.equals("Adjust min and max (selected images)...")) {
                adjustMinAndMaxGUI();
            } else if (command.equals("Mask image borders (layer-wise)...")) {
                final GenericDialog gd = new GenericDialog("Mask borders");
                Utils.addLayerRangeChoices(Display.this.layer, gd);
                gd.addMessage("Borders:");
                gd.addNumericField("left: ", 6, 2);
                gd.addNumericField("top: ", 6, 2);
                gd.addNumericField("right: ", 6, 2);
                gd.addNumericField("bottom: ", 6, 2);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final Collection<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
                final HashSet<Displayable> ds = new HashSet<Displayable>();
                for (final Layer l : layers) ds.addAll(l.getDisplayables(Patch.class));
                getLayerSet().addDataEditStep(ds);
                final Bureaucrat burro = project.getLoader().maskBordersLayerWise(layers, (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().addDataEditStep(ds);
                    }
                });
            } else if (command.equals("Mask image borders (selected images)...")) {
                final GenericDialog gd = new GenericDialog("Mask borders");
                gd.addMessage("Borders:");
                gd.addNumericField("left: ", 6, 2);
                gd.addNumericField("top: ", 6, 2);
                gd.addNumericField("right: ", 6, 2);
                gd.addNumericField("bottom: ", 6, 2);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final Collection<Displayable> patches = selection.getSelected(Patch.class);
                final HashSet<Displayable> ds = new HashSet<Displayable>(patches);
                getLayerSet().addDataEditStep(ds);
                final Bureaucrat burro = project.getLoader().maskBorders(patches, (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
                burro.addPostTask(new Runnable() {

                    @Override
                    public void run() {
                        getLayerSet().addDataEditStep(ds);
                    }
                });
            } else if (command.equals("Remove alpha masks (layer-wise)...")) {
                final GenericDialog gd = new GenericDialog("Remove alpha masks");
                Utils.addLayerRangeChoices(Display.this.layer, gd);
                gd.addCheckbox("Visible only", true);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final Collection<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
                final boolean visible_only = gd.getNextBoolean();
                final Collection<Patch> patches = new ArrayList<Patch>();
                for (final Layer l : layers) {
                    patches.addAll((Collection<Patch>) (Collection) l.getDisplayables(Patch.class, visible_only));
                }
                Display.removeAlphaMasks(patches);
            } else if (command.equals("Remove alpha masks (selected images)...")) {
                Display.removeAlphaMasks(selection.get(Patch.class));
            } else if (command.equals("Split images under polyline ROI")) {
                final Roi roi = canvas.getFakeImagePlus().getRoi();
                if (null == roi)
                    return;
                if (!(roi.getType() == Roi.POLYLINE || roi.getType() == Roi.FREELINE)) {
                    Utils.showMessage("Need a polyline or freeline ROI, not just any ROI!");
                    return;
                }
                if (!Utils.check("Really split images under the ROI?")) {
                    return;
                }
                // OK identify images whose contour intersects the ROI
                final Set<Displayable> col = new HashSet<Displayable>();
                // FreehandRoi is a subclass of PolygonRoi
                final PolygonRoi proi = (PolygonRoi) roi;
                final int[] x = proi.getXCoordinates(), y = proi.getYCoordinates();
                final Rectangle b = proi.getBounds();
                final Polygon[] pols = new Polygon[proi.getNCoordinates() - 1];
                for (int i = 0; i < pols.length; i++) {
                    pols[i] = new Polygon(new int[] { b.x + x[i], b.x + x[i] + 1, b.x + x[i + 1], b.x + x[i + 1] + 1 }, new int[] { b.y + y[i], b.y + y[i], b.y + y[i + 1], b.y + y[i + 1] }, 4);
                }
                for (final Patch p : getLayer().getAll(Patch.class)) {
                    if (!p.isVisible())
                        continue;
                    final Area a = p.getArea();
                    for (int i = 0; i < pols.length; i++) {
                        final Area c = new Area(pols[i]);
                        c.intersect(a);
                        if (M.isEmpty(c))
                            continue;
                        // Else, add it:
                        col.add(p);
                        break;
                    }
                }
                if (col.isEmpty()) {
                    Utils.showMessage("No images intersect the ROI!");
                    return;
                }
                for (int i = 1; i < proi.getNCoordinates(); i++) {
                    for (int k = i + 2; k < proi.getNCoordinates(); k++) {
                        // check if the two segments intersect
                        if (null != M.computeSegmentsIntersection(x[i - 1], y[i - 1], x[i], y[i], x[k - 1], y[k - 1], x[k], y[k])) {
                            Utils.showMessage("Cannot split images with a polygon ROI that intersects itself!");
                            return;
                        }
                    }
                }
                final Area[] as = M.splitArea(new Area(getLayerSet().get2DBounds()), proi, getLayerSet().get2DBounds());
                final Color[] c = new Color[] { Color.blue, Color.red };
                int i = 0;
                for (final Area a : as) {
                    // Utils.log2("Added overlay " + i + " with color " + c[i] + " and area " + AreaCalculations.area(a.getPathIterator(null)));
                    getLayer().getOverlay().add(a, c[i++], null, true, false, 0.4f);
                }
                Display.repaint(getLayer());
                final YesNoDialog yn = new YesNoDialog(frame, "Check", "Does the splitting match your expectations?\nPush 'yes' to split the images.", false);
                yn.setModal(false);
                for (final WindowListener wl : yn.getWindowListeners()) yn.removeWindowListener(wl);
                yn.setClosingTask(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            // Remove overlay shapes
                            for (final Area a : as) {
                                getLayer().getOverlay().remove(a);
                            }
                            if (!yn.yesPressed()) {
                                Utils.log2("Pushed 'no'");
                                return;
                            }
                            // Split intersecting patches
                            // Duplicate each intersecting patch, and assign a[0] to the original and a[1] to the copy, as mask.
                            Bureaucrat.createAndStart(new Worker.Task("Spliting images") {

                                @Override
                                public void exec() {
                                    final Roi r1 = new ShapeRoi(as[0]), r2 = new ShapeRoi(as[1]);
                                    final ArrayList<Future<?>> fus = new ArrayList<Future<?>>();
                                    for (final Patch p : (Collection<Patch>) (Collection) col) {
                                        final Patch copy = (Patch) p.clone(p.getProject(), false);
                                        p.addAlphaMask(r1, 0);
                                        copy.addAlphaMask(r2, 0);
                                        fus.add(p.updateMipMaps());
                                        fus.add(copy.updateMipMaps());
                                        // after submitting mipmaps, since it will get added to all Displays and repainted.
                                        p.getLayer().add(copy);
                                    }
                                    Utils.wait(fus);
                                }
                            }, project);
                        } catch (final Throwable t) {
                            IJError.print(t);
                        } finally {
                            yn.dispose();
                            Display.repaint(getLayer());
                        }
                    }
                });
                yn.setVisible(true);
            } else if (command.equals("Duplicate")) {
                // only Patch and DLabel, i.e. Layer-only resident objects that don't exist in the Project Tree
                final HashSet<Class> accepted = new HashSet<Class>();
                accepted.add(Patch.class);
                accepted.add(DLabel.class);
                accepted.add(Stack.class);
                final ArrayList<Displayable> originals = new ArrayList<Displayable>();
                final ArrayList<Displayable> selected = selection.getSelected();
                for (final Displayable d : selected) {
                    if (accepted.contains(d.getClass())) {
                        originals.add(d);
                    }
                }
                if (originals.size() > 0) {
                    getLayerSet().addChangeTreesStep();
                    for (final Displayable d : originals) {
                        if (d instanceof ZDisplayable) {
                            d.getLayerSet().add((ZDisplayable) d.clone());
                        } else {
                            d.getLayer().add(d.clone());
                        }
                    }
                    getLayerSet().addChangeTreesStep();
                } else if (selected.size() > 0) {
                    Utils.log("Can only duplicate images and text labels.\nDuplicate *other* objects in the Project Tree.\n");
                }
            } else if (command.equals("Create subproject")) {
                // Choose a 2D rectangle
                final Roi roi = canvas.getFakeImagePlus().getRoi();
                Rectangle bounds;
                if (null != roi) {
                    if (!Utils.check("Use bounds as defined by the ROI:\n" + roi.getBounds() + " ?"))
                        return;
                    bounds = roi.getBounds();
                } else
                    bounds = getLayerSet().get2DBounds();
                // Choose a layer range, and whether to ignore hidden images
                final GenericDialog gd = new GenericDialog("Choose layer range");
                Utils.addLayerRangeChoices(layer, gd);
                gd.addCheckbox("Ignore hidden images", true);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final Layer first = layer.getParent().getLayer(gd.getNextChoiceIndex());
                final Layer last = layer.getParent().getLayer(gd.getNextChoiceIndex());
                final boolean ignore_hidden_patches = gd.getNextBoolean();
                final Project sub = getProject().createSubproject(bounds, first, last, ignore_hidden_patches);
                if (null == sub) {
                    Utils.log("ERROR: failed to create subproject.");
                    return;
                }
                final LayerSet subls = sub.getRootLayerSet();
                Display.createDisplay(sub, subls.getLayer(0));
            } else if (command.startsWith("Image stack under selected Arealist")) {
                if (null == active || active.getClass() != AreaList.class)
                    return;
                final GenericDialog gd = new GenericDialog("Stack options");
                final String[] types = { "8-bit", "16-bit", "32-bit", "RGB" };
                gd.addChoice("type:", types, types[0]);
                gd.addSlider("Scale: ", 1, 100, 100);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final int type;
                switch(gd.getNextChoiceIndex()) {
                    case 0:
                        type = ImagePlus.GRAY8;
                        break;
                    case 1:
                        type = ImagePlus.GRAY16;
                        break;
                    case 2:
                        type = ImagePlus.GRAY32;
                        break;
                    case 3:
                        type = ImagePlus.COLOR_RGB;
                        break;
                    default:
                        type = ImagePlus.GRAY8;
                        break;
                }
                final ImagePlus imp = ((AreaList) active).getStack(type, gd.getNextNumber() / 100);
                if (null != imp)
                    imp.show();
            } else if (command.equals("Fly through selected Treeline/AreaTree")) {
                if (null == active || !(active instanceof Tree<?>))
                    return;
                Bureaucrat.createAndStart(new Worker.Task("Creating fly through", true) {

                    @Override
                    public void exec() {
                        final GenericDialog gd = new GenericDialog("Fly through");
                        gd.addNumericField("Width", 512, 0);
                        gd.addNumericField("Height", 512, 0);
                        final String[] types = new String[] { "8-bit gray", "Color RGB" };
                        gd.addChoice("Image type", types, types[0]);
                        gd.addSlider("scale", 0, 100, 100);
                        gd.addCheckbox("save to file", false);
                        gd.showDialog();
                        if (gd.wasCanceled())
                            return;
                        final int w = (int) gd.getNextNumber();
                        final int h = (int) gd.getNextNumber();
                        final int type = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB;
                        final double scale = gd.getNextNumber();
                        if (w <= 0 || h <= 0) {
                            Utils.log("Invalid width or height: " + w + ", " + h);
                            return;
                        }
                        if (0 == scale || Double.isNaN(scale)) {
                            Utils.log("Invalid scale: " + scale);
                            return;
                        }
                        String dir = null;
                        if (gd.getNextBoolean()) {
                            final DirectoryChooser dc = new DirectoryChooser("Target directory");
                            dir = dc.getDirectory();
                            // canceled
                            if (null == dir)
                                return;
                            dir = Utils.fixDir(dir);
                        }
                        final ImagePlus imp = ((Tree<?>) active).flyThroughMarked(w, h, scale / 100, type, dir);
                        if (null == imp) {
                            Utils.log("Mark a node first!");
                            return;
                        }
                        imp.show();
                    }
                }, project);
            } else if (command.startsWith("Arealists as labels")) {
                final GenericDialog gd = new GenericDialog("Export labels");
                gd.addSlider("Scale: ", 1, 100, 100);
                final String[] options = { "All area list", "Selected area lists" };
                gd.addChoice("Export: ", options, options[0]);
                Utils.addLayerRangeChoices(layer, gd);
                gd.addCheckbox("Visible only", true);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final float scale = (float) (gd.getNextNumber() / 100);
                final java.util.List<Displayable> al = (java.util.List<Displayable>) (0 == gd.getNextChoiceIndex() ? layer.getParent().getZDisplayables(AreaList.class) : selection.getSelectedSorted(AreaList.class));
                if (null == al) {
                    Utils.log("No area lists found to export.");
                    return;
                }
                // Generics are ... a pain? I don't understand them? They fail when they shouldn't? And so easy to workaround that they are a shame?
                final int first = gd.getNextChoiceIndex();
                final int last = gd.getNextChoiceIndex();
                final boolean visible_only = gd.getNextBoolean();
                if (-1 != command.indexOf("(amira)")) {
                    AreaList.exportAsLabels(al, canvas.getFakeImagePlus().getRoi(), scale, first, last, visible_only, true, true);
                } else if (-1 != command.indexOf("(tif)")) {
                    AreaList.exportAsLabels(al, canvas.getFakeImagePlus().getRoi(), scale, first, last, visible_only, false, false);
                }
            } else if (command.equals("Project properties...")) {
                project.adjustProperties();
            } else if (command.equals("Release memory...")) {
                Bureaucrat.createAndStart(new Worker("Releasing memory") {

                    @Override
                    public void run() {
                        startedWorking();
                        try {
                            final GenericDialog gd = new GenericDialog("Release Memory");
                            final int max = (int) (IJ.maxMemory() / 1000000);
                            gd.addSlider("Megabytes: ", 0, max, max / 2);
                            gd.showDialog();
                            if (!gd.wasCanceled()) {
                                final int n_mb = (int) gd.getNextNumber();
                                project.getLoader().releaseToFit((long) n_mb * 1000000);
                            }
                        } catch (final Throwable e) {
                            IJError.print(e);
                        } finally {
                            finishedWorking();
                        }
                    }
                }, project);
            } else if (command.equals("Create sibling project with retiled layers")) {
                final GenericDialog gd = new GenericDialog("Export flattened layers");
                gd.addNumericField("Tile_width", 2048, 0);
                gd.addNumericField("Tile_height", 2048, 0);
                final String[] types = new String[] { "16-bit", "RGB color" };
                gd.addChoice("Export_image_type", types, types[0]);
                gd.addCheckbox("Create mipmaps", true);
                gd.addNumericField("Number_of_threads_to_use", Runtime.getRuntime().availableProcessors(), 0);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final DirectoryChooser dc = new DirectoryChooser("Choose target folder");
                final String folder = dc.getDirectory();
                if (null == folder)
                    return;
                final int tileWidth = (int) gd.getNextNumber(), tileHeight = (int) gd.getNextNumber();
                if (tileWidth < 0 || tileHeight < 0) {
                    Utils.showMessage("Invalid tile sizes: " + tileWidth + ", " + tileHeight);
                    return;
                }
                if (tileWidth != tileHeight) {
                    if (!Utils.check("The tile width (" + tileWidth + ") differs from the tile height (" + tileHeight + ").\nContinue anyway?")) {
                        return;
                    }
                }
                final int imageType = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY16 : ImagePlus.COLOR_RGB;
                final boolean createMipMaps = gd.getNextBoolean();
                final int nThreads = (int) gd.getNextNumber();
                Bureaucrat.createAndStart(new Worker.Task("Export flattened sibling project") {

                    @Override
                    public void exec() {
                        try {
                            ProjectTiler.createRetiledSibling(project, folder, tileWidth, tileHeight, imageType, true, nThreads, createMipMaps);
                        } catch (final Throwable t) {
                            Utils.showMessage("ERROR: " + t);
                            IJError.print(t);
                        }
                    }
                }, project);
            } else if (command.equals("Flush image cache")) {
                Loader.releaseAllCaches();
            } else if (command.equals("Regenerate all mipmaps")) {
                project.getLoader().regenerateMipMaps(getLayerSet().getDisplayables(Patch.class));
            } else if (command.equals("Regenerate mipmaps (selected images)")) {
                project.getLoader().regenerateMipMaps(selection.getSelected(Patch.class));
            } else if (command.equals("Tags...")) {
                // get a file first
                final File f = Utils.chooseFile(null, "tags", ".xml");
                if (null == f)
                    return;
                if (!Utils.saveToFile(f, getLayerSet().exportTags())) {
                    Utils.logAll("ERROR when saving tags to file " + f.getAbsolutePath());
                }
            } else if (command.equals("Tags ...")) {
                final String[] ff = Utils.selectFile("Import tags");
                if (null == ff)
                    return;
                final GenericDialog gd = new GenericDialog("Import tags");
                final String[] modes = new String[] { "Append to current tags", "Replace current tags" };
                gd.addChoice("Import tags mode:", modes, modes[0]);
                gd.addMessage("Replacing current tags\nwill remove all tags\n from all nodes first!");
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                getLayerSet().importTags(new StringBuilder(ff[0]).append('/').append(ff[1]).toString(), 1 == gd.getNextChoiceIndex());
            } else if (command.equals("Connectivity graph...")) {
                Bureaucrat.createAndStart(new Worker.Task("Connectivity graph") {

                    @Override
                    public void exec() {
                        Graph.extractAndShowGraph(getLayerSet());
                    }
                }, getProject());
            } else if (command.equals("NeuroML...")) {
                final GenericDialog gd = new GenericDialog("Export NeuroML");
                final String[] a = new String[] { "NeuroML (arbors and synapses)", "MorphML (arbors)" };
                gd.addChoice("Type:", a, a[0]);
                final String[] b = new String[] { "All treelines and areatrees", "Selected treelines and areatrees" };
                gd.addChoice("Export:", b, b[0]);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                final int type = gd.getNextChoiceIndex();
                final int export = gd.getNextChoiceIndex();
                // 
                final SaveDialog sd = new SaveDialog("Choose .mml file", null, ".mml");
                final String filename = sd.getFileName();
                // canceled
                if (null == filename)
                    return;
                final File f = new File(sd.getDirectory() + filename);
                // 
                Bureaucrat.createAndStart(new Worker.Task("Export NeuroML") {

                    @Override
                    public void exec() {
                        OutputStreamWriter w = null;
                        try {
                            final Set<Tree<?>> trees = new HashSet<Tree<?>>();
                            Collection<? extends Displayable> ds = null;
                            switch(export) {
                                case 0:
                                    ds = getLayerSet().getZDisplayables();
                                    break;
                                case 1:
                                    ds = selection.getSelected();
                                    break;
                            }
                            for (final Displayable d : ds) {
                                if (d.getClass() == Treeline.class || d.getClass() == AreaTree.class) {
                                    trees.add((Tree<?>) d);
                                }
                            }
                            if (trees.isEmpty()) {
                                Utils.showMessage("No trees to export!");
                                return;
                            }
                            // 
                            // encoding in Latin 1 (for macosx not to mess around
                            w = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(f), 65536), "8859_1");
                            // 
                            switch(type) {
                                case 0:
                                    NeuroML.exportNeuroML(trees, w);
                                    break;
                                case 1:
                                    NeuroML.exportMorphML(trees, w);
                                    break;
                            }
                            // 
                            w.flush();
                            w.close();
                        // 
                        } catch (final Throwable t) {
                            IJError.print(t);
                            try {
                                if (null != w)
                                    w.close();
                            } catch (final Exception ee) {
                                IJError.print(ee);
                            }
                        }
                    }
                }, getProject());
            } else if (command.equals("Measure")) {
                if (selection.isEmpty()) {
                    Utils.log("Nothing selected to measure!");
                    return;
                }
                selection.measure();
            } else if (command.equals("Area interpolation options...")) {
                final GenericDialog gd = new GenericDialog("Area interpolation");
                final boolean a = project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map);
                gd.addCheckbox("Always use distance map method", a);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                project.setProperty(AreaUtils.always_interpolate_areas_with_distance_map, gd.getNextBoolean() ? "true" : null);
            } else {
                Utils.log2("Display: don't know what to do with command " + command);
            }
        }
    });
}
Also used : ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) Bureaucrat(ini.trakem2.utils.Bureaucrat) MatchIntensities(org.janelia.intensity.MatchIntensities) SaveDialog(ij.io.SaveDialog) Vector(java.util.Vector) TextListener(java.awt.event.TextListener) Project(ini.trakem2.Project) DBObject(ini.trakem2.persistence.DBObject) ItemEvent(java.awt.event.ItemEvent) Set(java.util.Set) HashSet(java.util.HashSet) GenericDialog(ij.gui.GenericDialog) InspectPatchTrianglesMode(ini.trakem2.display.inspect.InspectPatchTrianglesMode) Worker(ini.trakem2.utils.Worker) ProjectThing(ini.trakem2.tree.ProjectThing) TextEvent(java.awt.event.TextEvent) WindowListener(java.awt.event.WindowListener) Hashtable(java.util.Hashtable) ImagePlus(ij.ImagePlus) ItemListener(java.awt.event.ItemListener) OutputStreamWriter(java.io.OutputStreamWriter) DirectoryChooser(ij.io.DirectoryChooser) AlignTask(mpicbg.trakem2.align.AlignTask) AlignLayersTask(mpicbg.trakem2.align.AlignLayersTask) DistortionCorrectionTask(lenscorrection.DistortionCorrectionTask) Choice(java.awt.Choice) LayerStack(ini.trakem2.imaging.LayerStack) TextField(java.awt.TextField) ArrayList(java.util.ArrayList) List(java.util.List) CoordinateTransformList(mpicbg.trakem2.transform.CoordinateTransformList) Polygon(java.awt.Polygon) HashSet(java.util.HashSet) Color(java.awt.Color) PolygonRoi(ij.gui.PolygonRoi) ShapeRoi(ij.gui.ShapeRoi) Roi(ij.gui.Roi) Area(java.awt.geom.Area) FileOutputStream(java.io.FileOutputStream) Collection(java.util.Collection) File(java.io.File) Saver(ini.trakem2.utils.Saver) KeyEvent(java.awt.event.KeyEvent) PolygonRoi(ij.gui.PolygonRoi) ListIterator(java.util.ListIterator) Iterator(java.util.Iterator) YesNoCancelDialog(ij.gui.YesNoCancelDialog) BufferedOutputStream(java.io.BufferedOutputStream) ShapeRoi(ij.gui.ShapeRoi) Point(java.awt.Point) Point(java.awt.Point) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) Filter(ini.trakem2.utils.Filter) Future(java.util.concurrent.Future)

Aggregations

ImagePlus (ij.ImagePlus)1 GenericDialog (ij.gui.GenericDialog)1 PolygonRoi (ij.gui.PolygonRoi)1 Roi (ij.gui.Roi)1 ShapeRoi (ij.gui.ShapeRoi)1 YesNoCancelDialog (ij.gui.YesNoCancelDialog)1 DirectoryChooser (ij.io.DirectoryChooser)1 SaveDialog (ij.io.SaveDialog)1 Project (ini.trakem2.Project)1 InspectPatchTrianglesMode (ini.trakem2.display.inspect.InspectPatchTrianglesMode)1 LayerStack (ini.trakem2.imaging.LayerStack)1 DBObject (ini.trakem2.persistence.DBObject)1 ProjectThing (ini.trakem2.tree.ProjectThing)1 Bureaucrat (ini.trakem2.utils.Bureaucrat)1 Filter (ini.trakem2.utils.Filter)1 Saver (ini.trakem2.utils.Saver)1 Worker (ini.trakem2.utils.Worker)1 Choice (java.awt.Choice)1 Color (java.awt.Color)1 Point (java.awt.Point)1