org.nuiton.jaxx.runtime.swing.nav.NavNode Maven / Gradle / Ivy
/*
* #%L
* JAXX :: Runtime
* %%
* Copyright (C) 2008 - 2024 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;
import org.nuiton.jaxx.runtime.swing.nav.tree.AbstractNavTreeCellRenderer;
import javax.swing.tree.TreeNode;
import java.io.Serializable;
/**
* Definition of a node with a optional {@code childLoador} to build childs of
* node.
*
* A node is identified by an {@link #getId} of an associated data of type
* {@link #getInternalClass}.
*
* Note:
* While using a {@code childLoador}, we can not know before node
* was loaded the exact count of his childs. As a matter of facts, real leaf
* nodes appears at the beginning in ui as a not leaf (there is a root handler).
* When node was loaded, a leaf node will be then displayed as required.
*
*
* Why NavNode is generic ?
* In a project, you should implements your own Node extending with one like this :
*
* class MyNode extends NavNode<MyNode> { ... }
*
* While in this class, you overrides every method with a node return type,
* co-variance you'll be able to use this code :
*
* MyNode parentNode = new MyNode();
* MyNode node = parentNode.getFirstNode();
*
* So for final application this generic type avoid any cast for your own node
* type, this is quite convinient.
*
* Even if in your project, you wants to have a heriarchy of nodes, this will
* still works (if you use a genercic type on your abstract nodes).
* Internal states
*
* - internalClass : the type of data associated with the node
* - context : an optinal context to distinguish different types of
* node with same {@code internalclass}
* - id : id of the data associated with the node
* - dirty : flag sets to {@code true} when node render MUST be recomputed
* - loaded : flag sets to {@code true} when node was loaded
* - childLoador : optional loador of childs
*
* Static nodes
* Some nodes do not need auto-loading, we call them {@code static nodes}.
* The method {@link #isStaticNode()} gives this state.
*
* Note: A static node has no {@code childLoador}.
* Node loading
* Initialy node has no data child nodes, ({@link #isLoaded()} equals
* {@code false}).
* when model requires node's childs, it can load them via method
* {@link #populateNode(NavBridge, NavDataProvider, boolean)}
* and {@link #populateChilds(NavBridge, NavDataProvider)} methods.
* Node rendering
* the {@link AbstractNavTreeCellRenderer} looks the {@link #isDirty} state to
* know when render should be (re-)compute and set back the state to {@code false}.
*
* Each time, a node is modified, the {@link #isDirty} should be set to {@code true}.
*
* @author Tony Chemit - [email protected]
* @since 2.1
*/
public interface NavNode> extends Cloneable, TreeNode, Serializable {
String getId();
String getContext();
Class> getInternalClass();
boolean isLoaded();
boolean isDirty();
/**
* Convinient method to known if the node is a {@code String} typed.
*
* @return {@code true} if the type of node if
*/
boolean isStringNode();
/**
* To know if the node is static.
*
* A {@code static} node has no {@code childLoador}.
*
* @return {@code true} when the node is static : says, the node has
* no {@code childLoador}.
*/
boolean isStaticNode();
/**
* Gets the first node form this one to the root which has a none
* {@code String} type.
*
* @return the first concrete node type
*/
N getContainerNode();
/**
* Given an {@code id}, obtain the child with matching id.
*
* If node is NOT {@code loaded}, then first loads it (method
* {@link #populateChilds(NavBridge, NavDataProvider)}) then do search
* on direct childs of the node recursivly.
*
* @param id the id of the researched node
* @param bridge model owner of nodes
* @param provider data provider
* @return the found node or {@code null} if not found
*/
N findNodeById(String id,
NavBridge bridge,
NavDataProvider provider);
/**
* Given an {@code id}, obtain the child with matching id.
*
* If node is NOT {@code loaded}, then first loads it (method
* {@link #populateChilds(NavBridge, NavDataProvider)}) then return
* on direct childs of the node.
*
* @param id the id of the researched node
* @param bridge model owner of nodes
* @param provider data provider
* @return the found node or {@code null} if not found
*/
N getChild(String id,
NavBridge bridge,
NavDataProvider provider);
/**
* Changes the {@link #isDirty} state.
*
* As a side effect, when a renderer will use this node, it will force to
* reload the render from the {@link NavDataProvider}.
*
* @param dirty the new dirty value
*/
void setDirty(boolean dirty);
@Override
boolean isLeaf();
Object getUserObject();
@Override
String toString();
//--------------------------------------------------------------------------
//-- Populate methods
//--------------------------------------------------------------------------
/**
* To populate the node. A side-effect of this method is to set {@code dirty}
* the node (renderer will recompute the render of the node).
*
* If {@code populateChilds} is set to {@code true}, then also populate
* childs of the node using the given {@code dataProvider}.
*
* @param bridge le delegate modèles content le noeud
* @param provider le provider de données
* @param populateChilds un drapeau pour charger aussi les fils du noeud courant
*/
void populateNode(NavBridge bridge,
NavDataProvider provider,
boolean populateChilds);
/**
* To populate childs of the node (only when a none static node).
* A side-effect of this method is to set {@code loaded} of the node.
*
* For a static node, do nothing.
*
* @param bridge model owner of the node
* @param provider data provider
*/
void populateChilds(NavBridge bridge, NavDataProvider provider);
//--------------------------------------------------------------------------
//-- Overrides to use generic type as return
//--------------------------------------------------------------------------
boolean isRoot();
@Override
N getParent();
void add(N node);
void remove(N node);
void insert(N node, int position);
}