Create a JTree from a list of dot-delimited Strings - java

I am creating an editor application, and I am having a problem with my menus. In the object menu, I want to display several objects types using a JTree. These object types are dynamically registered by plugins and follow this style:
trigger.button
trigger.lever
out.door.fallgate
trigger.plate
out.door.door
...
This list of names is unsorted and I want to build a TreeNode structure for a JTree like this:
trigger
button
lever
plate
out
door
fallgate
door
Additionally, if the user selects a leaf node, I need to recreate the object name (e.g. trigger.button) from the TreePath. Could someone please advise how this can be done.

In psuedocode, this is what you need to do...
public TreeNode buildTree(){
String[] names = new String[]; // fill this with the names of your plugins
TreeNode tree;
// for each plugin name...
for (int i=0;i<names.length;i++){
String currentName = names[i];
String[] splitName = currentName.split(".");
// loop over the split name and see if the nodes exist in the tree. If not, create them
TreeNode parent = tree;
for (int n=0;n<splitName.length;n++){
if (parent.hasChild(splitName[n])){
// the parent node exists, so it doesn't need to be created. Store the node as 'parent' to use in the next loop run
parent = parent.getChild(splitName[n]);
}
else {
// the node doesn't exist, so create it. Then set it as 'parent' for use by the next loop run
TreeNode child = new TreeNode(splitName[n]);
parent.addChild(child);
parent = child;
}
}
return tree;
}
This is only psuedocode - you'll need to do the work of implementing the TreeNode methods properly, etc. Give it a try yourself - if you have any more problems, create a question and show us that you've attempted to do it yourself, then we will be more willing to help you solve the minor problems.

see Oracle JTree tutorial
part Dynamically Changing a Tree, check the code example
similair idea

Related

Binding for userdata change of nodes inside a list?

I'm building a JavaFX application where I have a GridPane of 10 labels, and the user can assign objects to these labels per drag and drop. I used the userdata property of nodes, so when the user drops an object onto one label, it sets that object as userdata of this label.
Now I want to set a bind for the disableProperty of a button, so that the button only gets enabled when the user "filled" all of these labels with data. I've tried several things, finally I came to something like this:
FilteredList<Node> emptySlots = gridPane.getChildren().filtered(node -> node.getUserData() == null);
SimpleListProperty<Node> listProperty = new SimpleListProperty<>(emptySlots);
BooleanProperty hasEmptySlots = new SimpleBooleanProperty();
hasEmptySlots.bind(not(listProperty.emptyProperty()));
button.disableProperty().bind(hasEmptySlots);
But sadly the emptySlots list doesn't seem to update when the userdata property of the labels gets changed. I already tried to find ways to update this list, but I only find ways that involve ObservableLists with own classes and custom setup when the list is created like this (from here):
ObservableList<Model> masterData = FXCollections.observableArrayList<>(model ->
new Observable[]{model.statusProperty()});
But I don't have that option here.
Has anyone an idea how to archieve this?
Using an extractor could have worked using a mirror of the children list, but unfortunately the userData is not stored in a property (i.e. it's not Observable). To do what you want you'll have to use a different mechanism to store your user's objects.
An alternative to using the userData, in the same spirit of your current approach, is to use a Node's properties. These properties are stored in an ObservableMap<Object, Object> which means they can be observed for changes. To use this option you'll still want to use an extractor and mirror the children list.
class Foo {
private static final String USER_OBJECT_KEY = "USER_OBJECT";
private final GridPane gridPane = ...;
private final Button button = ...;
Foo() {
ObservableList<Node> mirror = FXCollections.observableArrayList(
n -> new Observable[]{n.getProperties()}
);
Bindings.bindContent(mirror, gridPane.getChildren());
FilteredList<Node> filtered = mirror.filtered(
n -> !n.getProperties().containsKey(USER_OBJECT_KEY)
);
button.disableProperty(Bindings.isEmpty(filtered));
}
}
The above uses Bindings.isEmpty(ObservableList) rather than wrapping the observable list in a ListProperty.
You may also want to consider moving this state out into a model. That way you avoid coupling the state of the application with JavaFX GUI objects (the model should know nothing about the view).

Programmatically arranging contents in aem 6.4

everyone. I'm new in working with aem. I'm using aem 6.4. My task is to programmatically sort the order of the contents of a cq:project in aem depending on the content of a JSON file.
The content of the JSON file should be set as the initial child instead of the children sorted by their creation date.
This is the current structure of my cq:page. If the child2 is the one indicated in the JSON file, it should be the first one to be displayed. The content of the JSON file is just the name of one child so even though there are 10 children, the content of the JSON file should always be the first one in the list.
I've spent hours researching on how I can implement this although I still can't find any solution. Any insights on how should I create this? Thanks!
As I understand it, you want a way to order a named child of a cq:Page to be first in the list.
This is possible because cq:Page is an orderable node. This would not be possible otherwise. you chan check any nodetype in CRX Explorer.
I think adding the bit about JSON complicates the question. You just need a simple method such as the following:
private void orderAsFirstChild(String childName, Node parentNode) throws RepositoryException {
if (parentNode.hasNode(childName)) {
// find current first child name
String firstChildName = Optional.ofNullable(parentNode.getNodes())
.map(NodeIterator::nextNode)
.map(node -> {
try {
node.getName();
} catch (RepositoryException e) {
e.printStackTrace();
}
return (String) null;
}) //
.orElse(null);
parentNode.orderBefore(childName, firstChildName);
}
}
You should probably clean this up a little, but this is the general idea using Node#orderBefore
This may helps -
Get the children from the parent node.(you will get 'iterator' convert it to list here-Convert Iterator to ArrayList)
Delete all child nodes now. And keep the back up of above list.
iterate through the list , identify the node which you want place first(by title or some other property) add that to a separate set(LinkedHashSet- to maintain order).
Now add the remaining items/nodes in the same order after your specific node in the above set.(you may need to iterate through again)
Now this Set has nodes/Resources in the order which you want, iterate , create nodes and save your changes.

Java ExplorerManager Filter

I have implemented https://blogs.oracle.com/geertjan/file-browser to show only folders (changed == in accept() to !=). However, no matter what I have done it only calls the FileFilterNodeChildren for the first level, the children of the root node. So what I get is the folders of the root node (the directory I want) but it show ALL files and folders below this level. I have put in statements that verify that the filter function is only called for the first level.
What do I need to do to filter the children of the first level and below?
Inside of createNodes() you need to wrap the child nodes with instances of FileFilterNode. Here is a revised version of createNodes():
#Override
protected Node[] createNodes(Node object) {
List<Node> result = new ArrayList<Node>();
for (Node node : super.createNodes(object)) {
if (accept(node)) {
// This is the only changed line
result.add(new FileFilterNode(node));
}
}
return result.toArray(new Node[0]);
}
This was tested in NetBeans 8.2 on Windows and works as expected. The "File Browser" displays a tree containing only folders at all levels.

In Java how do I create a structured tree using FileVisitor

Given a starting path I want to create a tree like object representing the filesystem using Java, showing all the folders down to level x but not ordinary files. . So using FileVisitor I know that every time just before Im going to browse a new subfolder that the preVisitDirectory() method will be called and once it had completed parsing all its children the postVisitDirectory() will be called, but my problem is knowing how to attach this directory to its parent.
i.e in my case I want to create data for jstree using ul/li/ul/li elements, and Im doing this with j2html lib. So create root using ul(), then when I go into preVisitDirectory() I would create a li() element and in postVisitDirectory() would want to attach to ul() using ul().with(li) but I cant see how to keep track of where I am in building my tree.
e.g static hard coded example not actually browsing tree
public Tag createBrowseTreeAsHtml()
{
Tag ulTag = ul(
li("ChildNode 2").withId("child_node_1"),
li("ChildNode")
);
Tag divTag= div(
ul(
li("Root Node 1").with(ulTag),
li("Root Node 2")
)
)
.withId("jstree");
return div().with(divTag);
}
I see Guava has support for Graphs, should I be utilising this somehow ?

Trouble with inserting notes into a JTree

I have a JTree which is constructed with the following method:
(The BKMNode class extends DefaultMutableTreeNode, and theDataNode simply holds the data)
void populateTree(BKMNode parent) {
for (DataNode node : nodes) {
BKMNode treeNode = new BKMNode(node.name,node.fullName,null);
// check if this node was already added before
if (! existingNodes.contains(ip + "." + node.fullName)) {
existingNodes.add(ip + "." + node.fullName);
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
model.insertNodeInto(treeNode, parent, parent.getChildCount());
System.out.println("adding " + ip + "." + node.fullName);
}
node.populateTree(treeNode);
}
// some more non-relevant code...
When the tree is created at the application startup, everything is fine.
But once in a while my application adds nodes to the tree using the same method.
When the application attempts to add a new node to the tree in does print the text, but nothing changes on the GUI.
I tried calling JTree.invalidate(), validate(), repaint(), reload() but nothing seems to help.
The populateTree method is always called from the EDT.
Does anyone know what's the problems here?
Thanks a lot in advance!
Trust me, I tried using every invalidate, validate, repaint, reload method
Sorry, I don't trust you, people make silly mistakes all the time. That is why we need a SSCCE to see exactly what your are doing. Having said that, there is no reason to invoke any of those methods. invalidate(), validate() are used when you add/remove components from a Container, which you have not done. When you update a model, the model is responsible for notifying the view so the view can repaint itself.
but nothing changes on the GUI
What do you expect to change?
Inserting a node inserts a node into the model. If the parent node is expanded, then yes you should see the inserted node. However if the parent node is collapsed you will not see a change.
If you want to see the node after you insert it then you can use the tree.expandPath(...) method.
The basic code you posted works fine for me when I insert a default node containing a String value. Maybe the problem is your custom node? So the first thing you need to do is create a SSCCE that works with the default node. Once that works you replace the default node with your custom node. If it works, great. If not you know the problem is your custom node.
Based on the code provided it should work, so you need to give us more to work with.
Solved! I added some breakpoints at the "nodesWereInserted" method in the DefaultTreeModel's source and run the application with a debugger. It showed that the new nodes were added with a null parent! Further investigation showed the problem - the node.populateTree(treeNode); line added the new node without it being connected its indended parent.
This is the new (working) code. Thanks a lot for the help.
void populateTree(BKMNode parent) {
for (DataNode node : nodes) {
BKMNode treeNode = new BKMNode(node.name,node.fullName,null);
// check if this node was already added before
if (! existingNodes.contains(ip + "." + node.fullName)) {
existingNodes.add(ip + "." + node.fullName);
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
model.insertNodeInto(treeNode, parent, parent.getChildCount());
node.bkmNode = treeNode;
node.populateTree(treeNode);
} else {
node.populateTree(node.bkmNode);
}
} // for

Categories

Resources