Dépôt officiel du code source de l'ERP OpenConcerto
Rev 151 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.panel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTableListener;
import org.openconcerto.sql.model.UndefinedRowValuesCache;
import org.openconcerto.sql.request.SQLRowItemView;
import org.openconcerto.sql.sqlobject.itemview.RowItemViewComponent;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.FrameUtil;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.checks.EmptyChangeSupport;
import org.openconcerto.utils.checks.EmptyListener;
import org.openconcerto.utils.checks.EmptyObj;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.SwingWorker;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
// TODO Drag'n drop des nodes
public class ITreeSelection extends JTree implements MouseListener, EmptyObj, ValueWrapper<Integer>, RowItemViewComponent {
private SQLElement element;
private ITreeSelectionNode rootNode;
private DefaultTreeModel model;
// Map <Id, Node>
private Map<Integer, ITreeSelectionNode> mapNode = new HashMap<Integer, ITreeSelectionNode>();
protected static final int EMPTY_ID = SQLRow.MIN_VALID_ID - 1;
private final EmptyChangeSupport helper;
private final PropertyChangeSupport supp;
public ITreeSelection() {
this(null);
}
public ITreeSelection(SQLElement element) {
super();
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
renderer.setOpenIcon(null);
renderer.setClosedIcon(null);
renderer.setLeafIcon(null);
this.setCellRenderer(renderer);
// HighDPI
this.setRowHeight(FontUtils.getPreferredRowHeight(this));
// Selection
this.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
this.element = element;
this.supp = new PropertyChangeSupport(this);
this.helper = new EmptyChangeSupport(this);
// Value changed
this.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
ITreeSelection.this.supp.firePropertyChange("value", null, getValue());
ITreeSelection.this.helper.fireEmptyChange(isEmpty());
}
});
}
private void initTree() {
if (this.element == null) {
this.rootNode = new ITreeSelectionNode(null);
} else {
SQLRowValues row = UndefinedRowValuesCache.getInstance().getDefaultRowValues(element.getTable());
this.rootNode = new ITreeSelectionNode(row);
}
this.model = new DefaultTreeModel(this.rootNode);
this.setModel(this.model);
loadTree();
setTableListener();
this.addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
TreePath path = this.getSelectionPath();
if (path != null) {
if (e.getButton() == MouseEvent.BUTTON3) {
final int idSelect = getSelectedID();
// Ajouter, supprimer, modifier un élément dans l'arbre
JPopupMenu menu = new JPopupMenu();
menu.add(new AbstractAction("Ajouter un élément") {
public void actionPerformed(ActionEvent e) {
addElement(idSelect);
}
});
if (idSelect > 1) {
menu.add(new AbstractAction("Modifier") {
public void actionPerformed(ActionEvent e) {
modifyElement(idSelect);
}
});
menu.add(new AbstractAction("Supprimer") {
public void actionPerformed(ActionEvent e) {
removeElement(idSelect);
}
});
}
menu.show(e.getComponent(), e.getPoint().x, e.getPoint().y);
}
}
}
public int getSelectedID() {
TreePath path = this.getSelectionPath();
int id = 1;
if (path != null) {
Object o = path.getLastPathComponent();
if (o instanceof ITreeSelectionNode) {
final ITreeSelectionNode nodeSelect = (ITreeSelectionNode) o;
id = nodeSelect.getId();
}
}
return id;
}
/**
* Ajouter une feuille
*/
public void addElement(int idRoot) {
EditFrame frameAdd = new EditFrame(element, EditFrame.CREATION);
SQLRowValues rowVals = new SQLRowValues(element.getTable());
if (idRoot > 1) {
rowVals.put("ID_" + element.getTable().getName() + "_PERE", idRoot);
frameAdd.getSQLComponent().select(rowVals);
}
FrameUtil.showPacked(frameAdd);
}
/**
* Supprimer la feuille
*/
public void removeElement(int id) {
if (id > 1) {
try {
element.archive(id);
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
/**
* Modifier la feuille
*/
public void modifyElement(int id) {
if (id > 1) {
EditFrame frameModFamille = new EditFrame(element, EditFrame.MODIFICATION);
frameModFamille.selectionId(id, 1);
FrameUtil.showPacked(frameModFamille);
}
}
public JComponent getComp() {
return this;
}
public void resetValue() {
this.setValue(1);
}
@Override
public void addEmptyListener(EmptyListener l) {
this.helper.addEmptyListener(l);
}
@Override
public void removeEmptyListener(EmptyListener l) {
this.helper.removeEmptyListener(l);
}
public void addValueListener(PropertyChangeListener l) {
this.supp.addPropertyChangeListener(l);
}
@Override
public void rmValueListener(PropertyChangeListener l) {
this.supp.removePropertyChangeListener(l);
}
public Integer getValue() {
int id = 1;
TreePath path = this.getSelectionPath();
if (path != null) {
Object o = path.getLastPathComponent();
if (o instanceof ITreeSelectionNode) {
final ITreeSelectionNode nodeSelect = (ITreeSelectionNode) o;
id = nodeSelect.getId();
}
}
return id;
}
@Override
public boolean isEmpty() {
return this.getValue().intValue() <= EMPTY_ID;
}
public void addValidListener(ValidListener l) {
}
@Override
public void removeValidListener(ValidListener l) {
}
@Override
public ValidState getValidState() {
// return "Aucune valeur sélectionnée dans l'arbre";
return ValidState.getTrueInstance();
}
@Override
public void init(SQLRowItemView v) {
if (this.element == null) {
final SQLTable foreignTable = v.getField().getTable().getDBSystemRoot().getGraph().getForeignTable(v.getField());
this.element = Configuration.getInstance().getDirectory().getElement(foreignTable);
}
initTree();
}
public void setValue(Integer val) {
if (val == null) {
val = EMPTY_ID;
}
final ITreeSelectionNode v = this.mapNode.get(val);
if (v.getId() == val) {
this.setExpandsSelectedPaths(true);
this.setSelectionPath(new TreePath(v.getPath()));
}
}
private void loadTree() {
new SwingWorker<List<SQLRow>, Object>() {
@Override
protected List<SQLRow> doInBackground() throws Exception {
final SQLTable table = element.getTable();
final SQLSelect sel = new SQLSelect();
sel.addSelectStar(table);
return SQLRowListRSH.execute(sel);
}
@Override
protected void done() {
List<SQLRow> l;
try {
l = get();
if (l != null) {
Map<Integer, SQLRow> familles = new HashMap<Integer, SQLRow>();
for (int i = 0; i < l.size(); i++) {
SQLRow row = l.get(i);
familles.put(row.getID(), row);
}
for (int i = 0; i < l.size(); i++) {
SQLRow row = l.get(i);
addNewNode(familles, row, row.getInt("ID_" + element.getTable().getName() + "_PERE"), new HashSet<>());
}
expandRow(0);
}
} catch (InterruptedException e) {
ExceptionHandler.handle("", e);
} catch (ExecutionException e) {
ExceptionHandler.handle("", e);
}
}
}.execute();
}
/**
* Ajoute une famille dans l'arbre
*
* @param id
* @param idPere
*/
private void addNewNode(Map<Integer, SQLRow> familles, SQLRow row, int idPere, Set<Integer> addedIDs) {
if (row != null && this.mapNode.get(row.getID()) == null) {
ITreeSelectionNode nodePere = this.mapNode.get(Integer.valueOf(idPere));
if (idPere > 1 && nodePere == null && familles != null) {
final SQLRow rowPere = familles.get(idPere);
if (idPere != row.getID()) {
if (!addedIDs.contains(idPere)) {
addedIDs.add(idPere);
addNewNode(familles, rowPere, rowPere.getInt("ID_" + element.getTable().getName() + "_PERE"), addedIDs);
}
}
nodePere = this.mapNode.get(Integer.valueOf(idPere));
}
final ITreeSelectionNode newNode = new ITreeSelectionNode(row);
this.mapNode.put(row.getID(), newNode);
if (!row.isUndefined()) {
if (nodePere != null && idPere > 1) {
addNode(newNode, nodePere);
} else {
if (idPere == 1) {
addNode(newNode, rootNode);
}
}
}
}
}
/**
* Ajoute un noeud dans l'arbre dans l'ordre alphabétique
*
* @param nodeToAdd
* @param nodeParent
*/
private void addNode(ITreeSelectionNode nodeToAdd, ITreeSelectionNode nodeParent) {
int n = 0;
final int childCount = nodeParent.getChildCount();
for (; n < childCount; n++) {
if (nodeToAdd.toString().compareToIgnoreCase(nodeParent.getChildAt(n).toString()) < 0) {
break;
}
}
model.insertNodeInto(nodeToAdd, nodeParent, n);
}
/**
*
* @param row
* @param nodeParent
*/
private void modifyNode(SQLRow row, ITreeSelectionNode node) {
if (row.isArchived() && node.getParent() != null) {
model.removeNodeFromParent(node);
} else {
node.setRow(row);
model.nodeChanged(node);
}
}
/**
* Suppression d'un noeud
*
* @param row
* @param nodeParent
*/
private void removeNode(SQLRow row, ITreeSelectionNode nodeParent) {
final int childCount = nodeParent.getChildCount();
for (int i = 0; i < childCount; i++) {
final ITreeSelectionNode v = (ITreeSelectionNode) nodeParent.getChildAt(i);
if (v.getId() == row.getID()) {
model.removeNodeFromParent(v);
}
}
}
/**
* Table listener permettant de rafraichir l'arbre
*
*/
private void setTableListener() {
final SQLTableListener listener = new SQLTableListener() {
public void rowModified(SQLTable table, int id) {
final ITreeSelectionNode node = mapNode.get(Integer.valueOf(id));
if (node != null) {
modifyNode(table.getRow(id), node);
}
}
public void rowAdded(SQLTable table, int id) {
final SQLRow row = table.getRow(id);
int idPere = row.getInt("ID_" + element.getTable().getName() + "_PERE");
addNewNode(null, row, idPere, new HashSet<>());
}
public void rowDeleted(SQLTable table, int id) {
final ITreeSelectionNode node = mapNode.get(Integer.valueOf(id));
for (int i = 0; i < node.getChildCount(); i++) {
removeNode(table.getRow(id), node);
}
}
};
this.element.getTable().addTableListener(listener);
}
}