Skip to content

Commit

Permalink
fixed items order in a JTree by some really ugly coding
Browse files Browse the repository at this point in the history
  • Loading branch information
Acerbic committed Oct 2, 2012
1 parent 350bee2 commit df8c711
Show file tree
Hide file tree
Showing 8 changed files with 798 additions and 84 deletions.
215 changes: 149 additions & 66 deletions src/dloader/GUI.java
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Collection; import java.util.Collection;
import java.util.Deque; import java.util.Deque;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;


import javax.swing.border.BevelBorder; import javax.swing.border.BevelBorder;
Expand Down Expand Up @@ -46,28 +47,28 @@ public class GUI extends JFrame {
private MyWorker newWorker; private MyWorker newWorker;




@SuppressWarnings("serial") // @SuppressWarnings("serial")
class MyRenderer extends DefaultTreeCellRenderer { // class MyRenderer extends DefaultTreeCellRenderer {

//
public Component getTreeCellRendererComponent( // public Component getTreeCellRendererComponent(
JTree tree, // JTree tree,
Object value, // Object value,
boolean sel, // boolean sel,
boolean expanded, // boolean expanded,
boolean leaf, // boolean leaf,
int row, // int row,
boolean hasFocus) { // boolean hasFocus) {

//
super.getTreeCellRendererComponent( // super.getTreeCellRendererComponent(
tree, value, sel, // tree, value, sel,
expanded, leaf, row, // expanded, leaf, row,
hasFocus); // hasFocus);
if (value instanceof DefaultMutableTreeNode) // if (value instanceof DefaultMutableTreeNode)
return this; // return this;
return this; // return this;
} // }

//
} // }


public Thread getEventDispatchThread() { public Thread getEventDispatchThread() {
return eventDispatchThread; return eventDispatchThread;
Expand Down Expand Up @@ -108,7 +109,7 @@ public GUI() throws HeadlessException {
{} {}
} }
)); ));
tree.setCellRenderer(new MyRenderer()); // tree.setCellRenderer(new MyRenderer());
tree.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null)); tree.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));


lblStatus = new JLabel("kkkkss"); lblStatus = new JLabel("kkkkss");
Expand Down Expand Up @@ -239,11 +240,12 @@ public void init() {
} }


private void initPrefetch() { private void initPrefetch() {
lblStatus.setText("Prefetching"); if (newWorker == null) {
if (newWorker == null) lblStatus.setText("Prefetching");
newWorker = new MyWorker(rootPage, JobType.READCACHEPAGES); newWorker = new MyWorker(rootPage, JobType.READCACHEPAGES);
newWorker.execute(); newWorker.execute();
btnPrefetch.setEnabled(false); btnPrefetch.setEnabled(false);
}
} }


private void finishPrefetch() { private void finishPrefetch() {
Expand All @@ -254,11 +256,12 @@ private void finishPrefetch() {
} }


private void initScan() { private void initScan() {
lblStatus.setText("Scanning"); if (newWorker == null) {
if (newWorker == null) lblStatus.setText("Scanning");
newWorker = new MyWorker(rootPage, JobType.UPDATEPAGES); newWorker = new MyWorker(rootPage, JobType.UPDATEPAGES);
newWorker.execute(); newWorker.execute();
btnFetch.setEnabled(false); btnFetch.setEnabled(false);
}
} }


private void finishScan() { private void finishScan() {
Expand All @@ -269,7 +272,7 @@ private void finishScan() {
} }


/** /**
* Receiving message from SwingWorker * Receiving message from MyWorker (SwingWorker)
* @param p - page node to update * @param p - page node to update
* @param message - status info * @param message - status info
* @param value - numeral info * @param value - numeral info
Expand All @@ -291,85 +294,143 @@ else if (!p.getParent().childPages.contains(p))
} }


DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) model.getRoot(); DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) model.getRoot();
for (AbstractPage currentPage: pathToPage) { for (AbstractPage childPage: pathToPage) {
// check if this page exists in the tree // check if this page exists in the parent
DefaultMutableTreeNode child = null; DefaultMutableTreeNode childNode = getNodeOfPage (parentNode, childPage);
boolean found = false;
for (@SuppressWarnings("unchecked") if (childNode == null) {
Enumeration<DefaultMutableTreeNode> children = parent.children(); children.hasMoreElements();) {
child = children.nextElement();
if (currentPage.equals(pageOfNode(child))) {
found = true;
break;
}
}
if (! found) {
// currentPage's node was not found in parent node // currentPage's node was not found in parent node
//TODO: fix elements order in tree....


// add new item under this parent // add new item under this parent
child = new DefaultMutableTreeNode(); childNode = new DefaultMutableTreeNode();
TreeNodePageWrapper childsUserObject = new TreeNodePageWrapper(currentPage, child); TreeNodePageWrapper childsUserObject = new TreeNodePageWrapper(childPage, childNode);
child.setUserObject(childsUserObject); childNode.setUserObject(childsUserObject);

parent.add(child);


if (childPage.getParent() == null)
parentNode.add(childNode); // to the end
else {
int insertionIndex = findInsertionPoint(parentNode, childPage);

if (insertionIndex == -1)
parentNode.add(childNode); // to the end
else
parentNode.insert(childNode, insertionIndex);

}
int[] indices = new int[1]; int[] indices = new int[1];
indices[0] = parent.getIndex(child); indices[0] = parentNode.getIndex(childNode);


// new item's children if any (that way they maintain their order) // new item's children if any (that way they maintain their order)
for (AbstractPage subPage: currentPage.childPages) { for (AbstractPage subPage: childPage.childPages) {
DefaultMutableTreeNode subChild = new DefaultMutableTreeNode(); DefaultMutableTreeNode subChild = new DefaultMutableTreeNode();
subChild.setUserObject(new TreeNodePageWrapper(subPage, subChild)); subChild.setUserObject(new TreeNodePageWrapper(subPage, subChild));
} }
model.nodesWereInserted(parent, indices); //notification to repaint model.nodesWereInserted(parentNode, indices); //notification to repaint


//expand only if not a Track //expand only if not a Track
if (!(childsUserObject.page instanceof Track)) if (!(childsUserObject.page instanceof Track))
tree.expandPath(new TreePath(parent.getPath())); tree.expandPath(new TreePath(parentNode.getPath()));
} }


parent = child; // advance to search next element in our pathToPage parentNode = childNode; // advance to search next element in our pathToPage
} }
// after search is complete, parent points to a DefaultMutableTreeNode // after search is complete, parent points to a DefaultMutableTreeNode
// containing TreeNodePageWrapper containing original p (but now p is different) // containing TreeNodePageWrapper containing original p (but now p is different)


// Reading cache forces reset of page data (children refs), the node branch must be trimmed accordingly // Reading cache/ downloading a page forces reset of page data (children refs),
// the node branch must be trimmed accordingly
if (message.equals("read from cache") || message.equals("read cache failed") if (message.equals("read from cache") || message.equals("read cache failed")
|| message.equals("cache reading failed, submitting download job") || message.equals("cache reading failed, submitting download job")
|| message.equals("download finished") || message.equals("up to date") || message.equals("download finished") || message.equals("up to date")
|| message.equals("download failed") || message.equals("download failed")
) )
trimBranch(parent, model); trimBranch(parentNode, model);


// pass message to the user object and refresh its visual if needed // pass message to the user object and refresh its visual if needed
if (((TreeNodePageWrapper)parent.getUserObject()).update(message, value)) if (((TreeNodePageWrapper)parentNode.getUserObject()).update(message, value))
model.nodeChanged(parent); model.nodeChanged(parentNode);


} }

private int findInsertionPoint(DefaultMutableTreeNode parentNode,
AbstractPage childPage) {
// time to find proper insertion position (assume nodes are ordered same way as pages so far with "skips" probably existing)
// p1 p2 p3 p4 p5 p6
// n1 n2 n3 n4
Iterator<AbstractPage> pageLooker = childPage.getParent().childPages.iterator();
@SuppressWarnings("unchecked")
Enumeration<DefaultMutableTreeNode> nodeLooker = parentNode.children();

// check "DoubleListMatcher.graphml" automaton diagram to understand the following
// *S*
// *A1*
while (nodeLooker.hasMoreElements()) { // *G* exit
DefaultMutableTreeNode currentNode = nodeLooker.nextElement();

// *A2*
if (!pageLooker.hasNext())
break; // *H* an ERROR has happened, since it is supposed to be and an impossible state.
AbstractPage currentPage = pageLooker.next();

// these are B-C-D123-B and B-C-E-B loops
b_loop:
while (! getPageOfNode(currentNode).equals(currentPage)) { // *A2*->*B* check AND *E*->*B* check
// *B*
if (childPage.equals(currentPage)) {
return parentNode.getIndex(currentNode); // *F*
}
// *C*
if (getPageOfNode(parentNode).childPages.contains(getPageOfNode(currentNode))) {
// *D2*
while (pageLooker.hasNext())
currentPage = pageLooker.next();
if (getPageOfNode(currentNode).equals(currentPage))
break b_loop; // -> *A*
// *D3*
if (childPage.equals(currentPage)) {
return parentNode.getIndex(currentNode); // *F*
}
return -1; //*H*
}
else // *E*
if (nodeLooker.hasMoreElements())
currentNode = nodeLooker.nextElement(); //skip one
// -> *B*
else
break; // *G* exit
}
}
// *G*
return -1;
}


/** /**
* Remove branch->children nodes don't correspond to branch->page->children pages * Remove branch->children nodes don't correspond to branch->page->children pages
* and cancel their respective jobs running and scheduled
* O (n*n)
* @param branch - node branch to clean up * @param branch - node branch to clean up
* @param model - reference model * @param model - reference model
*/ */
private void trimBranch(DefaultMutableTreeNode branch, DefaultTreeModel model) { private void trimBranch(DefaultMutableTreeNode branch, DefaultTreeModel model) {
AbstractPage branchPage = pageOfNode(branch); AbstractPage branchPage = getPageOfNode(branch);
Collection<DefaultMutableTreeNode> removeList = new LinkedList<>(); Collection<DefaultMutableTreeNode> removeList = new LinkedList<>();
for (@SuppressWarnings("unchecked") for (@SuppressWarnings("unchecked")
Enumeration<DefaultMutableTreeNode> children = branch.children(); children.hasMoreElements();) { Enumeration<DefaultMutableTreeNode> children = branch.children(); children.hasMoreElements();) {
DefaultMutableTreeNode childNode = children.nextElement(); DefaultMutableTreeNode childNode = children.nextElement();
AbstractPage childPage = pageOfNode(childNode); AbstractPage childPage = getPageOfNode(childNode);
if (! branchPage.childPages.contains(childPage)) { if (! branchPage.childPages.contains(childPage)) {
// child's page is no more contained within its parent's page children collection // child's page is no more contained within its parent's page children collection
removeList.add(childNode); // can't remove on spot, it will fuck up the iteration removeList.add(childNode); // can't remove on spot, it will fuck up the iteration
} }
} }
for (DefaultMutableTreeNode element: removeList) {
for (DefaultMutableTreeNode element: removeList) {
// ordinary, this should never happen. if this is executing, it means that cache data was in conflict
// with updated net data.
model.removeNodeFromParent(element); model.removeNodeFromParent(element);
//since this page is no more of our concern, all jobs executing and pending are irrelevant CPU consumers //since this page is no more of our concern, all jobs executing and pending are irrelevant CPU consumers
newWorker.stopJobsForPage(pageOfNode(element)); newWorker.stopJobsForPage(getPageOfNode(element));
} }
} }


Expand All @@ -385,9 +446,31 @@ public void myWorkerDone (AbstractPage root, JobMaster.JobType jobType) {
} }
} }


private AbstractPage pageOfNode(DefaultMutableTreeNode node) { /**
* Shorthand to extract the page this node is displaying through user object
* @param node
* @return null if user object is not a AbstractPage wrapper
*/
private AbstractPage getPageOfNode(DefaultMutableTreeNode node) {
if (node.getUserObject() instanceof TreeNodePageWrapper) if (node.getUserObject() instanceof TreeNodePageWrapper)
return ((TreeNodePageWrapper)node.getUserObject()).page; return ((TreeNodePageWrapper)node.getUserObject()).page;
else return null; else return null;
} }

/**
* Search children nodes of a parentNode for a DefaultMutableTreeNode containing given AbstractPage.
* @param parentNode - parent of nodes to search among
* @param page - page to search
* @return found node or null if not found
*/
private DefaultMutableTreeNode getNodeOfPage (DefaultMutableTreeNode parentNode, AbstractPage page) {
DefaultMutableTreeNode childNode = null;
for (@SuppressWarnings("unchecked")
Enumeration<DefaultMutableTreeNode> children = parentNode.children(); children.hasMoreElements();) {
childNode = children.nextElement();
if (page.equals(getPageOfNode(childNode)))
return childNode;
}
return null;
}
} }
8 changes: 4 additions & 4 deletions src/dloader/WebDownloader.java
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
*/ */
public class WebDownloader { public class WebDownloader {


/** /**
* Downloads and saves a resource by given string address (URL) . * Downloads and saves a resource by given string address (URL) .
* @param from - resource URL string * @param from - resource URL string
* @param to - file to save to. * @param to - file to save to.
* @param reporter TODO * @param reporter - way to publish download progress.
* @return size of the downloaded file in bytes, * @return size of the downloaded file in bytes,
* 0 if download was skipped (file exists and not zero length) * 0 if download was skipped (file exists and not zero length)
* @throws IOException on stream problems or server has responded bad * @throws IOException on stream problems or server has responded bad
*/ */
public static long fetchWebFile(String from, String to, ProgressReporter reporter) throws IOException { public static long fetchWebFile(String from, String to, ProgressReporter reporter) throws IOException {
Expand Down
Loading

0 comments on commit df8c711

Please sign in to comment.