public TreeNodeUpdater(Project mpsProject) { myProject = mpsProject; myTimer = new Timer("ProjectPane Tree Update Thread", 500) { @Override protected void onTimer() throws InterruptedException { process(); } }; myTimer.setTakeInitialDelay(true); }
final void process() { if (!myGuard.tryAcquire()) { return; } try { do { int batchProcessMax = 20; // do not process more than X at once, not to block any write actions nor UI thread // for too long final ArrayList<Pair<MPSTreeNode, NodeUpdate>> updates = new ArrayList<Pair<MPSTreeNode, NodeUpdate>>(batchProcessMax); Pair<MPSTreeNode, NodeUpdate> u; while ((u = myUpdates.poll()) != null && batchProcessMax > 0) { if (u.o1.getTree() == null) { // no reason to update element which is not in the tree continue; } updates.add(u); batchProcessMax--; } if (updates.isEmpty()) { break; } myProject .getModelAccess() .runReadInEDT( new Runnable() { @Override public void run() { final HashSet<MPSTreeNode> toRefresh = new HashSet<MPSTreeNode>(); for (Pair<MPSTreeNode, NodeUpdate> next : updates) { MPSTreeNode node = next.o1; if (node.getTree() == null) { // once again, no reason to update element which is not in the tree continue; } next.o2.update(node); toRefresh.add(node); } for (MPSTreeNode node : toRefresh) { node.updateNodePresentationInTree(); } } }); } while (!myUpdates.isEmpty()); myTimer.suspend(); } finally { myGuard.release(); } }
public void addUpdate(MPSTreeNode node, NodeUpdate r) { if (!r.needed(node)) return; myUpdates.add(new Pair<MPSTreeNode, NodeUpdate>(node, r)); myTimer.start(); // sic(!), resume() or restart() force timer into 'running' state, effectively // skipping initial delay }