use of ini.trakem2.display.Tag in project TrakEM2 by trakem2.
the class NeuroML method exportMorphMLCell.
/**
* Without headers, just the cell block for a single Treeline.
* If pre is null, then synapses are not collected.
*/
private static final void exportMorphMLCell(final Writer w, final Treeline t, final Set<Tree<?>> trees, final List<HalfSynapse> pre, final List<HalfSynapse> post, final AffineTransform scale2d, final double zScale) throws IOException {
// x, y, z, r
final float[] fp = new float[4];
// Prepare transform
final AffineTransform aff = new AffineTransform(t.getAffineTransform());
aff.preConcatenate(scale2d);
writeCellHeader(w, t);
// Map of Node vs id of the node
// These ids are used to express parent-child relationships between segments
final HashMap<Node<Float>, Long> nodeIds = new HashMap<Node<Float>, Long>();
// Map of coords for branch or end nodes
// so that the start of a cable can write the proximal coords
final HashMap<Node<Float>, float[]> nodeCoords = new HashMap<Node<Float>, float[]>();
// Root gets ID of 0:
long nextSegmentId = 0;
long cableId = 0;
final Node<Float> root = t.getRoot();
toPoint(root, fp, aff, zScale);
// a dummy segment that has no length, and with a cableId of 0.
writeSomaSegment(w, fp);
if (null != pre)
collectConnectors(root, t, fp, 0, pre, post);
// Prepare
nodeIds.put(root, nextSegmentId);
nodeCoords.put(root, fp.clone());
nextSegmentId += 1;
cableId += 1;
// All cables that come out of the Soma (the root) require a special tag:
final HashSet<Long> somaCables = new HashSet<Long>();
// Iterate all cables (all slabs; here a slab is synonym with cable, even if in NeuroML it doesn't have to be)
for (final Node<Float> node : t.getRoot().getBranchAndEndNodes()) {
// Gather the list of nodes all the way up to the previous branch node or root,
// that last one not included.
final List<Node<Float>> slab = cable(node);
final String sCableId = Long.toString(cableId);
// The id of the parent already exists, given that the Collection
// is iterated depth-first from the root.
final Node<Float> parent = slab.get(slab.size() - 1).getParent();
long parentId = nodeIds.get(parent);
// Use the parent coords for the proximal coords of the first segment of the cable
float[] parentCoords = nodeCoords.get(parent);
// Is it a cable coming out of the root node (the soma) ?
if (0 == parentId)
somaCables.add(cableId);
// write a segment of the cable
for (final ListIterator<Node<Float>> it = slab.listIterator(slab.size()); it.hasPrevious(); ) {
// Assign an id to the node of the slab
final Node<Float> seg = it.previous();
// Write the segment
toPoint(seg, fp, aff, zScale);
writeCableSegment(w, fp, nextSegmentId, parentId, parentCoords, sCableId);
// Inspect and collect synapses originating at this node
if (null != pre)
collectConnectors(seg, t, fp, nextSegmentId, pre, post);
// Prepare next segment in the cable
parentId = nextSegmentId;
nextSegmentId += 1;
// is used only for the first node
parentCoords = null;
}
// Record the branch node, to be used for filling in "distal" fields
if (node.getChildrenCount() > 1) {
// parentId is the last used nextId, which is the id of node
nodeIds.put(node, parentId);
final float[] fpCopy = new float[4];
toPoint(node, fpCopy, aff, zScale);
nodeCoords.put(node, fpCopy);
}
// Prepare next slab or cable
cableId += 1;
}
w.write(" </segments>\n");
// Define the nature of each cable
// Each cable requires a unique name
w.write(" <cables xmlns=\"http://morphml.org/morphml/schema\">\n");
w.write(" <cable id=\"0\" name=\"Soma\">\n <meta:group>soma_group</meta:group>\n </cable>\n");
for (long i = 1; i < cableId; i++) {
final String sid = Long.toString(i);
w.write(" <cable id=\"");
w.write(sid);
w.write("\" name=\"");
w.write(sid);
if (somaCables.contains(i))
w.write("\" fract_along_parent=\"0.5");
else
// child segments start at the end of the segment
w.write("\" fract_along_parent=\"1.0");
w.write("\">\n <meta:group>arbor_group</meta:group>\n </cable>\n");
}
w.write(" </cables>\n</cell>\n");
}
use of ini.trakem2.display.Tag 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;
}
use of ini.trakem2.display.Tag in project TrakEM2 by trakem2.
the class Patch method exportXML.
/**
* Opens and closes the tag and exports data. The image is saved in the directory provided in @param any as a String.
*/
@Override
public void exportXML(final StringBuilder sb_body, final String indent, final XMLOptions options) {
// TODO the Loader should handle the saving of images, not this class.
final String in = indent + "\t";
String path = null;
String path2 = null;
if (options.export_images) {
path = options.patches_dir + title;
// save image without overwriting, and add proper extension (.zip)
path2 = project.getLoader().exportImage(this, path, false);
// path2 will be null if the file exists already
}
sb_body.append(indent).append("<t2_patch\n");
String rel_path = null;
if (null != path && path.equals(path2)) {
// this happens when a DB project is exported. It may be a different path when it's a FS loader
// Utils.log2("p id=" + id + " path==path2");
rel_path = path2;
// TrakEM2 uses paths that always have '/' and never '\', so using java.io.File.separatorChar would be an error.
int i_slash = rel_path.lastIndexOf('/');
if (i_slash > 0) {
i_slash = rel_path.lastIndexOf('/', i_slash - 1);
if (-1 != i_slash) {
rel_path = rel_path.substring(i_slash + 1);
}
}
} else {
// Utils.log2("Setting rel_path to " + path2);
rel_path = path2;
}
// For FSLoader projects, saving a second time will save images as null unless calling it
if (null == rel_path) {
// Utils.log2("path2 was null");
final Object ob = project.getLoader().getPath(this);
path2 = null == ob ? null : (String) ob;
if (null == path2) {
// Utils.log2("ERROR: No path for Patch id=" + id + " and title: " + title);
// at least some clue for recovery
rel_path = title;
} else {
rel_path = path2;
}
}
// Utils.log("Patch path is: " + rel_path);
super.exportXML(sb_body, in, options);
final String[] RGB = Utils.getHexRGBColor(color);
int type = this.type;
if (-1 == this.type) {
Utils.log2("Retrieving type for p = " + this);
final ImagePlus imp = project.getLoader().fetchImagePlus(this);
if (null != imp)
type = imp.getType();
}
sb_body.append(in).append("type=\"").append(type).append("\"\n").append(in).append("file_path=\"").append(rel_path).append("\"\n").append(in).append("style=\"fill-opacity:").append(alpha).append(";stroke:#").append(RGB[0]).append(RGB[1]).append(RGB[2]).append(";\"\n").append(in).append("o_width=\"").append(o_width).append("\"\n").append(in).append("o_height=\"").append(o_height).append("\"\n");
if (null != original_path) {
sb_body.append(in).append("original_path=\"").append(original_path).append("\"\n");
}
sb_body.append(in).append("min=\"").append(min).append("\"\n");
sb_body.append(in).append("max=\"").append(max).append("\"\n");
final String pps = getPreprocessorScriptPath();
if (null != pps)
sb_body.append(in).append("pps=\"").append(project.getLoader().makeRelativePath(pps)).append("\"\n");
sb_body.append(in).append("mres=\"").append(meshResolution).append("\"\n");
if (hasCoordinateTransform()) {
sb_body.append(in).append("ct_id=\"").append(ct_id).append("\"\n");
}
if (hasAlphaMask()) {
sb_body.append(in).append("alpha_mask_id=\"").append(alpha_mask_id).append("\"\n");
}
sb_body.append(indent).append(">\n");
if (hasCoordinateTransform()) {
if (options.include_coordinate_transform) {
// Write an XML entry for the CoordinateTransform
char[] ct_chars = null;
try {
ct_chars = readCoordinateTransformFile();
} catch (final Exception e) {
IJError.print(e);
}
if (null != ct_chars) {
sb_body.append(ct_chars).append('\n');
} else {
Utils.log("ERROR: could not write the CoordinateTransform to the XML file!");
}
}
}
if (null != filters && filters.length > 0) {
// specify their own line termination
for (final IFilter f : filters) sb_body.append(f.toXML(in));
}
super.restXML(sb_body, in, options);
sb_body.append(indent).append("</t2_patch>\n");
}
use of ini.trakem2.display.Tag in project TrakEM2 by trakem2.
the class Loader method makePrescaledTiles.
/**
* Generate 256x256 tiles, as many as necessary, to cover the given srcRect, starting at max_scale. Designed to be slow but memory-capable.
*
* filename = z + "/" + row + "_" + column + "_" + s + ".jpg";
*
* row and column run from 0 to n stepsize 1
* that is, row = y / ( 256 * 2^s ) and column = x / ( 256 * 2^s )
*
* z : z-level (slice)
* x,y: the row and column
* s: scale, which is 1 / (2^s), in integers: 0, 1, 2 ...
*
* var MAX_S = Math.floor( Math.log( MAX_Y + 1 ) / Math.LN2 ) - Math.floor( Math.log( Y_TILE_SIZE ) / Math.LN2 ) - 1;
*
* The module should not be more than 5
* At al levels, there should be an even number of rows and columns, except for the coarsest level.
* The coarsest level should be at least 5x5 tiles.
*
* Best results obtained when the srcRect approaches or is a square. Black space will pad the right and bottom edges when the srcRect is not exactly a square.
* Only the area within the srcRect is ever included, even if actual data exists beyond.
*
* @return The watcher thread, for joining purposes, or null if the dialog is canceled or preconditions are not passed.
* @throws IllegalArgumentException if the type is not ImagePlus.GRAY8 or Imageplus.COLOR_RGB.
*/
public Bureaucrat makePrescaledTiles(final Layer[] layers, final Class<?> clazz, final Rectangle srcRect, double max_scale_, final int c_alphas, final int type, String target_dir, final boolean from_original_images, final Saver saver, final int tileSide) {
if (null == layers || 0 == layers.length)
return null;
switch(type) {
case ImagePlus.GRAY8:
case ImagePlus.COLOR_RGB:
break;
default:
throw new IllegalArgumentException("Can only export for web with 8-bit or RGB");
}
// choose target directory
if (null == target_dir) {
final DirectoryChooser dc = new DirectoryChooser("Choose target directory");
target_dir = dc.getDirectory();
if (null == target_dir)
return null;
}
if (IJ.isWindows())
target_dir = target_dir.replace('\\', '/');
if (!target_dir.endsWith("/"))
target_dir += "/";
if (max_scale_ > 1) {
Utils.log("Prescaled Tiles: using max scale of 1.0");
// no point
max_scale_ = 1;
}
final String dir = target_dir;
final double max_scale = max_scale_;
final Worker worker = new Worker("Creating prescaled tiles") {
private void cleanUp() {
finishedWorking();
}
@Override
public void run() {
startedWorking();
try {
// project name
// String pname = layer[0].getProject().getTitle();
// create 'z' directories if they don't exist: check and ask!
// start with the highest scale level
final int[] best = determineClosestPowerOfTwo(srcRect.width > srcRect.height ? srcRect.width : srcRect.height);
final int edge_length = best[0];
final int n_edge_tiles = edge_length / tileSide;
Utils.log2("srcRect: " + srcRect);
Utils.log2("edge_length, n_edge_tiles, best[1] " + best[0] + ", " + n_edge_tiles + ", " + best[1]);
// thumbnail dimensions
// LayerSet ls = layer[0].getParent();
final double ratio = srcRect.width / (double) srcRect.height;
double thumb_scale = 1.0;
if (ratio >= 1) {
// width is larger or equal than height
thumb_scale = 192.0 / srcRect.width;
} else {
thumb_scale = 192.0 / srcRect.height;
}
// Figure out layer indices, given that layers are not necessarily evenly spaced
final TreeMap<Integer, Layer> indices = new TreeMap<Integer, Layer>();
final ArrayList<Integer> missingIndices = new ArrayList<Integer>();
final double resolution_z_px;
final int smallestIndex, largestIndex;
if (1 == layers.length) {
indices.put(0, layers[0]);
resolution_z_px = layers[0].getZ();
smallestIndex = 0;
largestIndex = 0;
} else {
// Ensure layers are sorted by Z index and are unique pointers and unique in Z coordinate:
final TreeMap<Double, Layer> t = new TreeMap<Double, Layer>();
for (final Layer l1 : new HashSet<Layer>(Arrays.asList(layers))) {
final Layer l2 = t.get(l1.getZ());
if (null == l2) {
t.put(l1.getZ(), l1);
} else {
// Ignore the layer with less objects
if (l1.getDisplayables().size() > l2.getDisplayables().size()) {
t.put(l1.getZ(), l1);
Utils.log("Ignoring duplicate layer: " + l2);
}
}
}
// What is the mode thickness, measured by Z(i-1) - Z(i)?
// (Distance between the Z of two consecutive layers)
final HashMap<Double, Integer> counts = new HashMap<Double, Integer>();
final Layer prev = t.get(t.firstKey());
double modeThickness = 0;
int modeThicknessCount = 0;
for (final Layer la : t.tailMap(prev.getZ(), false).values()) {
// Thickness with 3-decimal precision only
final double d = ((int) ((la.getZ() - prev.getZ()) * 1000 + 0.5)) / 1000.0;
Integer c = counts.get(d);
//
if (null == c)
c = 0;
++c;
counts.put(d, c);
//
if (c > modeThicknessCount) {
modeThicknessCount = c;
modeThickness = d;
}
}
// Not pixelDepth
resolution_z_px = modeThickness * prev.getParent().getCalibration().pixelWidth;
// Assign an index to each layer, approximating each layer at modeThickness intervals
for (final Layer la : t.values()) {
indices.put((int) (la.getZ() / modeThickness + 0.5), la);
}
// First and last
smallestIndex = indices.firstKey();
largestIndex = indices.lastKey();
Utils.logAll("indices: " + smallestIndex + ", " + largestIndex);
// Which indices are missing?
for (int i = smallestIndex + 1; i < largestIndex; ++i) {
if (!indices.containsKey(i)) {
missingIndices.add(i);
}
}
}
// JSON metadata for CATMAID
{
final StringBuilder sb = new StringBuilder("{");
final LayerSet ls = layers[0].getParent();
final Calibration cal = ls.getCalibration();
sb.append("\"volume_width_px\": ").append(srcRect.width).append(',').append('\n').append("\"volume_height_px\": ").append(srcRect.height).append(',').append('\n').append("\"volume_sections\": ").append(largestIndex - smallestIndex + 1).append(',').append('\n').append("\"extension\": \"").append(saver.getExtension()).append('\"').append(',').append('\n').append("\"resolution_x\": ").append(cal.pixelWidth).append(',').append('\n').append("\"resolution_y\": ").append(cal.pixelHeight).append(',').append('\n').append("\"resolution_z\": ").append(resolution_z_px).append(',').append('\n').append("\"units\": \"").append(cal.getUnit()).append('"').append(',').append('\n').append("\"offset_x_px\": 0,\n").append("\"offset_y_px\": 0,\n").append("\"offset_z_px\": ").append(indices.get(indices.firstKey()).getZ() * cal.pixelWidth / cal.pixelDepth).append(',').append('\n').append("\"missing_layers\": [");
for (final Integer i : missingIndices) sb.append(i - smallestIndex).append(',');
// remove last comma
sb.setLength(sb.length() - 1);
sb.append("]}");
if (!Utils.saveToFile(new File(dir + "metadata.json"), sb.toString())) {
Utils.logAll("WARNING: could not save " + dir + "metadata.json\nThe contents was:\n" + sb.toString());
}
}
for (final Map.Entry<Integer, Layer> entry : indices.entrySet()) {
if (this.quit) {
cleanUp();
return;
}
final int index = entry.getKey() - smallestIndex;
final Layer layer = entry.getValue();
// 1 - create a directory 'z' named as the layer's index
String tile_dir = dir + index;
File fdir = new File(tile_dir);
final int tag = 1;
// Ensure there is a usable directory:
while (fdir.exists() && !fdir.isDirectory()) {
fdir = new File(tile_dir + "_" + tag);
}
if (!fdir.exists()) {
fdir.mkdir();
Utils.log("Created directory " + fdir);
}
// if the directory exists already just reuse it, overwritting its files if so.
final String tmp = fdir.getAbsolutePath().replace('\\', '/');
if (!tile_dir.equals(tmp))
Utils.log("\tWARNING: directory will not be in the standard location.");
// debug:
Utils.log2("tile_dir: " + tile_dir + "\ntmp: " + tmp);
tile_dir = tmp;
if (!tile_dir.endsWith("/"))
tile_dir += "/";
// 2 - create layer thumbnail, max 192x192
ImagePlus thumb = getFlatImage(layer, srcRect, thumb_scale, c_alphas, type, clazz, true);
saver.save(thumb, tile_dir + "small");
// ImageSaver.saveAsJpeg(thumb.getProcessor(), tile_dir + "small.jpg", jpeg_quality, ImagePlus.COLOR_RGB != type);
flush(thumb);
thumb = null;
// 3 - fill directory with tiles
if (edge_length < tileSide) {
// edge_length is the largest length of the tileSide x tileSide tile map that covers an area equal or larger than the desired srcRect (because all tiles have to be tileSide x tileSide in size)
// create single tile per layer
makeTile(layer, srcRect, max_scale, c_alphas, type, clazz, tile_dir + "0_0_0", saver);
} else {
// create pyramid of tiles
if (from_original_images) {
Utils.log("Exporting from web using original images");
// Create a giant 8-bit image of the whole layer from original images
double scale = 1;
Utils.log("Export srcRect: " + srcRect);
// WARNING: the snapshot will most likely be smaller than the virtual square image being chopped into tiles
ImageProcessor snapshot = null;
if (ImagePlus.COLOR_RGB == type) {
Utils.log("WARNING: ignoring alpha masks for 'use original images' and 'RGB color' options");
snapshot = Patch.makeFlatImage(type, layer, srcRect, scale, (ArrayList<Patch>) (List) layer.getDisplayables(Patch.class, true), Color.black, true);
} else if (ImagePlus.GRAY8 == type) {
// Respect alpha masks and display range:
Utils.log("WARNING: ignoring scale for 'use original images' and '8-bit' options");
snapshot = ExportUnsignedShort.makeFlatImage((ArrayList<Patch>) (List) layer.getDisplayables(Patch.class, true), srcRect, 0).convertToByte(true);
} else {
Utils.log("ERROR: don't know how to generate mipmaps for type '" + type + "'");
cleanUp();
return;
}
int scale_pow = 0;
int n_et = n_edge_tiles;
final ExecutorService exe = Utils.newFixedThreadPool("export-for-web");
final ArrayList<Future<?>> fus = new ArrayList<Future<?>>();
try {
while (n_et >= best[1]) {
final int snapWidth = snapshot.getWidth();
final int snapHeight = snapshot.getHeight();
final ImageProcessor source = snapshot;
for (int row = 0; row < n_et; row++) {
for (int col = 0; col < n_et; col++) {
final String path = new StringBuilder(tile_dir).append(row).append('_').append(col).append('_').append(scale_pow).toString();
final int tileXStart = col * tileSide;
final int tileYStart = row * tileSide;
final int pixelOffset = tileYStart * snapWidth + tileXStart;
fus.add(exe.submit(new Callable<Boolean>() {
@Override
public Boolean call() {
if (ImagePlus.GRAY8 == type) {
final byte[] pixels = (byte[]) source.getPixels();
final byte[] p = new byte[tileSide * tileSide];
for (int y = 0, sourceIndex = pixelOffset; y < tileSide && tileYStart + y < snapHeight; sourceIndex = pixelOffset + y * snapWidth, y++) {
final int offsetL = y * tileSide;
for (int x = 0; x < tileSide && tileXStart + x < snapWidth; sourceIndex++, x++) {
p[offsetL + x] = pixels[sourceIndex];
}
}
return saver.save(new ImagePlus(path, new ByteProcessor(tileSide, tileSide, p, GRAY_LUT)), path);
} else {
final int[] pixels = (int[]) source.getPixels();
final int[] p = new int[tileSide * tileSide];
for (int y = 0, sourceIndex = pixelOffset; y < tileSide && tileYStart + y < snapHeight; sourceIndex = pixelOffset + y * snapWidth, y++) {
final int offsetL = y * tileSide;
for (int x = 0; x < tileSide && tileXStart + x < snapWidth; sourceIndex++, x++) {
p[offsetL + x] = pixels[sourceIndex];
}
}
return saver.save(new ImagePlus(path, new ColorProcessor(tileSide, tileSide, p)), path);
}
}
}));
}
}
//
scale_pow++;
// works as magnification
scale = 1 / Math.pow(2, scale_pow);
n_et /= 2;
//
Utils.wait(fus);
fus.clear();
// Scale snapshot in half with area averaging
final ImageProcessor nextSnapshot;
if (ImagePlus.GRAY8 == type) {
nextSnapshot = new ByteProcessor((int) (srcRect.width * scale), (int) (srcRect.height * scale));
final byte[] p1 = (byte[]) snapshot.getPixels();
final byte[] p2 = (byte[]) nextSnapshot.getPixels();
final int width1 = snapshot.getWidth();
final int width2 = nextSnapshot.getWidth();
final int height2 = nextSnapshot.getHeight();
int i = 0;
for (int y1 = 0, y2 = 0; y2 < height2; y1 += 2, y2++) {
final int offset1a = y1 * width1;
final int offset1b = (y1 + 1) * width1;
for (int x1 = 0, x2 = 0; x2 < width2; x1 += 2, x2++) {
p2[i++] = (byte) (((p1[offset1a + x1] & 0xff) + (p1[offset1a + x1 + 1] & 0xff) + (p1[offset1b + x1] & 0xff) + (p1[offset1b + x1 + 1] & 0xff)) / 4);
}
}
} else {
nextSnapshot = new ColorProcessor((int) (srcRect.width * scale), (int) (srcRect.height * scale));
final int[] p1 = (int[]) snapshot.getPixels();
final int[] p2 = (int[]) nextSnapshot.getPixels();
final int width1 = snapshot.getWidth();
final int width2 = nextSnapshot.getWidth();
final int height2 = nextSnapshot.getHeight();
int i = 0;
for (int y1 = 0, y2 = 0; y2 < height2; y1 += 2, y2++) {
final int offset1a = y1 * width1;
final int offset1b = (y1 + 1) * width1;
for (int x1 = 0, x2 = 0; x2 < width2; x1 += 2, x2++) {
final int ka = p1[offset1a + x1], kb = p1[offset1a + x1 + 1], kc = p1[offset1b + x1], kd = p1[offset1b + x1 + 1];
// Average each channel independently
p2[i++] = (((// red
((ka >> 16) & 0xff) + ((kb >> 16) & 0xff) + ((kc >> 16) & 0xff) + ((kd >> 16) & 0xff)) / 4) << 16) + (((// green
((ka >> 8) & 0xff) + ((kb >> 8) & 0xff) + ((kc >> 8) & 0xff) + ((kd >> 8) & 0xff)) / 4) << 8) + (// blue
(ka & 0xff) + (kb & 0xff) + (kc & 0xff) + (kd & 0xff)) / 4;
}
}
}
// Assign for next iteration
snapshot = nextSnapshot;
// Scale snapshot with a TransformMesh
/*
AffineModel2D aff = new AffineModel2D();
aff.set(0.5f, 0, 0, 0.5f, 0, 0);
ImageProcessor scaledSnapshot = new ByteProcessor((int)(snapshot.getWidth() * scale), (int)(snapshot.getHeight() * scale));
final CoordinateTransformMesh mesh = new CoordinateTransformMesh( aff, 32, snapshot.getWidth(), snapshot.getHeight() );
final mpicbg.ij.TransformMeshMapping<CoordinateTransformMesh> mapping = new mpicbg.ij.TransformMeshMapping<CoordinateTransformMesh>( mesh );
mapping.mapInterpolated(snapshot, scaledSnapshot, Runtime.getRuntime().availableProcessors());
// Assign for next iteration
snapshot = scaledSnapshot;
snapshotPixels = (byte[]) scaledSnapshot.getPixels();
*/
}
} catch (final Throwable t) {
IJError.print(t);
} finally {
exe.shutdown();
}
} else {
// max_scale; // WARNING if scale is different than 1, it will FAIL to set the next scale properly.
double scale = 1;
int scale_pow = 0;
// cached for local modifications in the loop, works as loop controler
int n_et = n_edge_tiles;
while (n_et >= best[1]) {
// best[1] is the minimal root found, i.e. 1,2,3,4,5 from which then powers of two were taken to make up for the edge_length
// 0 < scale <= 1, so no precision lost
final int tile_side = (int) (256 / scale);
for (int row = 0; row < n_et; row++) {
for (int col = 0; col < n_et; col++) {
final int i_tile = row * n_et + col;
Utils.showProgress(i_tile / (double) (n_et * n_et));
if (0 == i_tile % 100) {
// RGB int[] images
releaseToFit(tile_side * tile_side * 4 * 2);
}
if (this.quit) {
cleanUp();
return;
}
final Rectangle tile_src = new // TODO row and col are inverted
Rectangle(// TODO row and col are inverted
srcRect.x + tile_side * row, srcRect.y + tile_side * col, tile_side, // in absolute coords, magnification later.
tile_side);
// crop bounds
if (tile_src.x + tile_src.width > srcRect.x + srcRect.width)
tile_src.width = srcRect.x + srcRect.width - tile_src.x;
if (tile_src.y + tile_src.height > srcRect.y + srcRect.height)
tile_src.height = srcRect.y + srcRect.height - tile_src.y;
// negative tile sizes will be made into black tiles
// (negative dimensions occur for tiles beyond the edges of srcRect, since the grid of tiles has to be of equal number of rows and cols)
// should be row_col_scale, but results in transposed tiles in googlebrains, so I reversed the order.
makeTile(layer, tile_src, scale, c_alphas, type, clazz, new StringBuilder(tile_dir).append(col).append('_').append(row).append('_').append(scale_pow).toString(), saver);
}
}
scale_pow++;
// works as magnification
scale = 1 / Math.pow(2, scale_pow);
n_et /= 2;
}
}
}
}
} catch (final Exception e) {
IJError.print(e);
} finally {
Utils.showProgress(1);
}
cleanUp();
finishedWorking();
}
};
// watcher thread
return Bureaucrat.createAndStart(worker, layers[0].getProject());
}
use of ini.trakem2.display.Tag in project TrakEM2 by trakem2.
the class Layer method exportXML.
@Override
public void exportXML(final StringBuilder sb_body, final String indent, final XMLOptions options) {
final String in = indent + "\t";
// 1 - open tag
sb_body.append(indent).append("<t2_layer oid=\"").append(id).append("\"\n").append(in).append(" thickness=\"").append(thickness).append("\"\n").append(in).append(" z=\"").append(z).append("\"\n");
// TODO this search is linear!
final LayerThing lt = project.findLayerThing(this);
String title;
if (null == lt)
title = null;
else
title = lt.getTitle();
if (null == title)
title = "";
// TODO 'title' should be a property of the Layer, not the LayerThing. Also, the LayerThing should not exist: LayerSet and Layer should be directly presentable in a tree. They are not Things as in "objects of the sample", but rather, structural necessities such as Patch.
sb_body.append(in).append(" title=\"").append(title).append("\"\n");
sb_body.append(indent).append(">\n");
// 2 - export children
if (null != al_displayables) {
for (final Displayable d : al_displayables) {
d.exportXML(sb_body, in, options);
}
}
// 3 - close tag
sb_body.append(indent).append("</t2_layer>\n");
}
Aggregations