📄 abstracttree.java
字号:
* Tree constructor * * @param id * The component id * @param model * The tree model */ public AbstractTree(String id, IModel model) { super(id, model); init(); } /** called when all nodes are collapsed. */ public final void allNodesCollapsed() { invalidateAll(); } /** called when all nodes are expanded. */ public final void allNodesExpanded() { invalidateAll(); } /** * Returns the TreeState of this tree. * * @return Tree state instance */ public ITreeState getTreeState() { if (state == null) { state = newTreeState(); // add this object as listener of the state state.addTreeStateListener(this); // FIXME: Where should we remove the listener? } return state; } /** * This method is called before the onAttach is called. Code here gets executed before the items * have been populated. */ protected void onBeforeAttach() { } // This is necessary because MarkupContainer.onBeforeRender involves calling // beforeRender on children, which results in stack overflow when called from TreeItem private void onBeforeRenderInternal() { if (attached == false) { onBeforeAttach(); checkModel(); // Do we have to rebuild the whole tree? if (dirtyAll && rootItem != null) { clearAllItem(); } else { // rebuild children of dirty nodes that need it rebuildDirty(); } // is root item created? (root item is null if the items have not // been created yet, or the whole tree was dirty and clearAllITem // has been called if (rootItem == null) { TreeNode rootNode = (TreeNode)((TreeModel)getModelObject()).getRoot(); if (rootNode != null) { if (isRootLess()) { rootItem = newTreeItem(rootNode, -1); } else { rootItem = newTreeItem(rootNode, 0); } itemContainer.add(rootItem); buildItemChildren(rootItem); } } attached = true; } } /** * Called at the beginning of the request (not ajax request, unless we are rendering the entire * component) */ public void onBeforeRender() { onBeforeRenderInternal(); super.onBeforeRender(); } /** * @see org.apache.wicket.MarkupContainer#onDetach() */ public void onDetach() { attached = false; super.onDetach(); } /** * Call to refresh the whole tree. This should only be called when the roodNode has been * replaced or the entiry tree model changed. */ public final void invalidateAll() { updated(); dirtyAll = true; } /** * @return whether the tree root is shown */ public final boolean isRootLess() { return rootLess; }; /** * @see org.apache.wicket.markup.html.tree.ITreeStateListener#nodeCollapsed(javax.swing.tree.TreeNode) */ public final void nodeCollapsed(TreeNode node) { if (isNodeVisible(node) == true) { invalidateNodeWithChildren(node); } } /** * @see org.apache.wicket.markup.html.tree.ITreeStateListener#nodeExpanded(javax.swing.tree.TreeNode) */ public final void nodeExpanded(TreeNode node) { if (isNodeVisible(node) == true) { invalidateNodeWithChildren(node); } } /** * @see org.apache.wicket.markup.html.tree.ITreeStateListener#nodeSelected(javax.swing.tree.TreeNode) */ public final void nodeSelected(TreeNode node) { if (isNodeVisible(node)) { invalidateNode(node, isForceRebuildOnSelectionChange()); } } /** * @see org.apache.wicket.markup.html.tree.ITreeStateListener#nodeUnselected(javax.swing.tree.TreeNode) */ public final void nodeUnselected(TreeNode node) { if (isNodeVisible(node)) { invalidateNode(node, isForceRebuildOnSelectionChange()); } } /** * Determines whether the TreeNode needs to be rebuilt if it is selected or deselected * * @return true if the node should be rebuilt after (de)selection, false otherwise */ protected boolean isForceRebuildOnSelectionChange() { return true; } /** * Sets whether the root of the tree should be visible. * * @param rootLess * whether the root should be visible */ public void setRootLess(boolean rootLess) { if (this.rootLess != rootLess) { this.rootLess = rootLess; invalidateAll(); // if the tree is in rootless mode, make sure the root node is // expanded if (rootLess == true && getModelObject() != null) { getTreeState().expandNode((TreeNode)((TreeModel)getModelObject()).getRoot()); } } } /** * @see javax.swing.event.TreeModelListener#treeNodesChanged(javax.swing.event.TreeModelEvent) */ public final void treeNodesChanged(TreeModelEvent e) { // has root node changed? if (e.getChildren() == null) { if (rootItem != null) { invalidateNode((TreeNode)rootItem.getModelObject(), true); } } else { // go through all changed nodes Object[] children = e.getChildren(); if (children != null) { for (int i = 0; i < children.length; i++) { TreeNode node = (TreeNode)children[i]; if (isNodeVisible(node)) { // if the nodes is visible invalidate it invalidateNode(node, true); } } } } }; /** * Marks the last but one visible child node of the given item as dirty, if give child is the * last item of parent. * * We need this to refresh the previous visible item in case the inserted / deleted item was * last. The reason is that the line shape of previous item changes from L to |- . * * @param parent * @param child */ private void markTheLastButOneChildDirty(TreeItem parent, TreeItem child) { if (parent.getChildren().indexOf(child) == parent.getChildren().size() - 1) { // go through the children backwards, start at the last but one // item for (int i = parent.getChildren().size() - 2; i >= 0; --i) { TreeItem item = (TreeItem)parent.getChildren().get(i); // invalidate the node and it's children, so that they are // redrawn invalidateNodeWithChildren((TreeNode)item.getModelObject()); } } } /** * @see javax.swing.event.TreeModelListener#treeNodesInserted(javax.swing.event.TreeModelEvent) */ public final void treeNodesInserted(TreeModelEvent e) { // get the parent node of inserted nodes TreeNode parent = (TreeNode)e.getTreePath().getLastPathComponent(); if (isNodeVisible(parent) && isNodeExpanded(parent)) { TreeItem parentItem = (TreeItem)nodeToItemMap.get(parent); for (int i = 0; i < e.getChildren().length; ++i) { TreeNode node = (TreeNode)e.getChildren()[i]; int index = e.getChildIndices()[i]; TreeItem item = newTreeItem(node, parentItem.getLevel() + 1); itemContainer.add(item); parentItem.getChildren().add(index, item); markTheLastButOneChildDirty(parentItem, item); dirtyItems.add(item); dirtyItemsCreateDOM.add(item); } } } /** * @see javax.swing.event.TreeModelListener#treeNodesRemoved(javax.swing.event.TreeModelEvent) */ public final void treeNodesRemoved(TreeModelEvent e) { // get the parent node of inserted nodes TreeNode parent = (TreeNode)e.getTreePath().getLastPathComponent(); TreeItem parentItem = (TreeItem)nodeToItemMap.get(parent); if (isNodeVisible(parent) && isNodeExpanded(parent)) { for (int i = 0; i < e.getChildren().length; ++i) { TreeNode node = (TreeNode)e.getChildren()[i]; TreeItem item = (TreeItem)nodeToItemMap.get(node); if (item != null) { markTheLastButOneChildDirty(parentItem, item); parentItem.getChildren().remove(item); // go though item children and remove every one of them visitItemChildren(item, new IItemCallback() { public void visitItem(TreeItem item) { removeItem(item); // deselect the node getTreeState().selectNode((TreeNode)item.getModelObject(), false); } }); removeItem(item); } } } } /** * @see javax.swing.event.TreeModelListener#treeStructureChanged(javax.swing.event.TreeModelEvent) */ public final void treeStructureChanged(TreeModelEvent e) { // get the parent node of changed nodes TreeNode node = (TreeNode)e.getTreePath().getLastPathComponent(); // has the tree root changed? if (e.getTreePath().getPathCount() == 1) { invalidateAll(); } else { invalidateNodeWithChildren(node); } } /** * Convenience method that updates changed portions on tree. You can call this method during * Ajax response, where calling {@link #updateTree(AjaxRequestTarget)} would be appropriate, but * you don't have the AjaxRequestTarget instance. However, it is also safe to call this method * outside Ajax response. */ public final void updateTree() { IRequestTarget target = getRequestCycle().getRequestTarget(); if (target instanceof AjaxRequestTarget) { updateTree((AjaxRequestTarget)target); } } /** * Allows to intercept adding dirty components to AjaxRequestTarget. * * @param target * @param component */ protected void addComponent(AjaxRequestTarget target, Component component) { target.addComponent(component); } /** * Updates the changed portions of the tree using given AjaxRequestTarget. Call this method if * you modified the tree model during an ajax request target and you want to partially update * the component on page. Make sure that the tree model has fired the proper listener functions. * <p> * <b>You can only call this method once in a request.</b> * * @param target * Ajax request target used to send the update to the page */ public final void updateTree(final AjaxRequestTarget target) { if (target == null) { return; } // check whether the model hasn't changed checkModel(); // is the whole tree dirty if (dirtyAll) { // render entire tree component addComponent(target, this); } else { // remove DOM elements that need to be removed if (deleteIds.length() != 0) { String js = getElementsDeleteJavascript(); // add the javascript to target target.prependJavascript(js); } // We have to repeat this as long as there are any dirty items to be // created. // The reason why we can't do this in one pass is that some of the // items // may need to be inserted after items that has not been inserted // yet, so we have // to detect those and wait until the items they depend on are // inserted. while (dirtyItemsCreateDOM.isEmpty() == false) { for (Iterator i = dirtyItemsCreateDOM.iterator(); i.hasNext();) { TreeItem item = (TreeItem)i.next(); TreeItem parent = item.getParentItem(); int index = parent.getChildren().indexOf(item); TreeItem previous; // we need item before this (in dom structure) if (index == 0) { previous = parent; } else { previous = (TreeItem)parent.getChildren().get(index - 1); // get the last item of previous item subtree while (previous.getChildren() != null && previous.getChildren().size() > 0) { previous = (TreeItem)previous.getChildren().get( previous.getChildren().size() - 1); } } // check if the previous item isn't waiting to be inserted if (dirtyItemsCreateDOM.contains(previous) == false) { // it's already in dom, so we can use it as point of // insertion target.prependJavascript("Wicket.Tree.createElement(\"" + item.getMarkupId() + "\"," + "\"" + previous.getMarkupId() + "\")"); // remove the item so we don't process it again i.remove(); } else { // we don't do anything here, inserting this item will // have to wait // until the previous item gets inserted } } } // iterate through dirty items for (Iterator i = dirtyItems.iterator(); i.hasNext();) { TreeItem item = (TreeItem)i.next(); // does the item need to rebuild children? if (item.getChildren() == null) { // rebuild the children buildItemChildren(item); // set flag on item so that it renders itself together with // it's children item.setRenderChildren(true); } // add the component to target addComponent(target, item); } // clear dirty flags updated(); } } /** * Returns whether the given node is expanded. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -