/*
* 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) {
}
}
}