/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.wicket.extensions.markup.html.repeater.tree; import java.util.List; import java.util.Optional; import java.util.Set; import org.apache.wicket.core.request.handler.IPartialPageRequestHandler; import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.tree.table.ITreeColumn; import org.apache.wicket.extensions.markup.html.repeater.tree.table.ITreeDataProvider; import org.apache.wicket.extensions.markup.html.repeater.tree.table.NodeModel; import org.apache.wicket.extensions.markup.html.repeater.tree.table.TreeDataProvider; import org.apache.wicket.markup.repeater.IItemReuseStrategy; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.RefreshingView; import org.apache.wicket.markup.repeater.data.IDataProvider; import org.apache.wicket.model.IModel; import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.visit.IVisit; import org.apache.wicket.util.visit.IVisitor; /** * A tree with tabular markup. * * @author svenmeier * * @param <T> * The model object type * @param <S> * the type of the sort property */ public abstract class TableTree<T, S> extends AbstractTree<T> { private static final long serialVersionUID = 1L; private final DataTable<T, S> table; /** * Constructor * * @param id * component id * @param columns * list of IColumn objects * @param dataProvider * imodel for data provider * @param rowsPerPage * number of rows per page */ public TableTree(final String id, final List<? extends IColumn<T, S>> columns, final ITreeProvider<T> dataProvider, final long rowsPerPage) { this(id, columns, dataProvider, rowsPerPage, null); } /** * Constructor * * @param id * component id * @param columns * list of IColumn objects * @param provider * provider of the tree * @param rowsPerPage * number of rows per page * @param state * the expansion state */ public TableTree(final String id, final List<? extends IColumn<T, S>> columns, final ITreeProvider<T> provider, final long rowsPerPage, IModel<? extends Set<T>> state) { super(id, provider, state); Args.notEmpty(columns, "columns"); for (IColumn<T, S> column : columns) { if (column instanceof ITreeColumn<?, ?>) { ((ITreeColumn<T, S>)column).setTree(this); } } this.table = newDataTable("table", columns, newDataProvider(provider), rowsPerPage); add(table); // see #updateBranch(Object, AjaxRequestTarget) setOutputMarkupId(true); } /** * Factory method for the wrapped {@link DataTable}. * * Note: If overwritten, the DataTable's row items have to output their markupId, or * {@link #updateNode(Object, Optional)} will fail. * * @param id * @param columns * @param dataProvider * @param rowsPerPage * @return nested data table */ protected DataTable<T, S> newDataTable(String id, List<? extends IColumn<T, S>> columns, IDataProvider<T> dataProvider, long rowsPerPage) { return new DataTable<T, S>(id, columns, dataProvider, rowsPerPage) { private static final long serialVersionUID = 1L; @Override protected Item<T> newRowItem(String id, int index, IModel<T> model) { Item<T> item = TableTree.this.newRowItem(id, index, model); // see #update(Node); item.setOutputMarkupId(true); return item; } }; } /** * Get the nested table. * * @return the nested table */ public DataTable<T, S> getTable() { return table; } /** * Sets the item reuse strategy. This strategy controls the creation of {@link Item}s. * * @see RefreshingView#setItemReuseStrategy(IItemReuseStrategy) * @see IItemReuseStrategy * * @param strategy * item reuse strategy * @return this for chaining */ @Override public final TableTree<T, S> setItemReuseStrategy(final IItemReuseStrategy strategy) { table.setItemReuseStrategy(strategy); super.setItemReuseStrategy(strategy); return this; } /** * For updating of a single branch the whole table is added to the ART. */ @Override public void updateBranch(T node, IPartialPageRequestHandler target) { // TableTree always outputs markupId target.add(this); } /** * For an update of a node the complete row item is added to the ART. */ @Override public void updateNode(T t, IPartialPageRequestHandler target) { final IModel<T> model = getProvider().model(t); table.getBody().visitChildren(Item.class, new IVisitor<Item<T>, Void>() { @Override public void component(Item<T> item, IVisit<Void> visit) { NodeModel<T> nodeModel = (NodeModel<T>)item.getModel(); if (model.equals(nodeModel.getWrappedModel())) { // row items are configured to output their markupId target.add(item); visit.stop(); return; } visit.dontGoDeeper(); } }); model.detach(); } /** * Hook method to create an {@link ITreeDataProvider}. * * @param provider * the tree provider * @return the data provider */ protected ITreeDataProvider<T> newDataProvider(ITreeProvider<T> provider) { return new TreeDataProvider<T>(provider) { private static final long serialVersionUID = 1L; @Override protected boolean iterateChildren(T object) { return TableTree.this.getState(object) == State.EXPANDED; } }; } /** * Create a row item for the nested {@link DataTable}. * * @param id * component id * @param index * index of row * @param model * model for row * @return row item */ protected Item<T> newRowItem(String id, int index, IModel<T> model) { Item<T> item = new Item<>(id, index, model); return item; } }