use of ini.trakem2.display.Tree in project TrakEM2 by trakem2.
the class Compare method appendAndFork.
/**
* Recursive.
*/
private static void appendAndFork(final ProjectThing parent, Chain chain, HashSet<ProjectThing> hs_c_done, final ArrayList<Chain> chains, final LayerSet ls, final Pattern exclude) throws Exception {
if (null != exclude && exclude.matcher(parent.getTitle()).matches()) {
Utils.logAll("Excluding node " + parent + " with title " + parent.getTitle() + ", and all its children nodes.");
return;
}
final ArrayList<ProjectThing> children = parent.getChildren();
if (null == children)
return;
if (null == hs_c_done)
hs_c_done = new HashSet<ProjectThing>();
for (final ProjectThing child : children) {
if (hs_c_done.contains(child))
continue;
if (null != exclude && exclude.matcher(child.getTitle()).matches()) {
Utils.log2("Excluding child " + child + " with title " + child.getTitle());
continue;
}
hs_c_done.add(child);
if (child.getObject() instanceof Line3D) {
final Line3D pipe = (Line3D) child.getObject();
// not from the same LayerSet, maybe from a nested one.
if (!pipe.getLayerSet().equals(ls) || pipe.length() < 2)
continue;
if (null == chain) {
chain = new Chain(pipe);
chains.add(chain);
} else {
chain.append(pipe);
}
// find other children in the parent who contain children with child pipes
boolean first = true;
final Chain base = chain.duplicate();
for (final ProjectThing c : children) {
// already visited
if (hs_c_done.contains(c))
continue;
// c is at the same tree level as child (which contains a pipe directly)
final ArrayList<Line3D> child_pipes = c.findChildrenOfType(Line3D.class);
if (child_pipes.size() > 0) {
Chain ca;
if (first) {
// just append
ca = chain;
first = false;
} else {
// otherwise make a copy to branch out
// can't duplicate from chain itself, because it would have the previous child added to it.
ca = base.duplicate();
chains.add(ca);
}
appendAndFork(c, ca, hs_c_done, chains, ls, exclude);
}
}
// pipe wrapping ProjectThing objects cannot have any children
continue;
}
// if it does not have direct pipe children, cut chain - but keep inspecting
if (0 == child.findChildrenOfType(Line3D.class).size()) {
chain = null;
}
// inspect others down the unvisited tree nodes
appendAndFork(child, chain, hs_c_done, chains, ls, exclude);
}
}
use of ini.trakem2.display.Tree in project TrakEM2 by trakem2.
the class Project method createNewProject.
private static Project createNewProject(Loader loader, boolean ask_for_template, TemplateThing template_root, boolean clone_ids) {
Project project = new Project(loader);
// Utils.log2("ask_for_template: " + ask_for_template);
if (ask_for_template)
template_root = project.loader.askForXMLTemplate(project);
if (null == template_root) {
template_root = new TemplateThing("anything");
} else if (clone_ids) {
// the given template_root belongs to another project from which we are cloning
template_root = template_root.clone(project, true);
}
// else, use the given template_root as is.
// create tree
project.template_tree = new TemplateTree(project, template_root);
project.root_tt = template_root;
// collect unique TemplateThing instances
synchronized (project.ht_unique_tt) {
project.ht_unique_tt.clear();
project.ht_unique_tt.putAll(template_root.getUniqueTypes(new HashMap<String, TemplateThing>()));
}
// add all TemplateThing objects to the database, recursively
if (!clone_ids)
template_root.addToDatabase(project);
// else already done when cloning the root_tt
// create a non-database bound template for the project Thing
TemplateThing project_template = new TemplateThing("project");
project.ht_unique_tt.put("project", project_template);
project_template.addChild(template_root);
// create the project Thing, to be root of the whole project thing tree
try {
project.root_pt = new ProjectThing(project_template, project, project);
} catch (Exception e) {
IJError.print(e);
}
// create the user objects tree
project.project_tree = new ProjectTree(project, project.root_pt);
// create the layer's tree
project.createLayerTemplates();
// initialized with default values, and null parent to signal 'root'
project.layer_set = new LayerSet(project, "Top Level", 0, 0, null, 2048, 2048);
try {
project.root_lt = new LayerThing(Project.layer_set_template, project, project.layer_set);
project.layer_tree = new LayerTree(project, project.root_lt);
} catch (Exception e) {
project.remove();
IJError.print(e);
}
// create the project control window, containing the trees in a double JSplitPane
// beware that this call is asynchronous, dispatched by the SwingUtilities.invokeLater to avoid havok with Swing components.
ControlWindow.add(project, project.template_tree, project.project_tree, project.layer_tree);
// register
al_open_projects.add(project);
return project;
}
use of ini.trakem2.display.Tree in project TrakEM2 by trakem2.
the class Compare method reliabilityAnalysis.
public static final Bureaucrat reliabilityAnalysis(final String[] ignore, final boolean output_arff, final boolean weka_classify, final boolean show_dialog, final double delta, final double wi, final double wd, final double wm) {
// gather all open projects
final Project[] p = Project.getProjects().toArray(new Project[0]);
final Worker worker = new Worker("Reliability by name") {
@Override
public void run() {
startedWorking();
try {
final CATAParameters cp = new CATAParameters();
cp.delta = delta;
if (show_dialog && !cp.setup(false, null, false, false)) {
finishedWorking();
return;
}
Object[] ob = gatherChains(p, cp, ignore);
final ArrayList<Chain> chains = (ArrayList<Chain>) ob[0];
// to keep track of each project's chains
final ArrayList[] p_chains = (ArrayList[]) ob[1];
ob = null;
if (null == chains) {
finishedWorking();
return;
}
// For each pipe in a brain:
// - score against all other brains in which that pipe name exists,
// - record the score position within that brain.
//
final ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// for each individual lineage:
final TreeMap<String, ArrayList<Integer>> indices = new TreeMap<String, ArrayList<Integer>>();
final ArrayList<CITuple> cin = new ArrayList<CITuple>();
// for each family:
final TreeMap<String, ArrayList<Integer>> indices_f = new TreeMap<String, ArrayList<Integer>>();
final ArrayList<CITuple> cin_f = new ArrayList<CITuple>();
final ArrayList<Future> fus = new ArrayList<Future>();
// For neural network analysis:
final StringBuilder arff = output_arff ? new StringBuilder("@RELATION Lineages\n\n") : null;
if (output_arff) {
arff.append("@ATTRIBUTE APD NUMERIC\n");
arff.append("@ATTRIBUTE CPD NUMERIC\n");
arff.append("@ATTRIBUTE STD NUMERIC\n");
arff.append("@ATTRIBUTE MPD NUMERIC\n");
arff.append("@ATTRIBUTE PM NUMERIC\n");
arff.append("@ATTRIBUTE LEV NUMERIC\n");
arff.append("@ATTRIBUTE SIM NUMERIC\n");
arff.append("@ATTRIBUTE PRX NUMERIC\n");
arff.append("@ATTRIBUTE PRM NUMERIC\n");
// length ratio: len(query) / len(ref)
arff.append("@ATTRIBUTE LR NUMERIC\n");
arff.append("@ATTRIBUTE TR NUMERIC\n");
arff.append("@ATTRIBUTE CLASS {false,true}\n");
arff.append("\n@DATA\n");
}
// Count number of times when decision tree says it's good, versus number of times when it should be good
// observed
final AtomicInteger obs_good = new AtomicInteger(0);
// observed wrong
final AtomicInteger obs_wrong = new AtomicInteger(0);
// expected
final AtomicInteger exp_good = new AtomicInteger(0);
final AtomicInteger exp_bad = new AtomicInteger(0);
final AtomicInteger obs_bad_classified_good_ones = new AtomicInteger(0);
final AtomicInteger obs_well_classified_bad_ones = new AtomicInteger(0);
// inc by one when a lineage to compare is not found at all in the brain that works as reference
final AtomicInteger not_found = new AtomicInteger(0);
final AtomicInteger already_classified = new AtomicInteger(0);
Method classify_ = null;
if (weka_classify) {
try {
classify_ = Class.forName("lineage.LineageClassifier").getDeclaredMethod("classify", new Class[] { double[].class });
} catch (final Exception e) {
IJError.print(e);
}
}
final Method classify = classify_;
// All possible pairs of projects, with repetition (it's not the same, although the pipe pairwise comparison itself will be.)
for (int _i = 0; _i < p_chains.length; _i++) {
final int i = _i;
Utils.log2("Project " + p[i] + " has " + p_chains[i].size() + " chains.");
for (int _j = 0; _j < p_chains.length; _j++) {
final int j = _j;
// skip same project (would have a score of zero, identical.)
if (i == j)
continue;
final String[] titles_j = new String[p_chains[j].size()];
int next = 0;
for (final Chain cj : (ArrayList<Chain>) p_chains[j]) {
final String t = cj.getCellTitle();
titles_j[next++] = t.substring(0, t.indexOf(' '));
}
// families:
final TreeSet<String> ts_families = new TreeSet<String>();
for (int f = 0; f < titles_j.length; f++) {
// extract family name from title: read the first continuous string of capital letters
final String title = titles_j[f];
int u = 0;
for (; u < title.length(); u++) {
if (!Character.isUpperCase(title.charAt(u)))
break;
}
ts_families.add(title.substring(0, u));
}
final ArrayList<String> families = new ArrayList<String>(ts_families);
fus.add(exec.submit(new Callable() {
@Override
public Object call() {
// All chains of one project to all chains of the other:
for (final Chain chain : (ArrayList<Chain>) p_chains[i]) {
final VectorString3D vs1 = chain.vs;
// Prepare title
String title = chain.getCellTitle();
title = title.substring(0, title.indexOf(' '));
// check if the other project j contains a chain of name chain.getCellTitle() up to the space.
int title_index = -1;
for (int k = 0; k < titles_j.length; k++) {
if (title.equals(titles_j[k])) {
title_index = k;
break;
}
}
if (-1 == title_index) {
Utils.log2(title + " not found in project " + p[j]);
if (weka_classify)
not_found.incrementAndGet();
continue;
}
// should be there:
if (weka_classify) {
exp_good.incrementAndGet();
exp_bad.addAndGet(titles_j.length - 1);
}
final ArrayList<ChainMatch> list = new ArrayList<ChainMatch>();
// extract family name from title: read the first continuous string of capital letters
int u = 0;
for (; u < title.length(); u++) {
if (!Character.isUpperCase(title.charAt(u)))
break;
}
final String family_name = title.substring(0, u);
String last_classify = null;
int g = 0;
for (final Chain cj : (ArrayList<Chain>) p_chains[j]) {
final VectorString3D vs2 = cj.vs;
final Object[] ob = findBestMatch(vs1, vs2, cp.delta, cp.skip_ends, cp.max_mut, cp.min_chunk, cp.distance_type, cp.direct, cp.substring_matching, wi, wd, wm);
final Editions ed = (Editions) ob[0];
final double[] stats = ed.getStatistics(cp.skip_ends, cp.max_mut, cp.min_chunk, cp.score_mut_only);
final ChainMatch cm = new ChainMatch(cj, null, ed, stats, score(ed.getSimilarity(), ed.getDistance(), stats[3], Compare.W));
cm.title = titles_j[g];
list.add(cm);
g++;
if (weka_classify) {
// from decision tree: is it good?
final double[] param = new double[11];
for (int p = 0; p < stats.length; p++) param[p] = stats[p];
try {
if (((Boolean) classify.invoke(null, param)).booleanValue()) {
if (null != last_classify) {
Utils.log2("ALREADY CLASSIFIED " + title + " as " + last_classify + " (now: " + cm.title + " )");
already_classified.incrementAndGet();
}
last_classify = cm.title;
if (title.equals(cm.title)) {
obs_good.incrementAndGet();
} else {
Utils.log2("WRONG CLASSIFICATION of " + title + " as " + cm.title);
obs_wrong.incrementAndGet();
}
} else {
if (title.equals(cm.title)) {
obs_bad_classified_good_ones.incrementAndGet();
} else {
obs_well_classified_bad_ones.incrementAndGet();
}
}
} catch (final Exception ee) {
IJError.print(ee);
}
}
}
// sort scores:
Compare.sortMatches(list, cp.distance_type, cp.distance_type_2, cp.min_matches);
if (output_arff) {
// Take top 8 and put them into training set for WEKA in arff format
for (int h = 0; h < 8; h++) {
final ChainMatch cm = list.get(h);
final StringBuilder sb = new StringBuilder();
sb.append(cm.phys_dist).append(',').append(cm.cum_phys_dist).append(',').append(cm.stdDev).append(',').append(cm.median).append(',').append(cm.prop_mut).append(',').append(cm.ed.getDistance()).append(',').append(cm.seq_sim).append(',').append(cm.proximity).append(',').append(cm.proximity_mut).append(',').append(cm.prop_len).append(',').append(cm.tortuosity_ratio).append(',').append(title.equals(cm.title)).append(// append('-').append(cm.title.startsWith(family_name)).append('\n');
'\n');
synchronized (arff) {
arff.append(sb);
}
}
}
// record scoring index
int f = 0;
boolean found_specific = false;
boolean found_family = false;
for (final ChainMatch cm : list) {
// Exact match: for each individual lineage
if (!found_specific && title.equals(cm.title)) {
synchronized (indices) {
ArrayList<Integer> al = indices.get(title);
if (null == al) {
al = new ArrayList<Integer>();
indices.put(title, al);
// so I can keep a list of chains sorted by name
cin.add(new CITuple(title, chain, al));
}
al.add(f);
}
found_specific = true;
}
if (!found_family && cm.title.startsWith(family_name)) {
synchronized (indices_f) {
ArrayList<Integer> al = indices_f.get(family_name);
if (null == al) {
al = new ArrayList<Integer>();
indices_f.put(family_name, al);
cin_f.add(new CITuple(family_name, chain, al));
}
al.add(f);
}
found_family = true;
}
if (found_specific && found_family) {
break;
}
//
f++;
}
if (!found_specific) {
Utils.log2("NOT FOUND any match for " + title + " within a list of size " + list.size() + ", in project " + chain.getRoot().getProject());
}
}
return null;
}
}));
}
}
for (final Future fu : fus) {
try {
fu.get();
} catch (final Exception e) {
IJError.print(e);
}
}
exec.shutdownNow();
if (weka_classify) {
// so stateful ... it's a sin.
try {
Class.forName("lineage.LineageClassifier").getDeclaredMethod("flush", new Class[] {}).invoke(null, new Object[] {});
} catch (final Exception e) {
IJError.print(e);
}
}
// export ARFF for neural network training
if (output_arff) {
Utils.saveToFile(new File(System.getProperty("user.dir") + "/lineages.arff"), arff.toString());
}
// Show the results from indices map
final StringBuilder sb = new StringBuilder();
// scoring index vs count of occurrences
final TreeMap<Integer, Integer> sum = new TreeMap<Integer, Integer>();
// best scoring index of best family member vs count of ocurrences
final TreeMap<Integer, Integer> sum_f = new TreeMap<Integer, Integer>();
// scoring index vs count of ocurrences, within each family
final TreeMap<String, TreeMap<Integer, Integer>> sum_fw = new TreeMap<String, TreeMap<Integer, Integer>>();
// From collected data, several kinds of results:
// - a list of how well each chain scores: its index position in the sorted list of scores of one to many.
// - a list of how well each chain scores relative to family: the lowest (best) index position of a lineage of the same family in the sorted list of scores.
sb.append("List of scoring indices for each (starting at index 1, aka best possible score):\n");
for (final CITuple ci : cin) {
// sort indices in place
Collections.sort(ci.list);
// count occurrences of each scoring index
// lowest possible index
int last = 0;
int count = 1;
for (final int i : ci.list) {
if (last == i)
count++;
else {
sb.append(ci.title).append(' ').append(last + 1).append(' ').append(count).append('\n');
// reset
last = i;
count = 1;
}
// global count of occurrences
final Integer oi = new Integer(i);
sum.put(oi, (sum.containsKey(oi) ? sum.get(oi) : 0) + 1);
// Same thing but not for all lineages, but only for lineages within a family:
// extract family name from title: read the first continuous string of capital letters
int u = 0;
for (; u < ci.title.length(); u++) {
if (!Character.isUpperCase(ci.title.charAt(u)))
break;
}
final String family_name = ci.title.substring(0, u);
TreeMap<Integer, Integer> sfw = sum_fw.get(family_name);
if (null == sfw) {
sfw = new TreeMap<Integer, Integer>();
sum_fw.put(family_name, sfw);
}
sfw.put(oi, (sfw.containsKey(oi) ? sfw.get(oi) : 0) + 1);
}
if (0 != count)
sb.append(ci.title).append(' ').append(last + 1).append(' ').append(count).append('\n');
// find the very-off ones:
if (last > 6) {
Utils.log2("BAD index " + last + " for chain " + ci.title + " " + ci.chain.getRoot() + " of project " + ci.chain.getRoot().getProject());
}
}
sb.append("===============================\n");
// / family score:
for (final CITuple ci : cin_f) {
// sort indices in place
Collections.sort(ci.list);
// count occurrences of each scoring index
// lowest possible index
int last = 0;
int count = 1;
for (final int i : ci.list) {
if (last == i)
count++;
else {
// reset
last = i;
count = 1;
}
// global count of occurrences
final Integer oi = new Integer(i);
sum_f.put(oi, (sum_f.containsKey(oi) ? sum_f.get(oi) : 0) + 1);
}
}
sb.append("===============================\n");
// - a summarizing histogram that collects how many 1st, how many 2nd, etc. in total, normalized to total number of one-to-many matches performed (i.e. the number of scoring indices recorded.)
//
{
sb.append("Global count of index ocurrences:\n");
int total = 0;
int top2 = 0;
int top5 = 0;
for (final Map.Entry<Integer, Integer> e : sum.entrySet()) {
sb.append(e.getKey()).append(' ').append(e.getValue()).append('\n');
total += e.getValue();
if (e.getKey() < 2)
top2 += e.getValue();
if (e.getKey() < 5)
top5 += e.getValue();
}
sb.append("total: ").append(total).append('\n');
sb.append("top1: ").append(sum.get(sum.firstKey()) / (float) total).append('\n');
sb.append("top2: ").append(top2 / (float) total).append('\n');
sb.append("top5: ").append(top5 / (float) total).append('\n');
sb.append("===============================\n");
}
sb.append("Family-wise count of index ocurrences:\n");
for (final Map.Entry<String, TreeMap<Integer, Integer>> fe : sum_fw.entrySet()) {
int total = 0;
int top5 = 0;
for (final Map.Entry<Integer, Integer> e : fe.getValue().entrySet()) {
sb.append(fe.getKey()).append(' ').append(e.getKey()).append(' ').append(e.getValue()).append('\n');
total += e.getValue();
if (e.getKey() < 5)
top5 += e.getValue();
}
sb.append("total: ").append(total).append('\n');
sb.append("top1: ").append(fe.getValue().get(fe.getValue().firstKey()) / (float) total).append('\n');
sb.append("top5: ").append(top5 / (float) total).append('\n');
}
sb.append("===============================\n");
// - the percent of first score being the correct one:
double first = 0;
double first_5 = 0;
double all = 0;
for (final Map.Entry<Integer, Integer> e : sum.entrySet()) {
final int k = e.getKey();
final int a = e.getValue();
all += a;
if (0 == k)
first = a;
if (k < 5)
first_5 += a;
}
// STORE
this.result = new double[] { // Top one ratio
first / all, // Top 5 ratio
first_5 / all };
sb.append("Global count of index occurrences family-wise:\n");
for (final Map.Entry<Integer, Integer> e : sum_f.entrySet()) {
sb.append(e.getKey()).append(' ').append(e.getValue()).append('\n');
}
sb.append("===============================\n");
// - a summarizing histogram of how well each chain scores (4/4, 3/4, 2/4, 1/4, 0/4 only for those that have 4 homologous members.)
// Must consider that there are 5 projects taken in pairs with repetition.
sb.append("A summarizing histogram of how well each chain scores, for those that have 4 homologous members. It's the number of 1st scores (zeroes) versus the total number of scores:\n");
// First, classify them in having 4, 3, 2, 1
// For 5 brains: 5! / (5-2)! = 5 * 4 = 20 --- 5 elements taken in groups of 2, where order matters
// For 4 brains: 4! / (4-2)! = 4 * 3 = 12
// For 3 brains: 3! / (3-2)! = 3 * 2 = 6;
final TreeMap<Integer, ArrayList<String>> hsc = new TreeMap<Integer, ArrayList<String>>();
for (final CITuple ci : cin) {
final int size = ci.list.size();
ArrayList<String> al = hsc.get(size);
if (null == al) {
al = new ArrayList<String>();
hsc.put(size, al);
}
// Count the number of 0s -- top scoring
int count = 0;
for (final Integer i : ci.list) {
if (0 == i)
count++;
else
break;
}
al.add(new StringBuffer(ci.title).append(" =").append(count).append('/').append(ci.list.size()).append('\n').toString());
}
// Then just print:
for (final Map.Entry<Integer, ArrayList<String>> e : hsc.entrySet()) {
sb.append("For ").append(e.getKey()).append(" matches:\n");
for (final String s : e.getValue()) sb.append(s);
}
sb.append("=========================\n");
// Family-wise, count the number of zeros per family:
sb.append("Number of top scoring per family:\n");
final TreeMap<String, String> family_scores = new TreeMap<String, String>();
for (final CITuple ci : cin_f) {
int count = 0;
for (final Integer i : ci.list) {
if (0 == i)
count++;
else
// ci.list is sorted
break;
}
family_scores.put(ci.title, new StringBuilder().append(ci.title).append(" =").append(count).append('/').append(ci.list.size()).append('\n').toString());
}
// Now print sorted by family name:
for (final String s : family_scores.values()) {
sb.append(s);
}
sb.append("=========================\n");
if (weka_classify) {
sb.append("Decision tree:\n");
sb.append("Expected good matches: " + exp_good.get() + "\n");
sb.append("Expected bad matches: " + exp_bad.get() + "\n");
sb.append("Observed good matches: " + obs_good.get() + "\n");
sb.append("Observed bad matches: " + obs_wrong.get() + "\n");
sb.append("Observed well classified bad ones: " + obs_well_classified_bad_ones.get() + "\n");
sb.append("Observed bad classified good ones: " + obs_bad_classified_good_ones.get() + "\n");
sb.append("Not found, so skipped: " + not_found.get() + "\n");
sb.append("Already classified: " + already_classified.get() + "\n");
sb.append("=========================\n");
}
if (output_arff) {
Utils.log(sb.toString());
} else {
Utils.log2(sb.toString());
}
} catch (final Exception e) {
e.printStackTrace();
} finally {
finishedWorking();
}
}
};
return Bureaucrat.createAndStart(worker, p);
}
use of ini.trakem2.display.Tree in project TrakEM2 by trakem2.
the class DisplayCanvas method keyPressed.
@Override
public void keyPressed(final KeyEvent ke) {
final Displayable active = display.getActive();
if (null != freehandProfile && ProjectToolbar.getToolId() == ProjectToolbar.PENCIL && ke.getKeyCode() == KeyEvent.VK_ESCAPE && null != freehandProfile) {
freehandProfile.abort();
ke.consume();
return;
}
final int keyCode = ke.getKeyCode();
try {
// Enable tagging system for any alphanumeric key:
if (!input_disabled && null != active && active instanceof Tree<?> && ProjectToolbar.isDataEditTool(ProjectToolbar.getToolId())) {
if (tagging) {
if (KeyEvent.VK_0 == keyCode && KeyEvent.VK_0 != last_keyCode) {
// do nothing: keep tagging as true
} else {
// last step of tagging: a char after t or after t and a number (and the char itself can be a number)
tagging = false;
}
active.keyPressed(ke);
return;
} else if (KeyEvent.VK_T == keyCode) {
tagging = true;
active.keyPressed(ke);
return;
}
}
} finally {
last_keyCode = keyCode;
}
tagging = false;
if (ke.isConsumed())
return;
if (!zoom_and_pan) {
if (KeyEvent.VK_ESCAPE == keyCode) {
cancelAnimations();
}
return;
}
final int keyChar = ke.getKeyChar();
boolean used = false;
switch(keyChar) {
case '+':
case '=':
zoomIn();
used = true;
break;
case '-':
case '_':
zoomOut();
used = true;
break;
default:
break;
}
if (used) {
// otherwise ImageJ would use it!
ke.consume();
return;
}
if (input_disabled) {
if (KeyEvent.VK_ESCAPE == keyCode) {
// cancel last job if any
if (Utils.checkYN("Really cancel job?")) {
display.getProject().getLoader().quitJob(null);
display.repairGUI();
}
}
ke.consume();
// only zoom is enabled, above
return;
}
if (KeyEvent.VK_S == keyCode && 0 == ke.getModifiers() && display.getProject().getLoader().isAsynchronous()) {
display.getProject().getLoader().saveTask(display.getProject(), "Save");
ke.consume();
return;
} else if (KeyEvent.VK_F == keyCode && Utils.isControlDown(ke)) {
Search.showWindow();
ke.consume();
return;
}
// if display is not read-only, check for other keys:
switch(keyChar) {
case '<':
case // select next Layer up
',':
// repaints as well
display.previousLayer(ke.getModifiers());
ke.consume();
return;
case '>':
case // select next Layer down
'.':
display.nextLayer(ke.getModifiers());
ke.consume();
return;
}
if (null == active && null != imp.getRoi() && KeyEvent.VK_A != keyCode) {
// control+a and a roi should select under roi
IJ.getInstance().keyPressed(ke);
return;
}
// end here if display is read-only
if (display.isReadOnly()) {
ke.consume();
display.repaintAll();
return;
}
if (KeyEvent.VK_ENTER == keyCode) {
if (isTransforming()) {
applyTransform();
ke.consume();
return;
} else {
IJ.getInstance().toFront();
ke.consume();
return;
}
}
// check preconditions (or the keys are meaningless). Allow 'enter' to
// bring forward the ImageJ window, and 'v' to paste a patch.
/*if (null == active && KeyEvent.VK_ENTER != keyCode && KeyEvent.VK_V != keyCode && KeyEvent) {
return;
}*/
final Layer layer = display.getLayer();
final int mod = ke.getModifiers();
switch(keyCode) {
case KeyEvent.VK_COMMA:
case // select next Layer up
0xbc:
display.nextLayer(ke.getModifiers());
break;
case KeyEvent.VK_PERIOD:
case // select next Layer down
0xbe:
display.previousLayer(ke.getModifiers());
break;
case KeyEvent.VK_Z:
// UNDO: shift+z or ctrl+z
if (0 == (mod ^ Event.SHIFT_MASK) || 0 == (mod ^ Utils.getControlModifier())) {
Bureaucrat.createAndStart(new Worker.Task("Undo") {
@Override
public void exec() {
if (isTransforming())
display.getMode().undoOneStep();
else
display.getLayerSet().undoOneStep();
Display.repaint(display.getLayerSet());
}
}, display.getProject());
ke.consume();
// REDO: alt+z or ctrl+shift+z
} else if (0 == (mod ^ Event.ALT_MASK) || 0 == (mod ^ (Event.SHIFT_MASK | Utils.getControlModifier()))) {
Bureaucrat.createAndStart(new Worker.Task("Redo") {
@Override
public void exec() {
if (isTransforming())
display.getMode().redoOneStep();
else
display.getLayerSet().redoOneStep();
Display.repaint(display.getLayerSet());
}
}, display.getProject());
ke.consume();
}
// else, the 'z' command restores the image using ImageJ internal undo
break;
case KeyEvent.VK_T:
// Enable with any tool to the left of the PENCIL
if (null != active && !isTransforming() && ProjectToolbar.getToolId() < ProjectToolbar.PENCIL) {
ProjectToolbar.setTool(ProjectToolbar.SELECT);
if (0 == ke.getModifiers()) {
display.setMode(new AffineTransformMode(display));
} else if (Event.SHIFT_MASK == ke.getModifiers()) {
for (final Displayable d : display.getSelection().getSelected()) {
if (d.isLinked()) {
Utils.showMessage("Can't enter manual non-linear transformation mode:\nat least one image is linked.");
return;
}
}
display.setMode(new NonLinearTransformMode(display));
}
ke.consume();
}
// else, let ImageJ grab the ROI into the Manager, if any
break;
case KeyEvent.VK_A:
if (0 == (ke.getModifiers() ^ Utils.getControlModifier())) {
final Roi roi = getFakeImagePlus().getRoi();
if (null != roi)
display.getSelection().selectAll(roi, true);
else
display.getSelection().selectAllVisible();
Display.repaint(display.getLayer(), display.getSelection().getBox(), 0);
ke.consume();
// INSIDE the 'if' block, so that it can bleed to the default block which forwards to active!
break;
} else if (null != active) {
active.keyPressed(ke);
if (ke.isConsumed())
break;
// TODO this is just a hack really. Should just fall back to default switch option.
// The whole keyPressed method needs revision: should not break from it when not using the key.
}
break;
case // cancel transformation
KeyEvent.VK_ESCAPE:
if (isTransforming())
cancelTransform();
else {
// deselect
display.select(null);
// repaint out the brush if present
if (ProjectToolbar.BRUSH == ProjectToolbar.getToolId()) {
repaint(old_brush_box, 0);
}
}
ke.consume();
break;
case KeyEvent.VK_SPACE:
if (0 == ke.getModifiers()) {
if (null != active) {
invalidateVolatile();
if (Math.abs(active.getAlpha() - 0.5f) > 0.001f)
active.setAlpha(0.5f);
else
active.setAlpha(1.0f);
display.setTransparencySlider(active.getAlpha());
Display.repaint();
ke.consume();
}
} else {
// ;)
final int kem = ke.getModifiers();
if (0 != (kem & KeyEvent.SHIFT_MASK) && 0 != (kem & KeyEvent.ALT_MASK) && 0 != (kem & KeyEvent.CTRL_MASK)) {
Utils.showMessage("A mathematician, like a painter or poet,\nis a maker of patterns.\nIf his patterns are more permanent than theirs,\nit is because they are made with ideas\n \nG. H. Hardy.");
ke.consume();
}
}
break;
case KeyEvent.VK_S:
if (ke.isAltDown()) {
snapping = true;
ke.consume();
} else if (dragging) {
// ignore improper 's' that open ImageJ's save dialog (linux problem ... in macosx, a single dialog opens with lots of 'ssss...' in the text field)
ke.consume();
}
break;
case KeyEvent.VK_H:
handleHide(ke);
ke.consume();
break;
case KeyEvent.VK_J:
if (!display.getSelection().isEmpty()) {
display.adjustMinAndMaxGUI();
ke.consume();
}
break;
case KeyEvent.VK_F1:
case KeyEvent.VK_F2:
case KeyEvent.VK_F3:
case KeyEvent.VK_F4:
case KeyEvent.VK_F5:
case KeyEvent.VK_F6:
case KeyEvent.VK_F7:
case KeyEvent.VK_F8:
case KeyEvent.VK_F9:
case KeyEvent.VK_F10:
case KeyEvent.VK_F11:
case KeyEvent.VK_F12:
ProjectToolbar.keyPressed(ke);
ke.consume();
break;
case KeyEvent.VK_M:
if (0 == ke.getModifiers() && ProjectToolbar.getToolId() == ProjectToolbar.SELECT) {
display.getSelection().measure();
ke.consume();
}
break;
}
switch(keyChar) {
case ':':
case ';':
if (null != active && active instanceof ZDisplayable) {
if (null != display.getProject().getProjectTree().tryAddNewConnector(active, true)) {
ProjectToolbar.setTool(ProjectToolbar.PEN);
}
ke.consume();
}
break;
}
if (ke.isConsumed())
return;
if (null != active) {
if (display.getMode().getClass() == DefaultMode.class) {
active.keyPressed(ke);
}
if (ke.isConsumed())
return;
}
// Else:
switch(keyCode) {
case KeyEvent.VK_G:
if (browseToNodeLayer(ke.isShiftDown())) {
ke.consume();
}
break;
case KeyEvent.VK_I:
if (ke.isAltDown()) {
if (ke.isShiftDown())
display.importImage();
else
display.importNextImage();
ke.consume();
}
break;
case // as in Inkscape
KeyEvent.VK_PAGE_UP:
if (null != active) {
update_graphics = true;
layer.getParent().addUndoMoveStep(active);
layer.getParent().move(LayerSet.UP, active);
layer.getParent().addUndoMoveStep(active);
Display.repaint(layer, active, 5);
Display.updatePanelIndex(layer, active);
ke.consume();
}
break;
case // as in Inkscape
KeyEvent.VK_PAGE_DOWN:
if (null != active) {
update_graphics = true;
layer.getParent().addUndoMoveStep(active);
layer.getParent().move(LayerSet.DOWN, active);
layer.getParent().addUndoMoveStep(active);
Display.repaint(layer, active, 5);
Display.updatePanelIndex(layer, active);
ke.consume();
}
break;
case // as in Inkscape
KeyEvent.VK_HOME:
if (null != active) {
update_graphics = true;
layer.getParent().addUndoMoveStep(active);
layer.getParent().move(LayerSet.TOP, active);
layer.getParent().addUndoMoveStep(active);
Display.repaint(layer, active, 5);
Display.updatePanelIndex(layer, active);
ke.consume();
}
break;
case // as in Inkscape
KeyEvent.VK_END:
if (null != active) {
update_graphics = true;
layer.getParent().addUndoMoveStep(active);
layer.getParent().move(LayerSet.BOTTOM, active);
layer.getParent().addUndoMoveStep(active);
Display.repaint(layer, active, 5);
Display.updatePanelIndex(layer, active);
ke.consume();
}
break;
case KeyEvent.VK_V:
if (0 == ke.getModifiers()) {
if (null == active || active.getClass() == Patch.class) {
// paste a new image
final ImagePlus clipboard = ImagePlus.getClipboard();
if (null != clipboard) {
final ImagePlus imp = new ImagePlus(clipboard.getTitle() + "_" + System.currentTimeMillis(), clipboard.getProcessor().crop());
final Object info = clipboard.getProperty("Info");
if (null != info)
imp.setProperty("Info", (String) info);
final double x = srcRect.x + srcRect.width / 2 - imp.getWidth() / 2;
final double y = srcRect.y + srcRect.height / 2 - imp.getHeight() / 2;
// save the image somewhere:
final Patch pa = display.getProject().getLoader().addNewImage(imp, x, y);
display.getLayer().add(pa);
ke.consume();
}
// TODO there isn't much ImageJ integration in the pasting. Can't paste to a selected image, for example.
} else {
// Each type may know how to paste data from the copy buffer into itself:
active.keyPressed(ke);
ke.consume();
}
}
break;
case KeyEvent.VK_P:
if (0 == ke.getModifiers()) {
display.getLayerSet().color_cues = !display.getLayerSet().color_cues;
Display.repaint(display.getLayerSet());
ke.consume();
}
break;
case KeyEvent.VK_F:
if (0 == (ke.getModifiers() ^ KeyEvent.SHIFT_MASK)) {
// toggle visibility of tags
display.getLayerSet().paint_tags = !display.getLayerSet().paint_tags;
Display.repaint();
ke.consume();
} else if (0 == (ke.getModifiers() ^ KeyEvent.ALT_MASK)) {
// toggle visibility of edge arrows
display.getLayerSet().paint_arrows = !display.getLayerSet().paint_arrows;
Display.repaint();
ke.consume();
} else if (0 == ke.getModifiers()) {
// toggle visibility of edge confidence boxes
display.getLayerSet().paint_edge_confidence_boxes = !display.getLayerSet().paint_edge_confidence_boxes;
Display.repaint();
ke.consume();
}
break;
case KeyEvent.VK_DELETE:
if (0 == ke.getModifiers()) {
display.getSelection().deleteAll();
}
break;
case KeyEvent.VK_B:
if (0 == ke.getModifiers() && null != active && active.getClass() == Profile.class) {
display.duplicateLinkAndSendTo(active, 0, active.getLayer().getParent().previous(layer));
ke.consume();
}
break;
case KeyEvent.VK_N:
if (0 == ke.getModifiers() && null != active && active.getClass() == Profile.class) {
display.duplicateLinkAndSendTo(active, 1, active.getLayer().getParent().next(layer));
ke.consume();
}
break;
case KeyEvent.VK_1:
case KeyEvent.VK_2:
case KeyEvent.VK_3:
case KeyEvent.VK_4:
case KeyEvent.VK_5:
case KeyEvent.VK_6:
case KeyEvent.VK_7:
case KeyEvent.VK_8:
case KeyEvent.VK_9:
// run a plugin, if any
if (null != Utils.launchTPlugIn(ke, "Display", display.getProject(), display.getActive())) {
ke.consume();
break;
}
}
if (!(keyCode == KeyEvent.VK_UNDEFINED || keyChar == KeyEvent.CHAR_UNDEFINED) && !ke.isConsumed() && null != active && active instanceof Patch) {
// TODO should allow forwarding for all, not just Patch
// forward to ImageJ for a final try
IJ.getInstance().keyPressed(ke);
repaint(active, 5);
ke.consume();
}
// Utils.log2("keyCode, keyChar: " + keyCode + ", " + keyChar + " ref: " + KeyEvent.VK_UNDEFINED + ", " + KeyEvent.CHAR_UNDEFINED);
}
use of ini.trakem2.display.Tree 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