Search in sources :

Example 1 with Ball

use of ini.trakem2.display.Ball in project TrakEM2 by trakem2.

the class Display method getPopupMenu.

/**
 * Return a context-sensitive popup menu.
 */
protected JPopupMenu getPopupMenu() {
    // get the job canceling dialog
    if (!canvas.isInputEnabled()) {
        return project.getLoader().getJobsPopup(this);
    }
    // create new
    this.popup = new JPopupMenu();
    JMenuItem item = null;
    JMenu menu = null;
    if (mode instanceof InspectPatchTrianglesMode) {
        item = new JMenuItem("Exit inspection");
        item.addActionListener(this);
        popup.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
        return popup;
    } else if (canvas.isTransforming()) {
        item = new JMenuItem("Apply transform");
        item.addActionListener(this);
        popup.add(item);
        // dummy, for I don't add a MenuKeyListener, but "works" through the normal key listener. It's here to provide a visual cue
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true));
        item = new JMenuItem("Apply transform propagating to last layer");
        item.addActionListener(this);
        popup.add(item);
        if (layer.getParent().indexOf(layer) == layer.getParent().size() - 1)
            item.setEnabled(false);
        if (!(getMode().getClass() == AffineTransformMode.class || getMode().getClass() == NonLinearTransformMode.class))
            item.setEnabled(false);
        item = new JMenuItem("Apply transform propagating to first layer");
        item.addActionListener(this);
        popup.add(item);
        if (0 == layer.getParent().indexOf(layer))
            item.setEnabled(false);
        if (!(getMode().getClass() == AffineTransformMode.class || getMode().getClass() == NonLinearTransformMode.class))
            item.setEnabled(false);
        item = new JMenuItem("Cancel transform");
        item.addActionListener(this);
        popup.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
        item = new JMenuItem("Specify transform...");
        item.addActionListener(this);
        popup.add(item);
        if (getMode().getClass() != AffineTransformMode.class)
            item.setEnabled(false);
        if (getMode().getClass() == ManualAlignMode.class) {
            final JMenuItem lexport = new JMenuItem("Export landmarks");
            popup.add(lexport);
            final JMenuItem limport = new JMenuItem("Import landmarks");
            popup.add(limport);
            final ActionListener a = new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    final ManualAlignMode mam = (ManualAlignMode) getMode();
                    final Object source = ae.getSource();
                    if (lexport == source) {
                        mam.exportLandmarks();
                    } else if (limport == source) {
                        mam.importLandmarks();
                    }
                }
            };
            lexport.addActionListener(a);
            limport.addActionListener(a);
        }
        return popup;
    }
    final Class<?> aclass = null == active ? null : active.getClass();
    if (null != active) {
        if (Profile.class == aclass) {
            item = new JMenuItem("Duplicate, link and send to next layer");
            item.addActionListener(this);
            popup.add(item);
            Layer nl = layer.getParent().next(layer);
            if (nl == layer)
                item.setEnabled(false);
            item = new JMenuItem("Duplicate, link and send to previous layer");
            item.addActionListener(this);
            popup.add(item);
            nl = layer.getParent().previous(layer);
            if (nl == layer)
                item.setEnabled(false);
            menu = new JMenu("Duplicate, link and send to");
            int i = 1;
            for (final Layer la : layer.getParent().getLayers()) {
                // TODO should label which layers contain Profile instances linked to the one being duplicated
                item = new JMenuItem(i + ": z = " + la.getZ());
                // TODO should label which layers contain Profile instances linked to the one being duplicated
                item.addActionListener(this);
                // TODO should label which layers contain Profile instances linked to the one being duplicated
                menu.add(item);
                if (la == this.layer)
                    item.setEnabled(false);
                i++;
            }
            popup.add(menu);
            item = new JMenuItem("Duplicate, link and send to...");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
            item = new JMenuItem("Unlink from images");
            item.addActionListener(this);
            popup.add(item);
            // isLinked() checks if it's linked to a Patch in its own layer
            if (!active.isLinked())
                item.setEnabled(false);
            item = new JMenuItem("Show in 3D");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
        } else if (Patch.class == aclass) {
            final JMenu m = new JMenu("Patch");
            item = new JMenuItem("Fill ROI in alpha mask");
            item.addActionListener(this);
            m.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, 0));
            item.setEnabled(null != getRoi());
            item = new JMenuItem("Fill inverse ROI in alpha mask");
            item.addActionListener(this);
            m.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.SHIFT_MASK));
            item.setEnabled(null != getRoi());
            item = new JMenuItem("Remove alpha mask");
            item.addActionListener(this);
            m.add(item);
            if (!((Patch) active).hasAlphaMask())
                item.setEnabled(false);
            item = new JMenuItem("Unlink from images");
            item.addActionListener(this);
            m.add(item);
            if (!active.isLinked(Patch.class))
                item.setEnabled(false);
            if (((Patch) active).isStack()) {
                item = new JMenuItem("Unlink slices");
                item.addActionListener(this);
                m.add(item);
            }
            final int n_sel_patches = selection.getSelected(Patch.class).size();
            item = new JMenuItem("Snap");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(1 == n_sel_patches);
            item = new JMenuItem("Montage");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(n_sel_patches > 1);
            item = new JMenuItem("Lens correction");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(n_sel_patches > 1);
            item = new JMenuItem("Blend");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(n_sel_patches > 1);
            item = new JMenuItem("Open image");
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    for (final Patch p : selection.get(Patch.class)) {
                        p.getImagePlus().show();
                    }
                }
            });
            m.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.SHIFT_MASK, true));
            item = new JMenuItem("Open original image");
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    for (final Patch p : selection.get(Patch.class)) {
                        p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 5);
                        p.getProject().getLoader().openImagePlus(p.getImageFilePath()).show();
                    }
                }
            });
            item = new JMenuItem("View volume");
            item.addActionListener(this);
            m.add(item);
            final HashSet<Displayable> hs = active.getLinked(Patch.class);
            if (null == hs || 0 == hs.size())
                item.setEnabled(false);
            item = new JMenuItem("View orthoslices");
            item.addActionListener(this);
            m.add(item);
            // if no Patch instances among the directly linked, then it's not a stack
            if (null == hs || 0 == hs.size())
                item.setEnabled(false);
            popup.add(m);
            popup.addSeparator();
        } else {
            item = new JMenuItem("Unlink");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Show in 3D");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
        }
        if (AreaList.class == aclass) {
            final ArrayList<?> al = selection.getSelected();
            int n = 0;
            for (final Iterator<?> it = al.iterator(); it.hasNext(); ) {
                if (it.next().getClass() == AreaList.class)
                    n++;
            }
            item = new JMenuItem("Merge");
            item.addActionListener(this);
            popup.add(item);
            if (n < 2)
                item.setEnabled(false);
            item = new JMenuItem("Split");
            item.addActionListener(this);
            popup.add(item);
            if (n < 1)
                item.setEnabled(false);
            addAreaListAreasMenu(popup, active);
            popup.addSeparator();
        } else if (Pipe.class == aclass) {
            item = new JMenuItem("Reverse point order");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
        } else if (Treeline.class == aclass || AreaTree.class == aclass) {
            if (AreaTree.class == aclass)
                addAreaTreeAreasMenu(popup, (AreaTree) active);
            item = new JMenuItem("Reroot");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Part subtree");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Join");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Show tabular view");
            item.addActionListener(this);
            popup.add(item);
            final Collection<Tree> trees = selection.get(Tree.class);
            // 
            final JMenu nodeMenu = new JMenu("Nodes");
            item = new JMenuItem("Mark");
            item.addActionListener(this);
            nodeMenu.add(item);
            item = new JMenuItem("Clear marks (selected Trees)");
            item.addActionListener(this);
            nodeMenu.add(item);
            final JMenuItem nodeColor = new JMenuItem("Color...");
            nodeMenu.add(nodeColor);
            nodeColor.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.SHIFT_MASK, true));
            final JMenuItem nodePairColor = new JMenuItem("Color path between two nodes tagged as...");
            nodeMenu.add(nodePairColor);
            final JMenuItem nodeRadius = active instanceof Treeline ? new JMenuItem("Radius...") : null;
            if (null != nodeRadius) {
                nodeMenu.add(nodeRadius);
                nodeRadius.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0, true));
            }
            final JMenuItem removeAllTags = new JMenuItem("Drop all tags (selected trees)");
            nodeMenu.add(removeAllTags);
            final JMenuItem removeTag = new JMenuItem("Drop all occurrences of tag...");
            nodeMenu.add(removeTag);
            final JMenuItem colorizeByNodeCentrality = new JMenuItem("Colorize by node betweenness centrality");
            nodeMenu.add(colorizeByNodeCentrality);
            final JMenuItem colorizeByBranchCentrality = new JMenuItem("Colorize by branch betweenness centrality");
            nodeMenu.add(colorizeByBranchCentrality);
            popup.add(nodeMenu);
            final ActionListener ln = new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    if (null == active) {
                        Utils.showMessage("No tree selected!");
                        return;
                    }
                    if (!(active instanceof Tree)) {
                        Utils.showMessage("The selected object is not a Tree!");
                        return;
                    }
                    final Tree tree = (Tree) active;
                    final Object src = ae.getSource();
                    // 
                    if (src == nodeColor) {
                        final Node nd = tree.getLastVisited();
                        if (null == nd) {
                            Utils.showMessage("Select a node first by clicking on it\nor moving the mouse over it and pushing 'g'.");
                            return;
                        }
                        // sets an undo step
                        tree.adjustNodeColors(nd);
                    } else if (src == nodePairColor) {
                        final TreeMap<String, Tag> sm = getTags(tree);
                        if (null == sm)
                            return;
                        if (1 == sm.size()) {
                            Utils.showMessage("Need at least two different tags in the tree!");
                            return;
                        }
                        final Color color = tree.getColor();
                        final GenericDialog gd = new GenericDialog("Node colors");
                        gd.addSlider("Red: ", 0, 255, color.getRed());
                        gd.addSlider("Green: ", 0, 255, color.getGreen());
                        gd.addSlider("Blue: ", 0, 255, color.getBlue());
                        final String[] stags = asStrings(sm);
                        sm.keySet().toArray(stags);
                        gd.addChoice("Upstream tag:", stags, stags[0]);
                        gd.addChoice("Downstream tag:", stags, stags[1]);
                        gd.showDialog();
                        if (gd.wasCanceled())
                            return;
                        final Color newColor = new Color((int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
                        final Tag upstreamTag = sm.get(gd.getNextChoice());
                        final Tag downstreamTag = sm.get(gd.getNextChoice());
                        final List<Tree<?>.NodePath> pairs = tree.findTaggedPairs(upstreamTag, downstreamTag);
                        if (null == pairs || pairs.isEmpty()) {
                            Utils.showMessage("No pairs found for '" + upstreamTag + "' and '" + downstreamTag + "'");
                            return;
                        }
                        getLayerSet().addDataEditStep(tree);
                        for (final Tree<?>.NodePath pair : pairs) {
                            for (final Node<?> nd : pair.path) {
                                nd.setColor(newColor);
                            }
                        }
                        getLayerSet().addDataEditStep(tree);
                        Display.repaint();
                    } else if (src == nodeRadius) {
                        if (!(tree instanceof Treeline))
                            return;
                        final Node nd = tree.getLastVisited();
                        if (null == nd) {
                            Utils.showMessage("Select a node first by clicking on it\nor moving the mouse over it and pushing 'g'.");
                            return;
                        }
                        // sets an undo step
                        ((Treeline) tree).askAdjustRadius(nd);
                    } else if (src == removeAllTags) {
                        if (!Utils.check("Really remove all tags from all selected trees?"))
                            return;
                        final List<Tree> sel = selection.get(Tree.class);
                        getLayerSet().addDataEditStep(new HashSet<Displayable>(sel));
                        try {
                            for (final Tree t : sel) {
                                t.dropAllTags();
                            }
                            // current state
                            getLayerSet().addDataEditStep(new HashSet<Displayable>(sel));
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                        Display.repaint();
                    } else if (src == removeTag) {
                        final TreeMap<String, Tag> tags = getTags(tree);
                        final String[] ts = asStrings(tags);
                        final GenericDialog gd = new GenericDialog("Remove tags");
                        gd.addChoice("Tag:", ts, ts[0]);
                        final String[] c = new String[] { "Active tree", "All selected trees and connectors", "All trees and connectors" };
                        gd.addChoice("From: ", c, c[0]);
                        gd.showDialog();
                        if (gd.wasCanceled())
                            return;
                        final HashSet<Displayable> ds = new HashSet<Displayable>();
                        final Tag tag = tags.get(gd.getNextChoice());
                        switch(gd.getNextChoiceIndex()) {
                            case 0:
                                ds.add(tree);
                                break;
                            case 1:
                                ds.addAll(selection.get(Tree.class));
                            case 2:
                                ds.addAll(getLayerSet().getZDisplayables(Tree.class, true));
                        }
                        getLayerSet().addDataEditStep(ds);
                        try {
                            for (final Displayable d : ds) {
                                final Tree t = (Tree) d;
                                t.removeTag(tag);
                            }
                            getLayerSet().addDataEditStep(ds);
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                        Display.repaint();
                    } else if (src == colorizeByNodeCentrality) {
                        final List<Tree> ts = selection.get(Tree.class);
                        final HashSet<Tree> ds = new HashSet<Tree>(ts);
                        getLayerSet().addDataEditStep(ds);
                        try {
                            for (final Tree t : ts) {
                                t.colorizeByNodeBetweennessCentrality();
                            }
                            getLayerSet().addDataEditStep(ds);
                            Display.repaint();
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                    } else if (src == colorizeByBranchCentrality) {
                        final List<Tree> ts = selection.get(Tree.class);
                        final HashSet<Tree> ds = new HashSet<Tree>(ts);
                        getLayerSet().addDataEditStep(ds);
                        try {
                            for (final Tree t : ts) {
                                t.colorizeByBranchBetweennessCentrality(2);
                            }
                            getLayerSet().addDataEditStep(ds);
                            Display.repaint();
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                    }
                }
            };
            for (final JMenuItem a : new JMenuItem[] { nodeColor, nodePairColor, nodeRadius, removeAllTags, removeTag, colorizeByNodeCentrality, colorizeByBranchCentrality }) {
                if (null == a)
                    continue;
                a.addActionListener(ln);
            }
            // 
            final JMenu review = new JMenu("Review");
            final JMenuItem tgenerate = new JMenuItem("Generate review stacks (selected Trees)");
            review.add(tgenerate);
            tgenerate.setEnabled(trees.size() > 0);
            final JMenuItem tslab = new JMenuItem("Generate review stack for current slab");
            review.add(tslab);
            final JMenuItem tsubtree = new JMenuItem("Generate review stacks for subtree");
            review.add(tsubtree);
            final JMenuItem tremove = new JMenuItem("Remove reviews (selected Trees)");
            review.add(tremove);
            tremove.setEnabled(trees.size() > 0);
            final JMenuItem tconnectors = new JMenuItem("View table of outgoing/incoming connectors");
            review.add(tconnectors);
            final ActionListener l = new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    if (!Utils.check("Really " + ae.getActionCommand())) {
                        return;
                    }
                    dispatcher.exec(new Runnable() {

                        @Override
                        public void run() {
                            int count = 0;
                            for (final Tree<?> t : trees) {
                                Utils.log("Processing " + (++count) + "/" + trees.size());
                                Bureaucrat bu = null;
                                if (ae.getSource() == tgenerate)
                                    bu = t.generateAllReviewStacks();
                                else if (ae.getSource() == tremove)
                                    bu = t.removeReviews();
                                else if (ae.getSource() == tslab) {
                                    final Point po = canvas.consumeLastPopupPoint();
                                    Utils.log2(po, layer, 1.0);
                                    bu = t.generateReviewStackForSlab(po.x, po.y, Display.this.layer, 1.0);
                                } else if (ae.getSource() == tsubtree) {
                                    final Point po = canvas.consumeLastPopupPoint();
                                    bu = t.generateSubtreeReviewStacks(po.x, po.y, Display.this.layer, 1.0);
                                }
                                if (null != bu)
                                    try {
                                        bu.getWorker().join();
                                    } catch (final InterruptedException ie) {
                                        return;
                                    }
                            }
                        }
                    });
                }
            };
            for (final JMenuItem c : new JMenuItem[] { tgenerate, tslab, tsubtree, tremove }) c.addActionListener(l);
            tconnectors.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    for (final Tree<?> t : trees) TreeConnectorsView.create(t);
                }
            });
            popup.add(review);
            final JMenu go = new JMenu("Go");
            item = new JMenuItem("Previous branch node or start");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, 0, true));
            item = new JMenuItem("Next branch node or end");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0, true));
            item = new JMenuItem("Root");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0, true));
            go.addSeparator();
            item = new JMenuItem("Last added node");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, 0, true));
            item = new JMenuItem("Last edited node");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0, true));
            popup.add(go);
            final JMenu tmeasure = new JMenu("Measure");
            final JMenuItem dist_to_root = new JMenuItem("Distance from this node to root");
            tmeasure.add(dist_to_root);
            final JMenuItem dist_to_tag = new JMenuItem("Distance from this node to all nodes tagged as...");
            tmeasure.add(dist_to_tag);
            final JMenuItem dist_to_mark = new JMenuItem("Distance from this node to the marked node");
            tmeasure.add(dist_to_mark);
            final JMenuItem dist_pairs = new JMenuItem("Shortest distances between all pairs of nodes tagged as...");
            tmeasure.add(dist_pairs);
            final ActionListener tma = getTreePathMeasureListener((Tree<?>) active);
            for (final JMenuItem mi : new JMenuItem[] { dist_to_root, dist_to_tag, dist_to_mark, dist_pairs }) {
                mi.addActionListener(tma);
            }
            popup.add(tmeasure);
            final String[] name = new String[] { AreaTree.class.getSimpleName(), Treeline.class.getSimpleName() };
            if (Treeline.class == aclass) {
                final String a = name[0];
                name[0] = name[1];
                name[1] = a;
            }
            item = new JMenuItem("Duplicate " + name[0] + " as " + name[1]);
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    Bureaucrat.createAndStart(new Worker.Task("Converting") {

                        @Override
                        public void exec() {
                            try {
                                getLayerSet().addChangeTreesStep();
                                final Map<Tree<?>, Tree<?>> m = Tree.duplicateAs(selection.getSelected(), (Class<Tree<?>>) (Treeline.class == aclass ? AreaTree.class : Treeline.class));
                                if (m.isEmpty()) {
                                    getLayerSet().removeLastUndoStep();
                                } else {
                                    getLayerSet().addChangeTreesStep();
                                }
                            } catch (final Exception e) {
                                IJError.print(e);
                            }
                        }
                    }, getProject());
                }
            });
            popup.add(item);
            popup.addSeparator();
        } else if (Connector.class == aclass) {
            item = new JMenuItem("Merge");
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    if (null == getActive() || getActive().getClass() != Connector.class) {
                        Utils.log("Active object must be a Connector!");
                        return;
                    }
                    final List<Connector> col = selection.get(Connector.class);
                    if (col.size() < 2) {
                        Utils.log("Select more than one Connector!");
                        return;
                    }
                    if (col.get(0) != getActive()) {
                        if (col.remove(getActive())) {
                            col.add(0, (Connector) getActive());
                        } else {
                            Utils.log("ERROR: cannot find active object in selection list!");
                            return;
                        }
                    }
                    Bureaucrat.createAndStart(new Worker.Task("Merging connectors") {

                        @Override
                        public void exec() {
                            getLayerSet().addChangeTreesStep();
                            Connector base = null;
                            try {
                                base = Connector.merge(col);
                            } catch (final Exception e) {
                                IJError.print(e);
                            }
                            if (null == base) {
                                Utils.log("ERROR: could not merge connectors!");
                                getLayerSet().undoOneStep();
                            } else {
                                getLayerSet().addChangeTreesStep();
                            }
                            Display.repaint();
                        }
                    }, getProject());
                }
            });
            popup.add(item);
            item.setEnabled(selection.getSelected(Connector.class).size() > 1);
            popup.addSeparator();
        }
        item = new JMenuItem("Duplicate");
        item.addActionListener(this);
        popup.add(item);
        item = new JMenuItem("Color...");
        item.addActionListener(this);
        popup.add(item);
        if (active instanceof LayerSet)
            item.setEnabled(false);
        if (active.isLocked()) {
            item = new JMenuItem("Unlock");
            item.addActionListener(this);
            popup.add(item);
        } else {
            item = new JMenuItem("Lock");
            item.addActionListener(this);
            popup.add(item);
        }
        menu = new JMenu("Move");
        popup.addSeparator();
        final LayerSet ls = layer.getParent();
        item = new JMenuItem("Move to top");
        item.addActionListener(this);
        menu.add(item);
        // this is just to draw the key name by the menu; it does not incur on any event being generated (that I know if), and certainly not any event being listened to by TrakEM2.
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, true));
        if (ls.isTop(active))
            item.setEnabled(false);
        item = new JMenuItem("Move up");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, true));
        if (ls.isTop(active))
            item.setEnabled(false);
        item = new JMenuItem("Move down");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, true));
        if (ls.isBottom(active))
            item.setEnabled(false);
        item = new JMenuItem("Move to bottom");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, true));
        if (ls.isBottom(active))
            item.setEnabled(false);
        popup.add(menu);
        popup.addSeparator();
        item = new JMenuItem("Delete...");
        item.addActionListener(this);
        popup.add(item);
        try {
            if (Patch.class == aclass) {
                if (!active.isOnlyLinkedTo(Patch.class)) {
                    item.setEnabled(false);
                }
            }
        } catch (final Exception e) {
            IJError.print(e);
            item.setEnabled(false);
        }
        if (Patch.class == aclass) {
            item = new JMenuItem("Revert");
            item.addActionListener(this);
            popup.add(item);
            if (null == ((Patch) active).getOriginalPath())
                item.setEnabled(false);
            popup.addSeparator();
        }
        item = new JMenuItem("Properties...");
        item.addActionListener(this);
        popup.add(item);
        item = new JMenuItem("Show centered");
        item.addActionListener(this);
        popup.add(item);
        popup.addSeparator();
        if (!(active instanceof ZDisplayable)) {
            final int i_layer = layer.getParent().indexOf(layer);
            final int n_layers = layer.getParent().size();
            item = new JMenuItem("Send to previous layer");
            item.addActionListener(this);
            popup.add(item);
            if (1 == n_layers || 0 == i_layer || active.isLinked())
                item.setEnabled(false);
            else // check if the active is a profile and contains a link to another profile in the layer it is going to be sent to, or it is linked
            if (active instanceof Profile && !active.canSendTo(layer.getParent().previous(layer)))
                item.setEnabled(false);
            item = new JMenuItem("Send to next layer");
            item.addActionListener(this);
            popup.add(item);
            if (1 == n_layers || n_layers - 1 == i_layer || active.isLinked())
                item.setEnabled(false);
            else if (active instanceof Profile && !active.canSendTo(layer.getParent().next(layer)))
                item.setEnabled(false);
            menu = new JMenu("Send linked group to...");
            if (active.hasLinkedGroupWithinLayer(this.layer)) {
                int i = 1;
                for (final Layer la : ls.getLayers()) {
                    String layer_title = i + ": " + la.getTitle();
                    if (-1 == layer_title.indexOf(' '))
                        layer_title += " ";
                    item = new JMenuItem(layer_title);
                    item.addActionListener(this);
                    menu.add(item);
                    if (la == this.layer)
                        item.setEnabled(false);
                    i++;
                }
                popup.add(menu);
            } else {
                menu.setEnabled(false);
            // Utils.log("Active's linked group not within layer.");
            }
            popup.add(menu);
            popup.addSeparator();
        }
    }
    item = new JMenuItem("Undo");
    item.addActionListener(this);
    popup.add(item);
    if (!layer.getParent().canUndo() || canvas.isTransforming())
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Utils.getControlModifier(), true));
    item = new JMenuItem("Redo");
    item.addActionListener(this);
    popup.add(item);
    if (!layer.getParent().canRedo() || canvas.isTransforming())
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.SHIFT_MASK | Utils.getControlModifier(), true));
    popup.addSeparator();
    try {
        menu = new JMenu("Hide/Unhide");
        item = new JMenuItem("Hide deselected");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.SHIFT_MASK, true));
        boolean none = 0 == selection.getNSelected();
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Hide deselected except images");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.SHIFT_MASK | Event.ALT_MASK, true));
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Hide selected");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, 0, true));
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().containsDisplayable(DLabel.class);
        item = new JMenuItem("Hide all labels");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all labels");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(AreaList.class);
        item = new JMenuItem("Hide all arealists");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all arealists");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.contains(Profile.class);
        item = new JMenuItem("Hide all profiles");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all profiles");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Pipe.class);
        item = new JMenuItem("Hide all pipes");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all pipes");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Polyline.class);
        item = new JMenuItem("Hide all polylines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all polylines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Treeline.class);
        item = new JMenuItem("Hide all treelines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all treelines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(AreaTree.class);
        item = new JMenuItem("Hide all areatrees");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all areatrees");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Ball.class);
        item = new JMenuItem("Hide all balls");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all balls");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Connector.class);
        item = new JMenuItem("Hide all connectors");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all connectors");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().containsDisplayable(Patch.class);
        item = new JMenuItem("Hide all images");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all images");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Hide all but images");
        item.addActionListener(this);
        menu.add(item);
        item = new JMenuItem("Unhide all");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.ALT_MASK, true));
        popup.add(menu);
    } catch (final Exception e) {
        IJError.print(e);
    }
    // plugins, if any
    Utils.addPlugIns(popup, "Display", project, new Callable<Displayable>() {

        @Override
        public Displayable call() {
            return Display.this.getActive();
        }
    });
    final JMenu align_menu = new JMenu("Align");
    item = new JMenuItem("Align stack slices");
    item.addActionListener(this);
    align_menu.add(item);
    if (selection.isEmpty() || !(getActive().getClass() == Patch.class && ((Patch) getActive()).isStack()))
        item.setEnabled(false);
    item = new JMenuItem("Align layers");
    item.addActionListener(this);
    align_menu.add(item);
    if (1 == layer.getParent().size())
        item.setEnabled(false);
    item = new JMenuItem("Align layers manually with landmarks");
    item.addActionListener(this);
    align_menu.add(item);
    if (1 == layer.getParent().size())
        item.setEnabled(false);
    item = new JMenuItem("Align multi-layer mosaic");
    item.addActionListener(this);
    align_menu.add(item);
    if (1 == layer.getParent().size())
        item.setEnabled(false);
    item = new JMenuItem("Montage all images in this layer");
    item.addActionListener(this);
    align_menu.add(item);
    if (layer.getDisplayables(Patch.class).size() < 2)
        item.setEnabled(false);
    item = new JMenuItem("Montage selected images");
    item.addActionListener(this);
    align_menu.add(item);
    if (selection.getSelected(Patch.class).size() < 2)
        item.setEnabled(false);
    item = new JMenuItem("Montage multiple layers");
    item.addActionListener(this);
    align_menu.add(item);
    popup.add(align_menu);
    final JMenuItem st = new JMenu("Transform");
    final StartTransformMenuListener tml = new StartTransformMenuListener();
    item = new JMenuItem("Transform (affine)");
    item.addActionListener(tml);
    st.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0, true));
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Transform (non-linear)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, Event.SHIFT_MASK, true));
    item = new JMenuItem("Cancel transform");
    st.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
    // just added as a self-documenting cue; no listener
    item.setEnabled(false);
    item = new JMenuItem("Remove rotation, scaling and shear (selected images)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Remove rotation, scaling and shear layer-wise");
    item.addActionListener(tml);
    st.add(item);
    item = new JMenuItem("Remove coordinate transforms (selected images)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Remove coordinate transforms layer-wise");
    item.addActionListener(tml);
    st.add(item);
    item = new JMenuItem("Adjust mesh resolution (selected images)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Adjust mesh resolution layer-wise");
    item.addActionListener(tml);
    st.add(item);
    item = new JMenuItem("Set coordinate transform of selected image to other selected images");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Set coordinate transform of selected image layer-wise");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Set affine transform of selected image to other selected images");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Set affine transform of selected image layer-wise");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    popup.add(st);
    final JMenu link_menu = new JMenu("Link");
    item = new JMenuItem("Link images...");
    item.addActionListener(this);
    link_menu.add(item);
    item = new JMenuItem("Unlink all selected images");
    item.addActionListener(this);
    link_menu.add(item);
    item.setEnabled(selection.getSelected(Patch.class).size() > 0);
    item = new JMenuItem("Unlink all");
    item.addActionListener(this);
    link_menu.add(item);
    popup.add(link_menu);
    final JMenu adjust_menu = new JMenu("Adjust images");
    item = new JMenuItem("Enhance contrast layer-wise...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Enhance contrast (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Adjust image filters (selected images)");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Set Min and Max layer-wise...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Set Min and Max (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Adjust min and max (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J, 0));
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Mask image borders (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Mask image borders (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Remove alpha masks (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Remove alpha masks (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Split images under polyline ROI");
    item.addActionListener(this);
    adjust_menu.add(item);
    final Roi roi = canvas.getFakeImagePlus().getRoi();
    if (null == roi || !(roi.getType() == Roi.POLYLINE || roi.getType() == Roi.FREELINE))
        item.setEnabled(false);
    item = new JMenuItem("Blend (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Blend (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Match intensities (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Remove intensity maps (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    popup.add(adjust_menu);
    final JMenu script = new JMenu("Script");
    final MenuScriptListener msl = new MenuScriptListener();
    item = new JMenuItem("Set preprocessor script layer-wise...");
    item.addActionListener(msl);
    script.add(item);
    item = new JMenuItem("Set preprocessor script (selected images)...");
    item.addActionListener(msl);
    script.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Remove preprocessor script layer-wise...");
    item.addActionListener(msl);
    script.add(item);
    item = new JMenuItem("Remove preprocessor script (selected images)...");
    item.addActionListener(msl);
    script.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    popup.add(script);
    menu = new JMenu("Import");
    item = new JMenuItem("Import image");
    item.addActionListener(this);
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, Event.ALT_MASK & Event.SHIFT_MASK, true));
    item = new JMenuItem("Import stack...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import stack with landmarks...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import grid...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import sequence as grid...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import from text file...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import labels as arealists...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Tags ...");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Export");
    final boolean has_arealists = layer.getParent().contains(AreaList.class);
    item = new JMenuItem("Make flat image...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Arealists as labels (tif)");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(has_arealists);
    item = new JMenuItem("Arealists as labels (amira)");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(has_arealists);
    item = new JMenuItem("Image stack under selected Arealist");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(null != active && AreaList.class == active.getClass());
    item = new JMenuItem("Fly through selected Treeline/AreaTree");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(null != active && Tree.class.isInstance(active));
    item = new JMenuItem("Tags...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Connectivity graph...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("NeuroML...");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Display");
    item = new JMenuItem("Resize canvas/LayerSet...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Autoresize canvas/LayerSet");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Resize canvas/LayerSet to ROI");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(null != canvas.getFakeImagePlus().getRoi());
    item = new JMenuItem("Properties ...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Calibration...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Grid overlay...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Adjust snapping parameters...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Adjust fast-marching parameters...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Adjust arealist paint parameters...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Show current 2D position in 3D");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Show layers as orthoslices in 3D");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Inspect image mesh triangles");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Project");
    this.project.getLoader().setupMenuItems(menu, this.getProject());
    item = new JMenuItem("Project properties...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Create subproject");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Create sibling project with retiled layers");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Release memory...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Flush image cache");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Regenerate all mipmaps");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Regenerate mipmaps (selected images)");
    item.addActionListener(this);
    menu.add(item);
    menu.addSeparator();
    item = new JMenuItem("Measurement options...");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Selection");
    item = new JMenuItem("Select all");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Select all visible");
    item.addActionListener(this);
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Utils.getControlModifier(), true));
    if (0 == layer.getDisplayableList().size() && 0 == layer.getParent().getDisplayableList().size())
        item.setEnabled(false);
    item = new JMenuItem("Select all that match...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Select none");
    item.addActionListener(this);
    menu.add(item);
    if (0 == selection.getNSelected())
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
    final JMenu bytype = new JMenu("Select all by type");
    item = new JMenuItem("AreaList");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("AreaTree");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Ball");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Connector");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Dissector");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Image");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Pipe");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Polyline");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Profile");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Text");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Treeline");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    menu.add(bytype);
    item = new JMenuItem("Restore selection");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Select under ROI");
    item.addActionListener(this);
    menu.add(item);
    if (canvas.getFakeImagePlus().getRoi() == null)
        item.setEnabled(false);
    final JMenu graph = new JMenu("Graph");
    final GraphMenuListener gl = new GraphMenuListener();
    item = new JMenuItem("Select outgoing Connectors");
    item.addActionListener(gl);
    graph.add(item);
    item = new JMenuItem("Select incoming Connectors");
    item.addActionListener(gl);
    graph.add(item);
    item = new JMenuItem("Select downstream targets");
    item.addActionListener(gl);
    graph.add(item);
    item = new JMenuItem("Select upstream targets");
    item.addActionListener(gl);
    graph.add(item);
    graph.setEnabled(!selection.isEmpty());
    menu.add(graph);
    item = new JMenuItem("Measure");
    item.addActionListener(this);
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0, true));
    item.setEnabled(!selection.isEmpty());
    popup.add(menu);
    menu = new JMenu("Tool");
    item = new JMenuItem("Rectangular ROI");
    item.addActionListener(new SetToolListener(Toolbar.RECTANGLE));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, true));
    item = new JMenuItem("Polygon ROI");
    item.addActionListener(new SetToolListener(Toolbar.POLYGON));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0, true));
    item = new JMenuItem("Freehand ROI");
    item.addActionListener(new SetToolListener(Toolbar.FREEROI));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0, true));
    item = new JMenuItem("Text");
    item.addActionListener(new SetToolListener(Toolbar.TEXT));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0, true));
    item = new JMenuItem("Magnifier glass");
    item.addActionListener(new SetToolListener(Toolbar.MAGNIFIER));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0, true));
    item = new JMenuItem("Hand");
    item.addActionListener(new SetToolListener(Toolbar.HAND));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0, true));
    item = new JMenuItem("Select");
    item.addActionListener(new SetToolListener(ProjectToolbar.SELECT));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0, true));
    item = new JMenuItem("Pencil");
    item.addActionListener(new SetToolListener(ProjectToolbar.PENCIL));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F10, 0, true));
    item = new JMenuItem("Pen");
    item.addActionListener(new SetToolListener(ProjectToolbar.PEN));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0, true));
    popup.add(menu);
    item = new JMenuItem("Search...");
    item.addActionListener(this);
    popup.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Utils.getControlModifier(), true));
    // canvas.add(popup);
    return popup;
}
Also used : AlignTask(mpicbg.trakem2.align.AlignTask) AlignLayersTask(mpicbg.trakem2.align.AlignLayersTask) DistortionCorrectionTask(lenscorrection.DistortionCorrectionTask) ActionEvent(java.awt.event.ActionEvent) Bureaucrat(ini.trakem2.utils.Bureaucrat) ArrayList(java.util.ArrayList) List(java.util.List) CoordinateTransformList(mpicbg.trakem2.transform.CoordinateTransformList) HashSet(java.util.HashSet) Color(java.awt.Color) PolygonRoi(ij.gui.PolygonRoi) ShapeRoi(ij.gui.ShapeRoi) Roi(ij.gui.Roi) ActionListener(java.awt.event.ActionListener) DBObject(ini.trakem2.persistence.DBObject) InspectPatchTrianglesMode(ini.trakem2.display.inspect.InspectPatchTrianglesMode) GenericDialog(ij.gui.GenericDialog) Worker(ini.trakem2.utils.Worker) JMenuItem(javax.swing.JMenuItem) Point(java.awt.Point) TreeMap(java.util.TreeMap) JPopupMenu(javax.swing.JPopupMenu) Point(java.awt.Point) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) JMenu(javax.swing.JMenu)

Example 2 with Ball

use of ini.trakem2.display.Ball in project TrakEM2 by trakem2.

the class Display method insertStack.

/**
 * @param stack_patch is just a Patch of a series of Patch that make a stack of Patches.
 */
private boolean insertStack(final ProjectThing target_landmarks, final Project source, final ProjectThing source_landmarks, final Patch stack_patch) {
    final List<Ball> l1 = new ArrayList<Ball>();
    final List<Ball> l2 = new ArrayList<Ball>();
    // source is the one that has the stack_patch
    final Collection<ProjectThing> b1s = source_landmarks.findChildrenOfType("ball");
    // target is this
    final Collection<ProjectThing> b2s = target_landmarks.findChildrenOfType("ball");
    final HashSet<String> seen = new HashSet<String>();
    for (final ProjectThing b1 : b1s) {
        final Ball ball1 = (Ball) b1.getObject();
        if (null == ball1) {
            Utils.log("ERROR: there's an empty 'ball' node in target project" + project.toString());
            return false;
        }
        final String title1 = ball1.getTitle();
        for (final ProjectThing b2 : b2s) {
            final Ball ball2 = (Ball) b2.getObject();
            if (null == ball2) {
                Utils.log("ERROR: there's an empty 'ball' node in source project" + source.toString());
                return false;
            }
            if (title1.equals(ball2.getTitle())) {
                if (seen.contains(title1))
                    continue;
                seen.add(title1);
                l1.add(ball1);
                l2.add(ball2);
            }
        }
    }
    if (l1.size() < 4) {
        Utils.log("ERROR: found only " + l1.size() + " common landmarks: needs at least 4!");
        return false;
    }
    // Extract coordinates of source project landmarks, in patch stack coordinate space
    final List<double[]> c1 = new ArrayList<double[]>();
    for (final Ball ball1 : l1) {
        final Map<Layer, double[]> m = ball1.getRawBalls();
        if (1 != m.size()) {
            Utils.log("ERROR: ball object " + ball1 + " from target project " + project + " has " + m.size() + " balls instead of just 1.");
            return false;
        }
        final Map.Entry<Layer, double[]> e = m.entrySet().iterator().next();
        final Layer layer = e.getKey();
        final double[] xyr = e.getValue();
        final double[] fin = new double[] { xyr[0], xyr[1] };
        final AffineTransform affine = ball1.getAffineTransformCopy();
        try {
            affine.preConcatenate(stack_patch.getAffineTransform().createInverse());
        } catch (final Exception nite) {
            IJError.print(nite);
            return false;
        }
        final double[] fout = new double[2];
        affine.transform(fin, 0, fout, 0, 1);
        c1.add(new double[] { fout[0], fout[1], layer.getParent().indexOf(layer) });
    }
    // Extract coordinates of target (this) project landmarks, in calibrated world space
    final List<double[]> c2 = new ArrayList<double[]>();
    for (final Ball ball2 : l2) {
        final double[][] b = ball2.getBalls();
        if (1 != b.length) {
            Utils.log("ERROR: ball object " + ball2 + " from source project " + source + " has " + b.length + " balls instead of just 1.");
            return false;
        }
        final double[] fin = new double[] { b[0][0], b[0][1] };
        final AffineTransform affine = ball2.getAffineTransformCopy();
        final double[] fout = new double[2];
        affine.transform(fin, 0, fout, 0, 1);
        c2.add(new double[] { fout[0], fout[1], b[0][2] });
    }
    // Print landmarks:
    Utils.log("Landmarks:");
    for (Iterator<double[]> it1 = c1.iterator(), it2 = c2.iterator(); it1.hasNext(); ) {
        Utils.log(Utils.toString(it1.next()) + " <--> " + Utils.toString(it2.next()));
    }
    // Create point matches
    final List<PointMatch> pm = new ArrayList<PointMatch>();
    for (Iterator<double[]> it1 = c1.iterator(), it2 = c2.iterator(); it1.hasNext(); ) {
        pm.add(new mpicbg.models.PointMatch(new mpicbg.models.Point(it1.next()), new mpicbg.models.Point(it2.next())));
    }
    // Estimate AffineModel3D
    final AffineModel3D aff3d = new AffineModel3D();
    try {
        aff3d.fit(pm);
    } catch (final Exception e) {
        IJError.print(e);
        return false;
    }
    // Create and add the Stack
    final String path = stack_patch.getImageFilePath();
    final Stack st = new Stack(project, new File(path).getName(), 0, 0, getLayerSet().getLayers().get(0), path);
    st.setInvertibleCoordinateTransform(aff3d);
    getLayerSet().add(st);
    return true;
}
Also used : PointMatch(mpicbg.models.PointMatch) ArrayList(java.util.ArrayList) ProjectThing(ini.trakem2.tree.ProjectThing) HashSet(java.util.HashSet) Point(java.awt.Point) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) LayerStack(ini.trakem2.imaging.LayerStack) PatchStack(ini.trakem2.imaging.PatchStack) PointMatch(mpicbg.models.PointMatch) AffineTransform(java.awt.geom.AffineTransform) Map(java.util.Map) TreeMap(java.util.TreeMap) HashMap(java.util.HashMap) File(java.io.File) AffineModel3D(mpicbg.trakem2.transform.AffineModel3D)

Example 3 with Ball

use of ini.trakem2.display.Ball in project TrakEM2 by trakem2.

the class Display3D method show.

/**
 * Scan the {@link ProjectThing} children and assign the renderable ones to an existing {@link Display3D} for their {@link LayerSet}, or open a new one. If {@code true == wait && -1 != resample}, then the method returns only when the mesh/es have been added.
 */
public static Future<Vector<Future<Content>>> show(final ProjectThing pt, final boolean wait, final int resample) {
    if (null == pt)
        return null;
    final Future<Vector<Future<Content>>> fu = launchers.submit(new Callable<Vector<Future<Content>>>() {

        @Override
        public Vector<Future<Content>> call() {
            // Scan the given ProjectThing for 3D-viewable items
            // So: find arealist, pipe, ball, and profile_list types
            final HashSet<ProjectThing> hs = pt.findBasicTypeChildren();
            if (null == hs || 0 == hs.size()) {
                Utils.logAll("Node " + pt + " does not contain any 3D-displayable children");
                return null;
            }
            // Remove profile if it lives under a profile_list
            for (final Iterator<ProjectThing> it = hs.iterator(); it.hasNext(); ) {
                final ProjectThing pt = it.next();
                if (null != pt.getObject() && pt.getObject().getClass() == Profile.class && pt.getParent().getType().equals("profile_list")) {
                    it.remove();
                }
            }
            setWaitingCursor();
            // Start new scheduler to publish/add meshes to the 3D Viewer every 5 seconds and when done.
            final Hashtable<Display3D, Vector<Content>> contents = new Hashtable<Display3D, Vector<Content>>();
            final ScheduledExecutorService updater = Executors.newScheduledThreadPool(1);
            final AtomicInteger counter = new AtomicInteger();
            updater.scheduleWithFixedDelay(new Runnable() {

                @Override
                public void run() {
                    // Obtain a copy of the contents queue
                    final HashMap<Display3D, Vector<Content>> m = new HashMap<Display3D, Vector<Content>>();
                    synchronized (contents) {
                        m.putAll(contents);
                        contents.clear();
                    }
                    if (m.isEmpty())
                        return;
                    // Add all to the corresponding Display3D
                    for (final Map.Entry<Display3D, Vector<Content>> e : m.entrySet()) {
                        e.getKey().universe.addContentLater(e.getValue());
                        counter.getAndAdd(e.getValue().size());
                    }
                    Utils.showStatus(new StringBuilder("Rendered ").append(counter.get()).append('/').append(hs.size()).toString());
                }
            }, 100, 4000, TimeUnit.MILLISECONDS);
            // A list of all generated Content objects
            final Vector<Future<Content>> list = new Vector<Future<Content>>();
            for (final Iterator<ProjectThing> it = hs.iterator(); it.hasNext(); ) {
                // obtain the Displayable object under the node
                final ProjectThing child = it.next();
                final Object obc = child.getObject();
                final Displayable displ = obc.getClass().equals(String.class) ? null : (Displayable) obc;
                if (null != displ) {
                    if (displ.getClass().equals(Profile.class)) {
                        // handled by profile_list Thing
                        continue;
                    }
                    if (!displ.isVisible()) {
                        Utils.log("Skipping non-visible node " + displ);
                        continue;
                    }
                }
                // obtain the containing LayerSet
                final Display3D d3d;
                if (null != displ)
                    d3d = Display3D.get(displ.getLayerSet());
                else if (child.getType().equals("profile_list")) {
                    final ArrayList<ProjectThing> al_children = child.getChildren();
                    if (null == al_children || 0 == al_children.size())
                        continue;
                    // else, get the first Profile and get its LayerSet
                    d3d = Display3D.get(((Displayable) ((ProjectThing) al_children.get(0)).getObject()).getLayerSet());
                } else {
                    Utils.log("Don't know what to do with node " + child);
                    d3d = null;
                }
                if (null == d3d) {
                    Utils.log("Could not get a proper 3D display for node " + displ);
                    // java3D not installed most likely
                    return null;
                }
                boolean already;
                synchronized (d3d.ht_pt_meshes) {
                    already = d3d.ht_pt_meshes.containsKey(child);
                }
                if (already) {
                    if (child.getObject() instanceof ZDisplayable) {
                        Utils.log("Updating 3D view of " + child.getObject());
                    } else {
                        Utils.log("Updating 3D view of " + child);
                    }
                }
                list.add(d3d.executors.submit(new Callable<Content>() {

                    @Override
                    public Content call() {
                        Content c = null;
                        try {
                            c = d3d.createMesh(child, displ, resample).call();
                            Vector<Content> vc;
                            synchronized (contents) {
                                vc = contents.get(d3d);
                                if (null == vc)
                                    vc = new Vector<Content>();
                                contents.put(d3d, vc);
                            }
                            vc.add(c);
                        } catch (final Exception e) {
                            IJError.print(e);
                        }
                        return c;
                    }
                }));
                // If it's the last one:
                if (!it.hasNext()) {
                    // Add the concluding task, that waits on all and shuts down the scheduler
                    d3d.executors.submit(new Runnable() {

                        @Override
                        public void run() {
                            // Wait until all are done
                            for (final Future<Content> c : list) {
                                try {
                                    c.get();
                                } catch (final Throwable t) {
                                    IJError.print(t);
                                }
                            }
                            try {
                                // Shutdown scheduler and execute remaining tasks
                                for (final Runnable r : updater.shutdownNow()) {
                                    r.run();
                                }
                            } catch (final Throwable e) {
                                IJError.print(e);
                            }
                            // Reset cursor
                            doneWaiting();
                            Utils.showStatus(new StringBuilder("Done rendering ").append(counter.get()).append('/').append(hs.size()).toString());
                        }
                    });
                }
            }
            return list;
        }
    });
    if (wait && -1 != resample) {
        try {
            fu.get();
        } catch (final Throwable t) {
            IJError.print(t);
        }
    }
    return fu;
}
Also used : HashMap(java.util.HashMap) Iterator(java.util.Iterator) Vector(java.util.Vector) ProjectThing(ini.trakem2.tree.ProjectThing) HashSet(java.util.HashSet) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Hashtable(java.util.Hashtable) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Content(ij3d.Content) Future(java.util.concurrent.Future) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with Ball

use of ini.trakem2.display.Ball in project TrakEM2 by trakem2.

the class Render method save.

/**
 * Popup a dialog to save a .shapes file with all the curves of the objects inside. The z_scale corrects for sample squashign under the coverslip.
 */
public void save(double z_scale) {
    /* I would have never though that the crappy .shapes file would make it so far.
		 */
    if (ht_objects.isEmpty() && al_pipes.isEmpty() && al_balls.isEmpty()) {
        Utils.log("No objects to save.");
        return;
    }
    Ob[] obs = new Ob[ht_objects.size()];
    ht_objects.values().toArray(obs);
    Pipe[] pipes = new Pipe[al_pipes.size()];
    al_pipes.toArray(pipes);
    Ball[] balls = new Ball[al_balls.size()];
    al_balls.toArray(balls);
    // generare header: the Groups= and Colors= and Supergroups= and Supercolors=
    StringBuffer data = new StringBuffer("Groups=");
    String l = "\n";
    for (int i = 0; i < obs.length; i++) {
        data.append(obs[i].name).append(",");
    }
    for (int i = 0; i < pipes.length; i++) {
        data.append(pipes[i].toString()).append(",");
    }
    for (int i = 0; i < balls.length; i++) {
        data.append(balls[i].toString()).append(",");
    }
    // compute a color from RGB to grayscale// TODO there are tones of improvements to be done here, besides Blender would accept an RGB color straight. The python script has to be modified. For example with bit packing it could save an int alpha/red/green/blue no problem!
    int[] color = new int[obs.length + pipes.length + balls.length];
    data.append(l).append("Colors=");
    int j = 0;
    for (int i = 0; i < obs.length; i++) {
        Color colorRGB = obs[i].profiles[0].getColor();
        color[j++] = colorRGB.getGreen();
        data.append(color[i]).append(",");
    }
    for (int i = 0; i < pipes.length; i++) {
        Color colorRGB = pipes[i].getColor();
        color[j++] = colorRGB.getGreen();
        data.append(color[i]).append(",");
    }
    for (int i = 0; i < balls.length; i++) {
        Color colorRGB = balls[i].getColor();
        color[j++] = colorRGB.getGreen();
        data.append(color[i]).append(",");
    }
    data.append(l).append("Supergroups=");
    for (int i = 0; i < obs.length + pipes.length + balls.length; i++) {
        data.append("null,");
    }
    data.append(l).append("Supercolors=");
    for (int i = 0; i < obs.length + pipes.length + balls.length; i++) {
        data.append("null,");
    }
    data.append(l).append(l);
    // add the data
    j = 0;
    for (int i = 0; i < obs.length; i++) {
        String clr = Integer.toString(color[j++]);
        for (int k = 0; k < obs[i].profiles.length; k++) {
            if (null == obs[i] || null == obs[i].profiles[k]) {
                Utils.log("obs[i] is : " + obs[i]);
                if (null != obs[i].profiles[k])
                    Utils.log("obs[i].profiles[k] is " + obs[i].profiles[k]);
                continue;
            }
            obs[i].profiles[k].toShapesFile(data, obs[i].name, clr, z_scale);
            data.append(l);
        }
    }
    for (int i = 0; i < pipes.length; i++) {
        pipes[i].toShapesFile(data, pipes[i].toString(), Integer.toString(color[j++]), z_scale);
        data.append(l);
    }
    for (int i = 0; i < balls.length; i++) {
        balls[i].toShapesFile(data, balls[i].toString(), Integer.toString(color[j++]), z_scale);
        data.append(l);
    }
    // save the data in a file
    final SaveDialog sd = new SaveDialog("Save .shapes", OpenDialog.getDefaultDirectory(), "shapes");
    String dir = sd.getDirectory();
    if (null == dir)
        return;
    if (IJ.isWindows())
        dir = dir.replace('\\', '/');
    if (!dir.endsWith("/"))
        dir += "/";
    String file_name = sd.getFileName();
    String file_path = dir + file_name;
    File f = new File(file_path);
    if (f.exists()) {
        YesNoCancelDialog d = new YesNoCancelDialog(IJ.getInstance(), "Overwrite?", "File " + file_name + " exists! Overwrite?");
        if (!d.yesPressed()) {
            return;
        }
    }
    String contents = data.toString();
    try {
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(f), data.length()));
        dos.writeBytes(contents);
        dos.flush();
    } catch (Exception e) {
        IJError.print(e);
        Utils.log("ERROR: Most likely did NOT save your file.");
    }
}
Also used : Ball(ini.trakem2.display.Ball) DataOutputStream(java.io.DataOutputStream) Color(java.awt.Color) Pipe(ini.trakem2.display.Pipe) FileOutputStream(java.io.FileOutputStream) SaveDialog(ij.io.SaveDialog) YesNoCancelDialog(ij.gui.YesNoCancelDialog) File(java.io.File) BufferedOutputStream(java.io.BufferedOutputStream)

Example 5 with Ball

use of ini.trakem2.display.Ball in project TrakEM2 by trakem2.

the class Compare method extractPoints.

/**
 * Extracts the list of fiduciary points from the fiducial parent and, if their name is different than "ball", adds their title as key and their first ball as a fiduciary point value of the returned map. The map is never null but could be empty.
 * The values are calibrated.
 */
public static Map<String, Tuple3d> extractPoints(final ProjectThing fiducial) {
    if (!fiducial.getType().equals("fiducial_points")) {
        Utils.log("Can only extract points from 'fiducial_points' type.");
        return null;
    }
    final ArrayList<ProjectThing> fiducials = fiducial.getChildren();
    if (null == fiducials || 0 == fiducials.size()) {
        Utils.log("No fiducial points can be extracted from " + fiducial);
        return null;
    }
    final Map<String, Tuple3d> fide = new HashMap<String, Tuple3d>();
    for (final ProjectThing child : fiducials) {
        final Ball ball;
        final String title;
        if (child.getType().equals("ball")) {
            // Method 1: use the ball title as the fiducial type
            ball = (Ball) child.getObject();
            title = ball.getTitle();
        } else {
            // Method 2: use the ball's parent type as the fiducial type
            final ArrayList<ProjectThing> balls = child.findChildrenOfType("ball");
            if (null == balls || 0 == balls.size()) {
                Utils.log2("Ignoring empty fiducial " + child);
                continue;
            }
            // pick the first one only
            ball = (Ball) balls.get(0).getObject();
            title = child.getType();
        }
        // calibrated
        final double[][] b = ball.getWorldBalls();
        if (b.length > 0) {
            // get the first one only
            fide.put(title.toLowerCase(), new Point3d(b[0][0], b[0][1], b[0][2]));
            Utils.log2("Found fiducial point " + title.toLowerCase());
        }
    }
    return fide;
}
Also used : Ball(ini.trakem2.display.Ball) HashMap(java.util.HashMap) Tuple3d(org.scijava.vecmath.Tuple3d) Point3d(org.scijava.vecmath.Point3d) ProjectThing(ini.trakem2.tree.ProjectThing)

Aggregations

Ball (ini.trakem2.display.Ball)5 Point (java.awt.Point)5 Color (java.awt.Color)4 HashMap (java.util.HashMap)4 HashSet (java.util.HashSet)4 GenericDialog (ij.gui.GenericDialog)3 Displayable (ini.trakem2.display.Displayable)3 Pipe (ini.trakem2.display.Pipe)3 ZDisplayable (ini.trakem2.display.ZDisplayable)3 ProjectThing (ini.trakem2.tree.ProjectThing)3 AreaList (ini.trakem2.display.AreaList)2 AreaTree (ini.trakem2.display.AreaTree)2 Connector (ini.trakem2.display.Connector)2 DLabel (ini.trakem2.display.DLabel)2 Patch (ini.trakem2.display.Patch)2 Polyline (ini.trakem2.display.Polyline)2 Profile (ini.trakem2.display.Profile)2 Treeline (ini.trakem2.display.Treeline)2 AffineTransform (java.awt.geom.AffineTransform)2 NoninvertibleTransformException (java.awt.geom.NoninvertibleTransformException)2