/* * Copyright (C) 2011 4th Line GmbH, Switzerland * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.fourthline.konto.client.ledger.component; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.resources.client.CssResource; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TreeItem; import com.google.gwt.user.client.ui.UsableTree; import org.fourthline.konto.shared.AccountType; import org.fourthline.konto.shared.entity.Account; import java.util.ArrayList; import java.util.List; /** * @author Christian Bauer */ public class AccountTree extends UsableTree { public interface Resources extends UsableTree.Resources { @Source(Style.DEFAULT_CSS) Style style(); } public interface Style extends CssResource { String DEFAULT_CSS = "org/fourthline/konto/client/ledger/component/AccountTree.css"; String accountTree(); String accountTypeLabel(); String accountTypeLabelHover(); String accountGroupLabel(); String accountGroupHover(); String accountLabel(); String accountLabelHover(); String accountMultiSelect(); } protected static Resources DEFAULT_RESOURCES; protected static Resources getDefaultResources() { if (DEFAULT_RESOURCES == null) { DEFAULT_RESOURCES = GWT.create(Resources.class); } return DEFAULT_RESOURCES; } final protected Resources resources; final protected Style style; final AccountType type; MultiSelectableTreeItem root; public AccountTree(AccountType type) { this(type, getDefaultResources(), false); } public AccountTree(AccountType type, Resources resources) { this(type, resources, false); } public AccountTree(AccountType type, Resources resources, boolean useLeafImages) { super(resources, useLeafImages); this.type = type; this.resources = resources; this.style = resources.style(); style.ensureInjected(); addStyleName(style.accountTree()); clear(); // Create the tree root } @Override public void clear() { super.clear(); // This is where the tree "model" is created root = new RootItem(type.getLabel()); addItem(root); } public void addAccount(Account account, boolean expandAll) { if (account.getGroupId() == null) { root.addItem(new AccountItem(account)); root.setState(expandAll); return; } GroupItem groupItem = null; // Try to find an existing group item for (int i = 0; i < root.getChildCount(); i++) { MultiSelectableTreeItem item = root.getChild(i); if (item instanceof GroupItem) { GroupItem gi = (GroupItem) item; if (gi.id.equals(account.getGroupId())) { groupItem = gi; break; } } } if (groupItem == null) { groupItem = new GroupItem(account.getGroupId(), account.getGroupName()); root.addItem(groupItem); } groupItem.addItem(new AccountItem(account)); root.setState(expandAll); groupItem.setState(expandAll); } public boolean hasRootChildren() { return root.getChildCount() > 0; } public List<Long> getSelectedAccounts() { List<Long> selectedIdentifiers = new ArrayList(); for (MultiSelectableTreeItem item : root.getMultiSelected()) { if (item instanceof AccountItem) { AccountItem accountItem = (AccountItem) item; selectedIdentifiers.add(accountItem.getAccount().getId()); } } return selectedIdentifiers; } public void setMultiSelectEnabled(final boolean enabled) { accept(new Visitor() { @Override public void visit(MultiSelectableTreeItem treeItem) { super.visit(treeItem); treeItem.setMultiSelectStyle( enabled ? style.accountMultiSelect() : null ); } }); } public void setMultiSelected(final boolean selected) { accept(new Visitor() { @Override public void visit(MultiSelectableTreeItem treeItem) { super.visit(treeItem); treeItem.setMultiSelected(selected); } }); } public void setMultiSelected(final List<Long> identifiers) { if (identifiers == null) { // Null means "all of the type", just like in the DAO setMultiSelected(true); return; } accept(new Visitor() { @Override public void visit(MultiSelectableTreeItem treeItem) { super.visit(treeItem); treeItem.setMultiSelected(false); if (treeItem instanceof AccountItem) { AccountItem item = (AccountItem) treeItem; if (identifiers.contains(item.getAccount().getId())) treeItem.setMultiSelected(true); } } }); } abstract public static class AccountSelectionHandler implements SelectionHandler<TreeItem> { public static class DefaultAccountSelectionHandler extends AccountSelectionHandler { @Override public boolean onAccountGroupSelection(Long id, String name) { return true; } @Override public boolean onAccountSelection(Account account) { return true; } @Override public boolean onSelection(AccountType type) { return true; } } @Override public void onSelection(SelectionEvent<TreeItem> event) { boolean cont = true; MultiSelectableTreeItem item = (MultiSelectableTreeItem) event.getSelectedItem(); AccountTree tree = (AccountTree) item.getTree(); if (item instanceof GroupItem) { GroupItem i = (GroupItem) item; cont = onAccountGroupSelection(i.id, i.name); } else if (item instanceof AccountItem) { AccountItem i = (AccountItem) item; cont = onAccountSelection(i.account); } else if (item.equals(tree.root)) { cont = onSelection(tree.type); } // If the subclass wants it, continue and expand/collapse item if (cont) { item.setState(!item.getState()); } } public abstract boolean onAccountGroupSelection(Long id, String name); public abstract boolean onAccountSelection(Account account); public abstract boolean onSelection(AccountType type); } protected class AccountLabel extends Label { AccountLabel(String text, String style, final String hoverStyle) { super(text); addStyleName(style); addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent event) { addStyleName(hoverStyle); } }); addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent event) { removeStyleName(hoverStyle); } }); } } protected class RootItem extends MultiSelectableTreeItem { public RootItem(String label) { super( new AccountLabel(label, style.accountTypeLabel(), style.accountTypeLabelHover()), true ); } @Override protected boolean isAddedToMultiSelection() { return false; } } protected class GroupItem extends MultiSelectableTreeItem { final Long id; final String name; public GroupItem(Long id, String name) { super( new AccountLabel(name, style.accountGroupLabel(), style.accountGroupHover()), true ); this.id = id; this.name = name; } @Override protected boolean isAddedToMultiSelection() { return false; } } protected class AccountItem extends MultiSelectableTreeItem { final Account account; public AccountItem(Account account) { super(new AccountLabel( account.getLabel(false, false, false, true), style.accountLabel(), style.accountLabelHover() )); this.account = account; } public Account getAccount() { return account; } } public static class Visitor implements TreeItemVisitor<MultiSelectableTreeItem> { @Override public void visit(MultiSelectableTreeItem treeItem) { if (treeItem instanceof RootItem) { visit((RootItem) treeItem); } else if (treeItem instanceof GroupItem) { visit((GroupItem) treeItem); } else if (treeItem instanceof AccountItem) { visit((AccountItem) treeItem); } } public void visit(RootItem item) { } public void visit(GroupItem item) { } public void visit(AccountItem item) { } } }