001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.extensions.markup.html.repeater.tree; 018 019import java.util.Set; 020 021import org.apache.wicket.Component; 022import org.apache.wicket.core.request.handler.IPartialPageRequestHandler; 023import org.apache.wicket.extensions.markup.html.repeater.tree.nested.BranchItem; 024import org.apache.wicket.extensions.markup.html.repeater.tree.nested.Subtree; 025import org.apache.wicket.model.IModel; 026import org.apache.wicket.util.visit.IVisit; 027import org.apache.wicket.util.visit.IVisitor; 028 029/** 030 * A tree with nested markup. 031 * 032 * @author svenmeier 033 * @param <T> 034 * the model object type 035 */ 036public abstract class NestedTree<T> extends AbstractTree<T> 037{ 038 private static final long serialVersionUID = 1L; 039 040 /** 041 * Construct. 042 * 043 * @param id 044 * the component id 045 * @param provider 046 * the provider of the tree 047 */ 048 public NestedTree(String id, ITreeProvider<T> provider) 049 { 050 this(id, provider, null); 051 } 052 053 /** 054 * Construct. 055 * 056 * @param id 057 * the component id 058 * @param provider 059 * the provider of the tree 060 * @param state 061 * the expansion state 062 * 063 * @see org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree.State 064 */ 065 public NestedTree(String id, ITreeProvider<T> provider, IModel<? extends Set<T>> state) 066 { 067 super(id, provider, state); 068 069 add(newSubtree("subtree", new RootsModel())); 070 } 071 072 /** 073 * Create a new subtree. 074 * 075 * @param id 076 * component id 077 * @param model 078 * the model of the new subtree 079 * @return the created component 080 */ 081 public Component newSubtree(String id, IModel<T> model) 082 { 083 return new Subtree<>(id, this, model); 084 } 085 086 /** 087 * Overridden to let the node output its markup id. 088 * 089 * @see #updateNode(Object, IPartialPageRequestHandler) 090 * @see Component#setOutputMarkupId(boolean) 091 */ 092 @Override 093 public Component newNodeComponent(String id, IModel<T> model) 094 { 095 Component node = super.newNodeComponent(id, model); 096 097 node.setOutputMarkupId(true); 098 099 return node; 100 } 101 102 /** 103 * Overridden to update the corresponding {@link BranchItem} only. 104 * 105 * @param t 106 * node to update 107 * @param target 108 * request target must not be @code null} 109 */ 110 @Override 111 public void updateBranch(T t, IPartialPageRequestHandler target) 112 { 113 final IModel<T> model = getProvider().model(t); 114 visitChildren(BranchItem.class, new IVisitor<BranchItem<T>, Void>() 115 { 116 @Override 117 public void component(BranchItem<T> branch, IVisit<Void> visit) 118 { 119 if (model.equals(branch.getModel())) 120 { 121 // BranchItem always outputs its markupId 122 target.add(branch); 123 visit.stop(); 124 } 125 } 126 }); 127 model.detach(); 128 } 129 130 /** 131 * Overridden to update the corresponding {@link Node} only. 132 * 133 * @param node 134 * node to update 135 * @param target 136 * request target must not be @code null} 137 */ 138 @Override 139 public void updateNode(T node, IPartialPageRequestHandler target) 140 { 141 final IModel<T> model = getProvider().model(node); 142 visitChildren(Node.class, new IVisitor<Node<T>, Void>() 143 { 144 @Override 145 public void component(Node<T> node, IVisit<Void> visit) 146 { 147 if (model.equals(node.getModel())) 148 { 149 // nodes are configured to output their markup id, see #newNodeComponent() 150 target.add(node); 151 visit.stop(); 152 } 153 visit.dontGoDeeper(); 154 } 155 }); 156 model.detach(); 157 } 158 159 private class RootsModel implements IModel<T> 160 { 161 private static final long serialVersionUID = 1L; 162 163 @Override 164 public T getObject() 165 { 166 return null; 167 } 168 } 169}