If I have a String[] such as { "root", "two", "1" } how can I get the DefaultMutableTreeNode from my JTree that is represented by this "path"?
For example if my JTree looks like this:
root
one
1
2
two
1 <-- I want this node
2
Assume all nodes are DefaultMutableTreeNodes.
First, you need to fetch the tree model with getModel() method. Once you have the model, it has the getRoot() method, to fetch the root of the tree. After that, you can follow with calls to getChild(Object parent, int index) and check if any of the children has the same name as the one provided in the String array. If you find such one, you can again call getChild(Object parent, int index), etc... until you arrive at the last String from the array. Then you have the corresponding tree node. You need to actually cast the tree nodes to DefaultMutableTreeNode, as the TreeModel uses Object as the tree elements (for pre-1.7 Java).
Related
I am making a tree from a text file like this:
Store, manager, employee
manager, smith, Michael
employee, steve, karen, litt, kwan
my code is something like this:
reads first line;
sets first string to parent and following to children
reads second line, sets first string to parent and following to children
But I want to read the second line, see if the first string is children in above string, and assign the value the first string(parent of second line) to that children to achieve a tree structure like this:
Store
/
manager - employee
/ \
smith - Michael steve - karen - litt - kwan
I cannot figure out the part where I check if the parent of the string is a child of any previous string and set it to that child
You can use a HashMap.
Suppose you have a Node class like this:
class Node{
String value;
Node parent;
Node[] children;
}
When you construct you tree,You can construct a HashMap<String,Node> to map the string value to the Node Object.
Then you can check map.get(stringValue)==null to see if the stringValue is a child of above String.
As the title say, is there a way to find the children of children node when listen or visit a node in ANTLR.
For example: (use grammars-v4-java lexer and parse rule)
First, I take a java file to grammar tree.
grun Java compilationUnit -gui Example.java
// Example.java
public class Example {
String name = "test";
void call(){
String name1 = "test";
}
}
and the grammar tree is
Then I try to use java to extends the baseListerner to listen enterClassDeclaration node. So I can get the ClassDeclarationContext node. I want to find the ClassDeclarationContext node's children of children that the child type is LocalDeclarationContext.
In this example:
public class MyListener extends JavaParserBaseListener {
#Override
public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) {
// find the children of children by ctx
List<ParserRuleContext> contexts = findChildContextBy(ctx, LocalVariableDeclarationContext.class);
super.enterClassDeclaration(ctx);
}
}
The variable contexts should has two elements. name and name1
I do not want to find the children one layer by one layer. emmm, Is there have a convenient way?
For a given parse tree it's easy to look up specific child nodes (at any nesting level) using ANTLR4's XPath implementation.
You can trigger that search from either the full parse tree return by the called parser rule or within a listener/visitor method for the particular subtree, for example:
List<ParseTreeMatch> matches = XPath.findAll(ctx, "//localVariableDeclaration", parser);
The return matches are instances of LocalVariableDeclarationContext (if any matched).
Note: the linked page describe two search utilities, parse tree matching and XPath, which can be used individually or together.
My graph contains nodes called points and lines.
There is a relationship type called "NEXT", which connects two points and has a property called lineID (a long). A line node consists simply of an ID and a reference to a "root" point. To traverse a line is to start with its root node and follow the NEXT relationships whose lineID matches the id of the line being traversed. To clarify, if we're traversing a line with ID 123, whose root point has id 321, the Cypher traversal would be:
START n = node(321)
MATCH (n)-[rel:NEXT*{lineID:123}]->(x)
RETURN collect(rel)
A line, then, is essentially a linked list of Next relationships with matching lineID properties. That said, I don't want to persist this list as a property of lines - I want the list to be constructed by a traversal when a line is loaded.
What are my options for implementing this in spring-data-neo4j? Specifically, should "lines" exist as NodeEntitys, and if so what should they contain?
#NodeEntity
class Line {
#RelatedTo(type="ROOT")
Point root;
#RelatedToVia(type="NEXT")
Iterable<Item> list;
doesn't quite fit, because the line is not related via Next relationships to the item, the root point is. It also fails to address the fact that those NEXT relationships need to have a lineID property matching the line's ID (which becomes important because some points exist on multiple lines - i.e. they have multiple NEXT relationships with different lineID's). I have a hunch that the solution will involve annotating the list as a #GraphTraversal, but I don't understand how that would work.
I'm doing this largely as an exercise to wrap my head around data modeling in SDN, in the context of wrapping my head around Neo4j and graph databases in general. If the question I'm asking reveals a flaw in my understanding of any of these things, I'd be very appreciative if someone could point it out.
This should be a suitable model for your entities:
#NodeEntity
class Point {
#GraphId
protected Long id;
#RelatedToVia(type="NEXT")
Set<Edge> edges;
}
#NodeEntity
class Line {
#GraphId
protected Long id;
#RelatedTo(type="ROOT")
Point root;
}
#RelationshipEntity
public class Edge {
#GraphId
protected Long id;
#StartNode private Point from;
#EndNode private Point to;
#RelatedTo(type="LINE")
Line line;
}
It easily allows both programmatic navigation in Java as in:
Set edges = line.getPoint().getEdges();
for (Edge edge: edges) {
if (edge.getLine().getId() == id) {
...
}
}
or Cypher queries like the one you listed.
I have a plain class named MenuModel in Java (it's for nested menu as the name suggests) like this:
public class MenuModel {
public String id;
public String parentId = null;
public String title;
public MenuModel parent = null;
public List<MenuModel> children = new ArrayList<MenuModel>();
}
My code fetch data from web API and generate a flat list of MenuModel with only id, parentId, and title fields filled with data. However, I need each MenuModel to have references to its parent and (optionally) children for further uses.
I have thought of a method which make a nested loop to pair the models each other and check if they are parent and child. But I think that costs too much (n^2 or n^3 complexity, the itemset is large) and can only fill the parent field.
What is the best way to achieve this in Java? To summarize:
Input: ArrayList<MenuModel> source
Output: ArrayList<MenuModel> result containing all MenuModel from source which has parentId = null (that means, it's top level menu), with each MenuModel has children fields filled with reference to their respective children MenuModel. Additionally, each children have reference to their parents.
Thanks in advance
Go through all the records and add them to a HashMap<String, MenuModel> (the key being the ID).
Then, for each record record:
Look up the parent ID in the above map to get parent.
Assign the parent to this record's parent variable - record.parent = parent.
Add this record to the parent's list of children - parent.children.add(record).
Running time: Expected O(n).
Before all I'm sorry for my bad english and tell me if anything is not understandable.
I have 2 Jtree. Each tree apparently has the same information. The only thing that changes in them are the names of the properties that has each node.
Eg
JTree1 has an ID and a ParentID. These properties have as a name and value. Name: ID_Tree1. Value: TESTID1 / / Name: ParentID_Tree1. Value: TESTPID1
In JTree2 has the same values as in the JTree1 but the names are different.
There is a moment in which I transfer a node from JTree1 to JTree2 to create it. The transfer/creation is correct but when I read the nodes, it has a different property name architecture(Jtree1 arch.) and can't be read because need to have the JTree2 architecture. I have the function changeAttributesNamesFromDOORSToTC() to solve the problem because it just change the name to the correct name and understandable for JTree2
The real problem: The function make the change in the node of JTree2 but at the same time it change the values name of the same node in JTree1. It makes reference data instead of assignments I think.
How can I solve this!?
Thanks!
JTree treeDOORSCode; //JTree1
JTree treeTCCode; //JTree2
Main Code:
//ACTUAL NODE
DefaultMutableTreeNode selectedTreeNode = (DefaultMutableTreeNode) CurrentSelection.getLastPathComponent();
NodeClass actualNode = (NodeClass)selectedTreeNode.getUserObject();
//ACTUAL PARENT NODE
DefaultMutableTreeNode selectedParentTreeNode = (DefaultMutableTreeNode) selectedTreeNode.getParent();
NodeClass parentNode = (NodeClass) selectedParentTreeNode.getUserObject();
DefaultMutableTreeNode parent = findNode(NodeClass.getNodeParentIdentifierAttrDOORS(parentNode), treeTCCode);
//NEW NODE
DefaultMutableTreeNode newSelectedTreeNode = selectedTreeNode;
//NEW PART
NodeClass newNode = new NodeClass();
newNode = insertNodeInfo(actualNode);
//Create the Model and insert the node
DefaultTreeModel treeModelTC = (DefaultTreeModel)treeTCCode.getModel();
treeModelTC.insertNodeInto(newSelectedTreeNode, parent, 0);
//NEW PART
newNode .changeAttributesNamesFromDOORSToTC();
newSelectedTreeNode.setUserObject(newNode);
Function which change the attr Name values:
public void changeAttributesNamesFromDOORSToTC(){
for (int i = 0; i < this.attributes.size(); i++) {
if (this.attributes.get(i).attributeName.equals(DOORS_ID)){
if (this.tag.equals(TYPE_NAME_CASE)){
this.attributes.get(i).attributeName = TC_IDCASE;
}
if (this.tag.equals(TYPE_NAME_FOLDER)){
this.attributes.get(i).attributeName = TC_IDFOLDER;
}
if (this.tag.equals(TYPE_NAME_FEATURE)){
this.attributes.get(i).attributeName = TC_IDFEATURE;
}
}
if (this.attributes.get(i).attributeName.equals(DOORS_PARENTID)){
this.attributes.get(i).attributeName = TC_PARENTID;
}
if (this.attributes.get(i).attributeName.equals(DOORS_SRS)){
this.attributes.get(i).attributeName = TC_SRS;
}
}
}
Attributes Class:
NodeAttributesClass (String attributeName, String attributeValue)
{
this.attributeName = attributeName;
this.attributeValue = attributeValue;
}
Let me know if need more info!
Object assignment in java is actually a reference copy.
NodeClass newActualNode = actualNode;
That line doesn't mean "put the values of object actualNode into object newActualNode", because actually the variable actualNode is not an instance of NodeClass, but a reference to an instance of NodeClass. So when you do NodeClass newActualNode = actualNode; you are copying the reference and now both variables effectively point to the same instance.
Then when you change the attribute names in one "the other" also changes, because there is no such other, it's the same place in memory.
Now, what you need to do is to create a new instance of NodeClass with the values you want. There are several ways to do so, it's hard for me to know wich one is more suitable as I don't know the internal structures, but in the end you need to:
Create a new NodeClass instance for the newActualNode variable
Put the values (fields) of actualNode into the newActualNode
Assign the attribute names that you want in newActualNode
So, it could be something like this:
NodeClass newActualNode = new NodeClass(actualNode); //copy constructor NodeClass(NodeClass anotherNode);
newActualNode.changeAttributesNamesFromDOORSToTC(); //assuming the constructor doesn't put them right
or you could use a flag in the NodeClass construtors to indicate what kind of attribute names you want.
and the copy constructor should look like this:
public NodeClass(NodeClass anotherNode)
{
this(anotherNode.someFields); //call to your "normal" constructor, with whatever params you need
//copy the values into the new instance this, if you didn't do it in the above line
this.field1 = anotherNode.field1;
this.field2 = anotherNode.field2;
//...
this.fieldn = anotherNode.fieldn;
}
You can take this code with a grain of salt, there are several ways to do it, the differences are subtle if any. The important thing is that you need to have another instance for the other tree.
EDIT
If that doesn't work my guess would be, that either you need to do newSelectedTreeNode.setUserObject(newNode); before the insert, like this:
NodeClass newNode = new NodeClass();
newNode = insertNodeInfo(actualNode);
newNode.changeAttributesNamesFromDOORSToTC();
DefaultMutableTreeNode newSelectedTreeNode = new DefaultMutableTreeNode();
newSelectedTreeNode.setUserObject(newNode);
treeModelTC.insertNodeInto(newSelectedTreeNode, parent, 0);
or that parent is not properly calculated, in particular that you are getting the parent node of the treeDOORSCode, and not the one of the treeTCCode.