/**
* OrbisGIS is a java GIS application dedicated to research in GIScience.
* OrbisGIS is developed by the GIS group of the DECIDE team of the
* Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>.
*
* The GIS group of the DECIDE team is located at :
*
* Laboratoire Lab-STICC – CNRS UMR 6285
* Equipe DECIDE
* UNIVERSITÉ DE BRETAGNE-SUD
* Institut Universitaire de Technologie de Vannes
* 8, Rue Montaigne - BP 561 56017 Vannes Cedex
*
* OrbisGIS is distributed under GPL 3 license.
*
* Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488)
* Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285)
*
* This file is part of OrbisGIS.
*
* OrbisGIS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* OrbisGIS 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* OrbisGIS. If not, see <http://www.gnu.org/licenses/>.
*
* For more information, please consult: <http://www.orbisgis.org/>
* or contact directly:
* info_at_ orbisgis.org
*/
package org.orbisgis.sif.components;
import java.awt.BorderLayout;
import java.awt.Component;
import java.net.URL;
import java.util.*;
import javax.swing.*;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.*;
import org.orbisgis.sif.UIFactory;
import org.orbisgis.sif.UIPanel;
import org.xnap.commons.i18n.I18n;
import org.xnap.commons.i18n.I18nFactory;
public class CategorizedChoosePanel extends JPanel implements UIPanel {
private String id;
private String title;
private Map<Option, List<Option>> categories = new HashMap<Option, List<Option>>();
private JTree tree;
private CategoriesTreeModel categoriesTreeModel;
private static final I18n i18n = I18nFactory.getI18n(CategorizedChoosePanel.class);
public CategorizedChoosePanel(String title, String id) {
this.title = title;
this.id = id;
initComponents();
}
public void addOption(String categoryId, String categoryName, String name,
String id, String icon) {
Option category = new Option(categoryId, categoryName, true, null);
List<Option> options = categories.get(category);
if (options == null) {
options = new ArrayList<Option>();
}
options.add(new Option(id, name, false, icon));
categories.put(category, options);
categoriesTreeModel.refresh();
}
private void initComponents() {
tree = new JTree();
categoriesTreeModel = new CategoriesTreeModel();
tree.setModel(categoriesTreeModel);
tree.setRootVisible(false);
tree.setCellRenderer(new IconRenderer());
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
this.setLayout(new BorderLayout());
this.add(new JScrollPane(tree), BorderLayout.CENTER);
}
public String[] getErrorMessages() {
return null;
}
public String getId() {
return id;
}
public String[] getValues() {
return new String[]{getSelectedElement()};
}
public void setValue(String fieldName, String fieldValue) {
Iterator<Option> it = categories.keySet().iterator();
while (it.hasNext()) {
Option category = it.next();
List<Option> options = categories.get(category);
for (Option option : options) {
if (option.getId().equals(fieldValue)) {
tree.setSelectionPath(new TreePath(new Object[]{
categoriesTreeModel.getRoot(), category, option}));
return;
}
}
}
}
@Override
public Component getComponent() {
return this;
}
@Override
public String getTitle() {
return title;
}
@Override
public String validateInput() {
TreePath selectionPath = tree.getSelectionPath();
if ((selectionPath == null)
|| (((Option) selectionPath.getLastPathComponent()).isCategory())) {
return i18n.tr("An item must be selected.");
}
return null;
}
@Override
public URL getIconURL() {
return UIFactory.getDefaultIcon();
}
/**
* Returns the id of the currently selected option if it's valid. If
* there is no selection or the selection is not valid it returns null
*
* @return
*/
public String getSelectedElement() {
if (validateInput() == null) {
Object selection = tree.getSelectionPath().getLastPathComponent();
return ((Option) selection).getId();
} else {
return null;
}
}
private class Option {
private String id;
private String name;
private boolean category;
private String icon;
public Option(String id, String name, boolean category, String icon) {
super();
this.id = id;
this.name = name;
this.category = category;
this.icon = icon;
}
public String getIcon() {
return icon;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Option) {
Option opt = (Option) obj;
return id.equals(opt.id);
} else {
return false;
}
}
@Override
public int hashCode() {
return id.hashCode();
}
public boolean isCategory() {
return category;
}
}
private class CategoriesTreeModel implements TreeModel {
private List<TreeModelListener> listeners = new ArrayList<TreeModelListener>();
@Override
public void addTreeModelListener(TreeModelListener l) {
listeners.add(l);
}
public void refresh() {
for (TreeModelListener listener : listeners) {
listener.treeStructureChanged(new TreeModelEvent(this,
new Object[]{getRoot()}));
}
}
@Override
public Object getChild(Object parent, int index) {
List<Object> names = getArray(parent);
return names.get(index);
}
private List<Object> getArray(Object parent) {
List<Object> names = new ArrayList<Object>();
if (parent.toString().equals("ROOT")) {
// Categories
names.addAll(categories.keySet());
} else {
// Category content
List<Option> options = categories.get((Option)parent);
if (options != null) {
names.addAll(options);
}
}
return names;
}
@Override
public int getChildCount(Object parent) {
return getArray(parent).size();
}
@Override
public int getIndexOfChild(Object parent, Object child) {
return getArray(parent).indexOf(child);
}
@Override
public Object getRoot() {
return new Option("ROOT", "ROOT", true, null);
}
@Override
public boolean isLeaf(Object node) {
return !((Option) node).isCategory();
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
listeners.remove(l);
}
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
}
}
private class IconRenderer extends DefaultTreeCellRenderer implements
TreeCellRenderer {
private Icon defaultClosedFolderIcon;
private Icon defaultOpenFolderIcon;
private Icon defaultLeafIcon;
public IconRenderer() {
this.defaultClosedFolderIcon = this.getDefaultClosedIcon();
this.defaultOpenFolderIcon = this.getDefaultOpenIcon();
this.defaultLeafIcon = this.getLeafIcon();
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel,
boolean expanded,
boolean leaf, int row,
boolean hasFocus) {
Option option = (Option) value;
if (option.getIcon() != null) {
ImageIcon icon = new ImageIcon(this.getClass().getResource(
option.getIcon()));
this.setLeafIcon(icon);
} else {
if (option.isCategory()) {
this.setOpenIcon(defaultOpenFolderIcon);
this.setClosedIcon(defaultClosedFolderIcon);
} else {
this.setLeafIcon(defaultLeafIcon);
}
}
return super.getTreeCellRendererComponent(tree, value, sel,
expanded, leaf, row, hasFocus);
}
}
}