CheckBoxTree Lazy loading?

This is the forum for JIDE Common Layer which is open sourced at https://github.com/jidesoft/jide-oss. Please note, JIDE technical support doesn't monitor this forum as often as other forums. Please consider subscribe for technical support for JIDE Common Layer so that you can use customer only forum to get a timely response.

Moderator: JIDE Support

Forum rules
Community driven forum for open source JIDE Common Layer. JIDE technical support doesn't monitor this forum as often as other forums. If you only use JIDE Common Layer, please consider subscribing for technical support for JIDE Common Layer so that you can use customer only forum to get a timely response.

CheckBoxTree Lazy loading?

Postby hemna » Mon Sep 28, 2009 4:14 pm

Is there a way that I could implement a checkboxtree that included lazy loading of leaf nodes?

Say I have a tree that when created, it only loads the first level nodes as all collapsed. Then when a user clicks to expand one of the nodes, a method is called to fetch the leaf
nodes from another source and then inserts them, then displays them. I need to do this instead of loading the entire hierarchy at once for performance reasons. I have a tree with
thousands of nodes and I won't want to load them all up front.

Thanks,
Walt
hemna
 
Posts: 37
Joined: Wed Jul 29, 2009 10:27 am

Re: CheckBoxTree Lazy loading?

Postby JIDE Support » Mon Sep 28, 2009 4:42 pm

Yes. You can do that just imaging it as a normal JTree. However, for digIn mode, you probably need do more control so that when you select a parent node and expand it, all child nodes could be selected.

Thanks,
JIDE Software Technical Support Team
JIDE Support
Site Admin
 
Posts: 36466
Joined: Sun Sep 14, 2003 10:49 am

Re: CheckBoxTree Lazy loading?

Postby pvbemmel » Mon May 28, 2012 8:41 am

I want to show the filesystem using a CheckBoxTree with digin behaviour.
The filesystem does not have to be editable.

I have code that works; it uses FileTreeNode which I extended from DefaultMutableTreeNode.
FileTreeNode creates FileTreeNode instances for its children, only when asked for a child through
method getChildAt(int index) .

It works, but is rather slow, when compared to a javax.swing.JTree .

With digin enabled, the CheckBoxTree creates way more FileTreeNode instances than
the JTree, when showing the same part of the filesystem.

Is there a way to make the creation of FileTreeNode instances more lazy ?

I have enclosed some files. Two of these files contain main(String[]) to run test programs:
FileTreeFrame.java: test program using JTree and FileTreeNode
CheckBoxFileTreeFrame.java: test program using CheckBoxTree and FileTreeNode

Anybody any idea to increase speed, be more lazy ?
Code: Select all
import java.io.*;
import java.util.*;
import java.util.logging.*;

import javax.swing.tree.*;

@SuppressWarnings("serial")
public class FileTreeNode extends DefaultMutableTreeNode {
 
  private static class FileComparator implements Comparator<File> {
    public int compare(File o1, File o2) {
      return o1.getName().compareTo(o2.getName());
    }
  }
  private static Logger getLogger() {
    return Logger.getLogger(FileTreeNode.class.getName());
  }
  private static final FileComparator fileComparator;
  private static final DirFileFilter dirFileFilter;
  private static final FileFileFilter fileFileFilter;
  static {
    fileComparator = new FileComparator();
    dirFileFilter = new DirFileFilter();
    fileFileFilter = new FileFileFilter();
  }
  /** Children have been constructed. */
  private boolean initialized;
  private File file;

  public FileTreeNode(File file) {
     super(file);
     getLogger().log(Level.INFO, file.getPath());
     this.file = file;
     setAllowsChildren(file.isDirectory());
     initialized = false;
  }
  public boolean getAllowsChildren() {
    return file.isDirectory();
  }
  public TreeNode getChildAt(int index) {
    assertChildren();
    return super.getChildAt(index);
  }
  private void assertChildren() {
    if(initialized) {
      return;
    }
    initialized = true;
    if(!file.isDirectory()) {
      return;
    }
    List<File> dirs = Arrays.asList(file.listFiles(dirFileFilter));
    Collections.sort(dirs, fileComparator);
    List<File> files = Arrays.asList(file.listFiles(fileFileFilter));
    Collections.sort(files, fileComparator);
    List<File> all = new ArrayList<File>();
    all.addAll(dirs);
    all.addAll(files);
    for(File f : all) {
      FileTreeNode child = new FileTreeNode(f);
      add(child);
      child.setParent(this);
    }
  }
  public int getChildCount() {
    if(file.isDirectory()) {
      if(initialized) {
        return super.getChildCount();
      }
      else {
        String[] names = file.list();
        return names==null ? 0 : names.length;
      }
    }
    return 0;
  }
  public boolean isLeaf() {
    if(file.isDirectory()) {
      if(initialized) {
        return super.isLeaf();
      }
      else {
        String[] names = file.list();
        return names==null ? true : (names.length>0);
      }
    }
    else {
      return false;
    }
  }
}

Code: Select all
import java.io.*;
import javax.swing.*;
import javax.swing.tree.*;
import com.jidesoft.plaf.*;
import com.jidesoft.swing.*;

@SuppressWarnings("serial")
public class CheckBoxFileTreeFrame extends JFrame {
  private CheckBoxTree fileTree;

  private TreeModel fileSystemModel;

  public CheckBoxFileTreeFrame(String directory) {
    super("CheckBoxFileFileTreeFrame");
    FileTreeNode top = new FileTreeNode(new File(directory));
    fileSystemModel = new DefaultTreeModel(top, true);
    fileTree = new CheckBoxTree(fileSystemModel) {
      public String convertValueToText(Object value, boolean selected,
          boolean expanded, boolean leaf, int row, boolean hasFocus) {
        FileTreeNode node = (FileTreeNode) value;
        File file = (File) node.getUserObject();
        return file.getName();
      }
    };
    fileTree.setEditable(false);
    fileTree.getCheckBoxTreeSelectionModel().setDigIn(true);
    getContentPane().add(new JScrollPane(fileTree));
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(640, 480);
    setLocationRelativeTo(null);
    setVisible(true);
  }
  public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        try {
          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        LookAndFeelFactory.installJideExtension();
        new CheckBoxFileTreeFrame("c:\\");
      }
    });
  }
}

Code: Select all
import java.io.*;

import javax.swing.*;
import javax.swing.tree.*;

import com.jidesoft.plaf.*;
import com.jidesoft.swing.*;

@SuppressWarnings("serial")
public class FileTreeFrame extends JFrame {
  private JTree fileTree;

  private DefaultTreeModel fileSystemModel;

  public FileTreeFrame(String directory) {
    super("JTree FileSystem Viewer");
    FileTreeNode top = new FileTreeNode(new File(directory));
    fileSystemModel = new DefaultTreeModel(top, true);
    fileTree = new JTree(fileSystemModel) {
      public String convertValueToText(Object value, boolean selected,
          boolean expanded, boolean leaf, int row, boolean hasFocus) {
        FileTreeNode node = (FileTreeNode)value;
        File file = (File)node.getUserObject();
        return file.getName();
      }
    };
    fileTree.setEditable(false);
    getContentPane().add(new JScrollPane(fileTree));
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(640, 480);
    setLocationRelativeTo(null);
    setVisible(true);
  }
  public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        try {
          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        new FileTreeFrame("c:\\");
      }
    });
  }
}

Code: Select all
import java.io.*;

public class DirFileFilter implements FileFilter {

  public boolean accept(File file) {
    return file.isDirectory();
  }
}

Code: Select all
import java.io.*;

public class FileFileFilter implements FileFilter {

  public boolean accept(File file) {
    return file.isFile();
  }
}
pvbemmel
 
Posts: 13
Joined: Thu May 24, 2012 4:32 am

Re: CheckBoxTree Lazy loading?

Postby pvbemmel » Tue May 29, 2012 5:43 am

After reading the first two posts in this thread again, I realize that those posts deal with the same problem that I have.

Earlier I thought that hemna had a dynamic model, but now I realize that basically he has a static model, which is large,
and that he wants to provide it to the CheckBoxTree piecewise (i.e. as a dynamic model), as a solution to performance problem.
Thus, the same problem as I have.

The solution suggested in the first two posts, seem to me like a workaround for a bug in the CheckBoxTree.
Couldn't the CheckBoxTree take care of this problem, by not creating nodes so aggressively ?

Paul.
pvbemmel
 
Posts: 13
Joined: Thu May 24, 2012 4:32 am

Re: CheckBoxTree Lazy loading?

Postby pvbemmel » Tue May 29, 2012 6:30 am

I solved the performance problem for my file system CheckBoxTree with digin true.
Now my code is as fast as the normal JTree.

I have used example code from http://docs.oracle.com/javase/tutorial/ ... /tree.html
from the "How to Load Children Lazily" section.

See attached code for my program.

Paul.
Code: Select all
import java.io.*;
import java.util.*;
import java.util.logging.*;

import javax.swing.tree.*;

@SuppressWarnings("serial")
public class FileTreeNode extends DefaultMutableTreeNode {
 
  private static class FileComparator implements Comparator<File> {
    public int compare(File o1, File o2) {
      return o1.getName().compareTo(o2.getName());
    }
  }
  private static Logger getLogger() {
    return Logger.getLogger(FileTreeNode.class.getName());
  }
  private static final FileComparator fileComparator;
  private static final DirFileFilter dirFileFilter;
  private static final FileFileFilter fileFileFilter;
  static {
    fileComparator = new FileComparator();
    dirFileFilter = new DirFileFilter();
    fileFileFilter = new FileFileFilter();
  }
  /** Children have been constructed. */
  private boolean initialized;
  private File file;

  public FileTreeNode(File file) {
     super(file);
     getLogger().log(Level.INFO, file.getPath());
     this.file = file;
     setAllowsChildren(file.isDirectory());
     initialized = false;
  }
  public boolean getAllowsChildren() {
    return file.isDirectory();
  }
  public TreeNode getChildAt(int index) {
//  assertChildren();
    return super.getChildAt(index);
  }
  public void assertChildren(DefaultTreeModel model) {
    if(initialized) {
      return;
    }
    initialized = true;
    if(!file.isDirectory()) {
      return;
    }
    List<File> dirs = Arrays.asList(file.listFiles(dirFileFilter));
    Collections.sort(dirs, fileComparator);
    List<File> files = Arrays.asList(file.listFiles(fileFileFilter));
    Collections.sort(files, fileComparator);
    List<File> all = new ArrayList<File>();
    all.addAll(dirs);
    all.addAll(files);
    for(File f : all) {
      FileTreeNode child = new FileTreeNode(f);
      model.insertNodeInto(child, this, getChildCount());
    }
  }
  public int getChildCount() {
    if(initialized) {
      return super.getChildCount();
    }
    else {
      return 0;
    }
  }
  public boolean isLeaf() {
    if(initialized) {
      return super.isLeaf();
    }
    else {
      return true;
    }
  }
}

Code: Select all
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

import com.jidesoft.plaf.*;
import com.jidesoft.swing.*;

@SuppressWarnings("serial")
public class CheckBoxFileTreeFrame extends JFrame {
  private CheckBoxTree fileTree;

  private DefaultTreeModel fileSystemModel;

  public CheckBoxFileTreeFrame(String directory) {
    super("CheckBoxFileFileTreeFrame");
    FileTreeNode top = new FileTreeNode(new File(directory));
    fileSystemModel = new DefaultTreeModel(top, true);
    top.assertChildren(fileSystemModel);
    fileTree = new CheckBoxTree(fileSystemModel) {
      public String convertValueToText(Object value, boolean selected,
          boolean expanded, boolean leaf, int row, boolean hasFocus) {
        FileTreeNode node = (FileTreeNode) value;
        File file = (File) node.getUserObject();
        return file.getName();
      }
    };
    fileTree.setEditable(false);
    fileTree.getCheckBoxTreeSelectionModel().setDigIn(true);
    fileTree.addTreeWillExpandListener(new MyTreeWillExpandListener());
    getContentPane().add(new JScrollPane(fileTree));
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(640, 480);
    setLocationRelativeTo(null);
    setVisible(true);
  }
  public class MyTreeWillExpandListener implements TreeWillExpandListener {
    public void treeWillExpand(TreeExpansionEvent event)
        throws ExpandVetoException {
      TreePath treePath = event.getPath();
      FileTreeNode ftNode = (FileTreeNode)treePath.getLastPathComponent();
      ftNode.assertChildren(fileSystemModel);
    }
    public void treeWillCollapse(TreeExpansionEvent event)
        throws ExpandVetoException {
    }
  }
  public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        try {
          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        LookAndFeelFactory.installJideExtension();
        new CheckBoxFileTreeFrame("c:\\");
      }
    });
  }
}

Code: Select all

import java.io.*;

public class DirFileFilter implements FileFilter {

  public boolean accept(File file) {
    return file.isDirectory();
  }
}

Code: Select all
import java.io.*;

public class FileFileFilter implements FileFilter {

  public boolean accept(File file) {
    return file.isFile();
  }
}
pvbemmel
 
Posts: 13
Joined: Thu May 24, 2012 4:32 am

Re: CheckBoxTree Lazy loading?

Postby pvbemmel » Wed May 30, 2012 2:30 am

I've updated the code, to now show a CheckBoxTree of all roots as listed by File.listRoots() .

Because I'm so pleased with the result, I have enclosed a zip with the sources .

Hope others my find this useful code.

Paul van Bemmelen.
Attachments
jideFileSystemTree.zip
(6.32 KiB) Downloaded 534 times
pvbemmel
 
Posts: 13
Joined: Thu May 24, 2012 4:32 am

Re: CheckBoxTree Lazy loading?

Postby JIDE Support » Wed May 30, 2012 2:28 pm

Thanks for your sharing. We will consider include your code into our package if possible and granted the permission by you.

Thanks,
JIDE Software Technical Support Team
JIDE Support
Site Admin
 
Posts: 36466
Joined: Sun Sep 14, 2003 10:49 am

Re: CheckBoxTree Lazy loading?

Postby pvbemmel » Thu May 31, 2012 4:14 am

Permission granted, provided that any copyright you put on it doesn't restrict access to it.

The code doesn't yet have functionality to find out what checkboxes are checked. I still have to look into that.

Kind regards,
Paul.
pvbemmel
 
Posts: 13
Joined: Thu May 24, 2012 4:32 am

Re: CheckBoxTree Lazy loading?

Postby pvbemmel » Thu May 31, 2012 6:17 am

That functionality is simple: use tree.getCheckBoxTreeSelectionModel() .
pvbemmel
 
Posts: 13
Joined: Thu May 24, 2012 4:32 am

Re: CheckBoxTree Lazy loading?

Postby JIDE Support » Thu May 31, 2012 2:25 pm

Got it.

Thanks,
JIDE Software Technical Support Team
JIDE Support
Site Admin
 
Posts: 36466
Joined: Sun Sep 14, 2003 10:49 am


Return to JIDE Common Layer Open Source Project Discussion (Community Driven)

Who is online

Users browsing this forum: No registered users and 3 guests