I am currently creatin a TreeView where leaf elements should be checkable.
I created the sampleTreeView from the eclipse plugin that comes with a predefined Tree structure.
public class TreeObject {
private String name;
private TreeParent parent;
public TreeObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setParent(TreeParent parent) {
this.parent = parent;
}
public TreeParent getParent() {
return parent;
}
public String toString() {
return getName();
}
public Object getAdapter(Class<?> key) {
return null;
}
}
public class TreeParent extends TreeObject{
private ArrayList<TreeObject> children;
public TreeParent(String name) {
super(name);
children = new ArrayList<TreeObject>();
}
public void addChild(TreeObject child) {
children.add(child);
child.setParent(this);
}
public void removeChild(TreeObject child) {
children.remove(child);
child.setParent(null);
}
public TreeObject [] getChildren() {
return (TreeObject [])children.toArray(new TreeObject[children.size()]);
}
public boolean hasChildren() {
return children.size()>0;
}
}
I then found the following tutorial. He is using the TreeItem Object where it is easy to attach a Image. Can I somehow Copy this function or do I have to use the TreeItem object as my data structure?
The tutorial says at the beginning of part 2 that you should use a ContentProvider and LabelProvider for the TreeViewer rather than use TreeItem, and that is what you should do.
The getImage method of the label provider would return the checked / unchecked /null image.
When you need to change an image call TreeViewer.update or TreeViewer.refresh if the children of the object also need refreshing. This will call the label provider again.
Related
Currently, there are 3 classes which are not inheriting to each other. Each class has a property in it that references to an instance of another class as below.
import java.util.ArrayList;
class Region {
private Directory areaDirectory;
public Region() {
areaDirectory = new Directory();
}
public Directory getAreaDirectory() {
return areaDirectory;
}
public void setAreaDirectory(Directory areaDirectory) {
this.areaDirectory = areaDirectory;
}
}
class Directory {
private ArrayList<Area> areaList;
public Directory() {
areaList = new ArrayList<>();
}
public ArrayList<Area> getAreaList() {
return areaList;
}
public void setAreaList(ArrayList<Area> areaList) {
this.areaList = areaList;
}
public Area addNewArea(){
Area area = new Area();
return area;
}
}
class Area {
private String Name;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public Region getAreaRegion() {
// This returns a new region but need the region it was created in
return new Region();
}
}
public class Scratch {
public static void main(String args[]) {
Region r = new Region();
Area a = r.getAreaDirectory().addNewArea();
a.setName("Demo");
//See getAreaRegion() method in Area class
System.out.println(a.getAreaRegion());
}
}
How to implement a method like getAreaRegion() such that it returns the region object r? How to setup inheritance in this example to get parent objects?
I have understood the business logic which you want to describe with codes as below:
There is a region. Every region has a directory. And every directory has an area.
In this case I think it would be nice if :
Region class holds reference to Directory field;
And Directory class also has reference for its own Region;
Directory class holds reference to Area field;
And Area class also has reference for its own Directory.
Then we can create classes in following way:
1.Region class
public class Region {
private Directory directory;
public Directory getDirectory() {
return directory;
}
public void setDirectory(Directory directory) {
this.directory = directory;
}
}
2.Directory class
class Directory{
private Region region;
private Area area;
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
public Area getArea() {
return area;
}
public void setArea(Area area) {
this.area = area;
}
}
3.Area class
class Area{
private Directory directory;
private String Name;
public Directory getDirectory() {
return directory;
}
public void setDirectory(Directory directory) {
this.directory = directory;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}
So we can get region of area as following:
area.getDirectory().getRegion();
I think this shows business logic better and simply. Hope it would be helpful for someone:)
Let's assume I have two objects, both created through the builder pattern and one is nested into other:
class Parent {
private final Child child;
private Parent(Child child) {
this.child = child;
}
public static class Builder {
private Child child;
public Builder() {}
public Builder child(Child child) {
this.child = child;
return this;
}
public Parent build() {
return new Parent(child);
}
}
}
class Child {
private final long id;
private Child(Builder builder) {
this.id = builder.id;
}
public static class Builder {
private long id;
public Builder() {}
public Builder id(long id) {
this.id = id;
return this;
}
public Parent build() {
return new Child(this);
}
}
}
So, the obvious usage is quite simple:
Person.Builder parentBuilder = new Person.Builder().child(new Child.Builder().id(10).build());
Is it quite common to make
public static class Builder {
private ChildBuilder child;
public Builder() {}
public Builder child(ChildBuilder child) {
this.child = child;
return this;
}
public Builder resetChildId() {
child.id(0);
return this;
}
public Parent build() {
Child childToPass = child.build();
return new Parent(childToPass);
}
}
That way it is still possible to update the child#id later, however due to late binding the errors are thrown lately during Parent.Builder#build() method.
I would pass a Child instance to Parent rather than a ChildBuilder instance.
If you wish to change Child properties afterwards then you can simply construct a new ChildBuilder from parentBuilder.child().
However, I'm concerned about the design when I see all those builders. DDD is all about the ubiquitous language and "builder" is certainly not part of it. Sometimes you have no choice to introduce technical concepts in the design, but I believe that you may be forgetting about other DDD building blocks that may help.
I have builders everywhere because I have to do validation for each
domain entity in the app. For example name for Parent not longer than
255, but for child not more than 1000. - Tahar Bakir (from the comments)
The rules you describe above may be encapsulated and enforce upon construction in domain concepts such as ParentName and ChildName that can be implemented as value objects.
Your Parent and Child classes can then work with those concepts rather than strings.
Hope this helps
the example on how to use it is in the main method, this will print
10
0
The parent class:
public class Parent {
private final Child child;
private Parent(Child child) {
this.child = child;
}
public Child getChild(){
return this.child;
}
public static class Builder {
private Child.Builder childBuilder;
public Builder() {}
public Builder child(Child.Builder childBuilder) {
this.childBuilder = childBuilder;
return this;
}
public void resetChildId() {
childBuilder = childBuilder.id(0);
}
public Parent build() {
return new Parent(childBuilder.build());
}
}
public static void main (String[] args){
Parent.Builder parentBuilder = new Parent.Builder().child(new Child.Builder().id(10));
System.out.println(parentBuilder.build().getChild().getId());
//Reset the sucker
parentBuilder.resetChildId();
System.out.println(parentBuilder.build().getChild().getId());
}
}
The child class:
class Child {
private final long id;
private Child(Builder builder) {
this.id = builder.id;
}
public long getId(){
return this.id;
}
public static class Builder {
private long id;
public Builder() {}
public Builder id(long id) {
this.id = id;
return this;
}
public Child build() {
return new Child(this);
}
}
}
Suppose i have a class as follows:
private class ComparableElement extends Element implements Comparable<ComparableElement> {
#Override
public int compareTo(ComparableElement o) {
return getName().compareTo(o.getName());
}
}
where Elements is defined as follows:
public class Element {
protected String name;
protected String category;
public Element() {
super();
}
public Element(String _name, String _category) {
super();
this.name = _name;
this.category = _category;
}
public String getName() {
return name;
}
}
Then in case i have an Element object, whats the best practice to convert that Element object to a ComparableElement instance? something like :
Element e;
...
ComparableElement ce = (ComparableElement)e;
only that this wouldnt work...
You can make new constractor ComparableElement :
public ComparableElement (Element element )
{
//Here you get all the data from the element and set it to this object.
}
I'm trying to display a tree of Categories, following the basic CellTree gwt examples.
What I am stuck at is determining the "leaf" condition of a Category.
A Category "is-a-leaf" when it hasn't children, right? So, here's my Category (I am using Objectify for appengine persistence):
#Entity
public class Categoria implements Serializable {
private static final long serialVersionUID = 1L;
#Id
Long id;
String nome;
Key<Categoria> parent;
public Categoria() { }
public Categoria(String nome) {
super();
this.nome = nome;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Key<Categoria> getParent() {
return parent;
}
public void setParent(Key<Categoria> parent) {
this.parent = parent;
}
}
My TreeViewModel is based on AsyncDataProvider (which I pass from outside):
public class CategorieTreeViewModel implements TreeViewModel {
private AbstractDataProvider<Categoria> dataProvider;
public CategorieTreeViewModel(AbstractDataProvider<Categoria> dataProvider) {
this.dataProvider = dataProvider;
}
#Override
public <T> NodeInfo<?> getNodeInfo(T value) {
return new DefaultNodeInfo<Categoria>(dataProvider, new CategoriaCell());
}
#Override
public boolean isLeaf(Object value) {
return false;
}
}
So here it is:
dataProvider = new AsyncDataProvider<Categoria>() {
#Override
protected void onRangeChanged(HasData<Categoria> display) {
updateTree();
}
};
private void updateTree() {
rpcService.getCategorie(new AsyncCallback<Categoria[]>() {
#Override
public void onSuccess(Categoria[] result) {
dataProvider.updateRowCount(result.length, true);
dataProvider.updateRowData(0, Arrays.asList(result));
}
#Override
public void onFailure(Throwable caught) {
Window.alert(caught.toString());
}
});
}
The question is: since I don't have a "leaf property" on my Category bean, how can I know if it has children or not? By doing a query obviously, but the isLeaf method needs to return synchronously, how can I make my rpc call?
Or I can retrieve that "leaf" information in the getCategorie() call, filling the property at runtime, but this could be a performance problem.
What can I do?
I would add a transient property to the Categoria class, a boolean isLeaf, then inside the setParent method, you could set the parent's isLeaf property to false (because if this object has a parent of that, then that object is not a leaf). Making the property transient means it won't be persisted, so you don't have to worry about having that field in your data model.
EDIT: Here is how I would code the Categoria class's setParent method...
public void setParent(Key<Categoria> parent) {
this.parent = parent;
parent.setIsLeaf(false);
}
That way, once you have built up your model of Categoria nodes, each one of them knows whether it is a leaf or not. This works because if parent has this as a child, parent can't possibly be a leaf. Default the isLeaf property to true and you'll know if any given Categoria is a leaf just by checking it's property.
A FileManager Class has a static filed to hold a file collection, this collection may contains files or folders or both , a folder may contains files or folders or both, the FileManager Class contains public method for client code to call such as addFile, addFolder, deleteFile, deleteFolder, these method operate on the collection. My question is:
What java data structure is best for this case ?
How to create model class for File and Folder ?
some example will be good.
best regars.
// added # 2011/05/27
thank everybody !
acutaly I am trying to buidl a eclipse-rcp application to manage some jdbc connection profile.
here is my code:
package com.amarsoft.sysconfig.plugin.model;
/**
* #author ggfan#amarsoft
*
*/
public class TreeNode {
/**
* unique key
*/
private String key;
/**
* used as label in a JFace TreeViewer,
*/
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
}
public class LeafNode extends TreeNode {
private FolderNode parent;
public void setParent(FolderNode parent) {
this.parent = parent;
}
public TreeNode getParent() {
return parent;
}
}
package com.amarsoft.sysconfig.plugin.model;
import java.util.List;
public class FolderNode extends TreeNode {
private List<TreeNode> children;
public void setChildren(List<TreeNode> children) {
this.children = children;
}
public List<TreeNode> getChildren() {
return children;
}
}
package com.amarsoft.sysconfig.plugin.model;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
/**
* 连接配置模型类
* #author ggfan#amarsoft
*
*/
public class ConnectionProfile extends LeafNode{
/**
* url
*/
private String url;
/**
* JDBC driver id
*/
private int driver;
/**
* user name for logon
*/
private String user;
/**
* password for logon
*/
private String pswd;
/**
* default constructor
*/
public ConnectionProfile() {
}
/**
* construct a instance using a XML element
* #param xmlElement the XML element
*/
public ConnectionProfile(Element xmlElement){
this.setName(xmlElement.attributeValue("name"));
this.setUrl(xmlElement.element("url").getTextTrim());
this.setUser(xmlElement.element("user").getTextTrim());
this.setPswd(xmlElement.element("password").getTextTrim());
}
/**
* serialize as XML
* #return
*/
public Element asXML(){
Element e = new DefaultElement("profile");
e.addAttribute("name", this.getName());
e.addElement("url", escapeNull(this.getUrl()));
e.addElement("user", escapeNull(this.getUser()));
e.addElement("password", escapeNull(this.getPswd()));
return e;
}
private String escapeNull(String s) {
return s == null ? "" : s;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPswd() {
return pswd;
}
public void setPswd(String pswd) {
this.pswd = pswd;
}
public void setDriver(int driver) {
this.driver = driver;
}
public int getDriver() {
return driver;
}
}
public class ConnectionProfileManager {
private static List<TreeNode> profiles = new ArrayList<TreeNode>();
public static void loadProfiles() throws DocumentException{
Element profiles = XMLUtil.readRoot(ConnectionProfileManager.class.getResourceAsStream("samples_profile.xml"));
//Element profiles = XMLUtil.readRoot(new File(ApplicationFiles.CONNNECTION_PROFILES));
if(profiles != null){
for(Element profile : profiles.elements()){
loadNode(profile, ConnectionProfileManager.profiles);
}
}
}
private static void loadNode(Element node, List<TreeNode> parent){
if(node.getName().equals(XMLConstants.CP_TAG_PROFILE)){
ConnectionProfile profile = new ConnectionProfile(node);
parent.add(profile);
}else if(node.getName().equals(XMLConstants.CP_TAG_FOLDER)){
FolderNode folder = new FolderNode();
folder.setChildren(new ArrayList<TreeNode>());
folder.setName(node.attributeValue(XMLConstants.CP_ATTR_NAME));
for(Element child : node.elements()){
loadNode(child, folder.getChildren());
}
parent.add(folder);
}
}
public static void saveProfiles(){
Element root = new DefaultElement(XMLConstants.CP_TAG_PROFILES);
for(TreeNode node : ConnectionProfileManager.profiles){
saveNode(node, root);
}
XMLUtil.save(root, new File("c:\\1.xml"));
}
private static void saveNode(TreeNode node, Element root) {
if(node instanceof ConnectionProfile){
ConnectionProfile p = (ConnectionProfile)node;
root.add(p.asXML());
}else if(node instanceof FolderNode){
FolderNode folder = (FolderNode)node;
Element e = new DefaultElement(XMLConstants.CP_TAG_FOLDER);
e.addAttribute(XMLConstants.CP_ATTR_NAME, node.getName());
for(TreeNode child : folder.getChildren()){
saveNode(child, e);
}
root.add(e);
}
}
public static void addProfile(ConnectionProfile profile){
profiles.add(profile);
}
public static void addProfile(TreeNode parentNode, ConnectionProfile profile){
}
public static List<TreeNode> getProfiles() {
return profiles;
}
}
with these class I get my tree works, but I found It's hard to support add operation.
You've kinda of dictacted the answer already in the question..
The File class is (according to the JavaDocs) an:
abstract representation of file and directory pathnames.
So from what you've described:
// A file manager class
class FileManager {
// has a static field to hold a file collection
static Collection<File> fileCollection;
// contains public methods such as
public addFile(File f) { }
public deleteFile(File f) { }
public addFolder(File f) { }
public deleteFolder(File f { }
}
If you have to look at implementing your own version of the File class, then the JavaDocs for that should be a good start to understanding this.
AS to what collection is best for the file collection, I think a Set makes most sense. There's no point having more than one file (e.g. a List and two entries of the same file would be meaningless), and testing membership of a set is a very quick operation. For example, in addFile you might check it exists before trying to add, and similarly for delete you'd want to make sure that it exists before you delete it.
A couple of points about the design you've mentioned.
Static fields like this as nasty. They make it difficult to test and are a pain for multi-threading. Could you make it an instance variable?
Given that File is an abstract representation of a path name, why'd you need the method addFile and addFolder, they are going to have the same implementation?
A Collection of Files?
Most collections support add and delete, so there is no need for a special data structure. Java File can be a file and a directory. Simply call isDirectory to find out if it is a directory or a file.
Unless you have more requirements, I think this would make up a pretty easy to use FileManager:
List<File> fileManager = new ArrayList<File>();