Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* #%L
* JAXX :: Runtime Swing Nav
* %%
* Copyright (C) 2008 - 2020 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.jaxx.runtime.swing.nav.treetable;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.MutableTreeTableNode;
import org.nuiton.jaxx.runtime.swing.nav.NavBridge;
import org.nuiton.jaxx.runtime.swing.nav.NavDataProvider;
import org.nuiton.jaxx.runtime.swing.nav.NavNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
/**
* Implementation of {@link NavNode} used to create in tree table
* This node extends {@link DefaultMutableTreeTableNode} used by
* {@link JXTreeTable}
*
* @author Sylvain Lletellier
* @since 2.2
*/
public class NavTreeTableNode> extends DefaultMutableTreeTableNode implements NavNode {
/** Logger */
static private final Logger log = LogManager.getLogger(NavNode.class);
private static final long serialVersionUID = 1L;
/** Type of data associated with the node */
protected final Class> internalClass;
/**
* Optinal context to distinguish different nodes with same
* {@link #internalClass}.
*/
protected final String context;
/** Id of the data associated with the node. */
protected final String id;
/** Flag to know when renderer should (re-)compute render of the node. */
protected boolean dirty = true;
/** Flag to know when the none static node was loaded. */
protected boolean loaded;
/** Optional child loador to lazy create childs of the node. */
protected final NavTreeTableNodeChildLoador, ?, N> childLoador;
protected NavTreeTableNode(String id) {
this(String.class, id, null, null);
}
public NavTreeTableNode(Class> internalClass,
String id,
String context,
NavTreeTableNodeChildLoador, ?, N> childLoador) {
this.internalClass = internalClass;
this.id = id;
this.context = context;
this.childLoador = childLoador;
if (isStaticNode()) {
// A static node is always full loaded
loaded = true;
}
if (log.isDebugEnabled()) {
log.debug("new node : " + this);
}
}
@Override
public String getId() {
return id;
}
@Override
public String getContext() {
return context;
}
@Override
public Class> getInternalClass() {
return internalClass;
}
@Override
public boolean isLoaded() {
return loaded;
}
@Override
public boolean isDirty() {
return dirty;
}
@Override
public boolean isStringNode() {
return String.class.equals(internalClass);
}
@Override
public boolean isStaticNode() {
return childLoador == null;
}
@Override
@SuppressWarnings({"unchecked"})
public N getContainerNode() {
if (isRoot()) {
// si on arrive sur le root, quelque chose ne va pas,
// on bloque par null, a defaut de declancher une exception
return null;
}
if (isStringNode()) {
// on est sur un noeud de type String, donc on regarde sur le parent
return getParent().getContainerNode();
}
// cas final : sur un noeud de donnee + classe interne de donnee
return (N) this;
}
public boolean isRoot() {
return getParent() == null;
}
@Override
@SuppressWarnings({"unchecked"})
public N findNodeById(String id,
NavBridge model,
NavDataProvider provider) {
if (id == null) {
// id null ? donc rien a faire
return null;
}
if (id.equals(getId())) {
// on a trouve le bon noeud
return (N) this;
}
if (!isLoaded()) {
// il faut charger les fils du noeud pour effectuer la recherche
populateChilds(model, provider);
}
if (isLeaf()) {
// au final le noeud est une feuille, donc ne convient pas
return null;
}
// on recherche dans les fils
Enumeration enumeration = children();
while (enumeration.hasMoreElements()) {
N node = enumeration.nextElement();
N nodeById = node.findNodeById(id, model, provider);
if (nodeById != null) {
return nodeById;
}
}
// aucun des noeud fils ne convient
return null;
}
@Override
public N getChild(String id,
NavBridge bridge,
NavDataProvider provider) {
if (id == null) {
// id null ? donc rien a faire
return null;
}
if (!isLoaded()) {
// il faut charger les fils du noeud pour effectuer la recherche
populateChilds(bridge, provider);
}
if (isLeaf()) {
// au final le noeud est une feuille, donc ne convient pas
return null;
}
// on recherche dans les fils
Enumeration enumeration = children();
while (enumeration.hasMoreElements()) {
N node = enumeration.nextElement();
if (id.equals(node.getId())) {
return node;
}
}
// aucun des noeud fils ne convient
return null;
}
@Override
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
@Override
public boolean isLeaf() {
// there is two behaviours for the test :
// 1 - when the node is static, then can directly use his number of child
// to determine if node is a leaf (no child)
// 2 - when the node is dynamic, then ALWAYS says the node is NOT a leaf until
// it was loaded, otherwise the WillExpand listener will not load the childs...
// Once the node is loaded, use back the normal behaviour (count number of childs)
return isStaticNode() ? super.isLeaf() : isLoaded() && getChildCount() == 0;
}
@Override
public Object getUserObject() {
return id;
}
@Override
public String toString() {
return System.identityHashCode(this) + "-" + id;
}
//--------------------------------------------------------------------------
//-- Populate methods
//--------------------------------------------------------------------------
@Override
public void populateNode(NavBridge model,
NavDataProvider provider,
boolean populateChilds) {
// on indique que le noeud n'est plus propre
setDirty(true);
if (populateChilds) {
// chargement des fils
populateChilds(model, provider);
}
}
@Override
@SuppressWarnings({"unchecked"})
public void populateChilds(NavBridge bridge,
NavDataProvider provider) {
if (isStaticNode()) {
// noeud static, rien a faire
return;
}
if (!bridge.canLoadChild((N) this)) {
// can not load childs
if (log.isDebugEnabled()) {
log.debug("Will Skip populateChilds for node : " + this);
}
return;
}
// chargement des noeuds fils du noeud courant
try {
if (log.isDebugEnabled()) {
log.debug("Will load childs for " + this);
}
childLoador.loadChilds((NavTreeTableBridge) bridge, (N) this, provider);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
// au final, on passe le noeud a l'état chargé
loaded = true;
}
}
//--------------------------------------------------------------------------
//-- Overrides to use generic type as return
//--------------------------------------------------------------------------
@SuppressWarnings({"unchecked"})
@Override
public N getParent() {
return (N) super.getParent();
}
@SuppressWarnings({"unchecked"})
@Override
public N getChildAt(int index) {
return (N) super.getChildAt(index);
}
// It's a hack to prevent concurent modification exception, caused by
// children() of AbstractMutableTreeTableNode return Collections.enumeration
@SuppressWarnings({"unchecked"})
@Override
public Enumeration children() {
List extends MutableTreeTableNode> newChildrenList =
new ArrayList<>(children);
return (Enumeration) Collections.enumeration(newChildrenList);
}
public void removeAllChildren() {
children.clear();
}
@Override
public void add(N node) {
super.add(node);
}
@SuppressWarnings({"unchecked"})
public N[] getPathToRoot(NavTreeTableNode aNode, int depth) {
NavTreeTableNode[] retNodes;
/* Check for null, in case someone passed in a null node, or
they passed in an element that isn't rooted at root. */
if (aNode == null) {
if (depth == 0) {
return null;
} else {
retNodes = new NavTreeTableNode[depth];
}
} else {
depth++;
retNodes = getPathToRoot(aNode.getParent(), depth);
retNodes[retNodes.length - depth] = aNode;
}
return (N[]) retNodes;
}
@Override
public void remove(N node) {
super.remove(node);
}
@Override
public void insert(N node, int position) {
super.insert(node, position);
}
}