OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 156 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
182 ilm 4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
18 ilm 5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.erp.panel;
15
 
16
import org.openconcerto.sql.Configuration;
17
import org.openconcerto.sql.element.SQLElement;
18
import org.openconcerto.sql.model.SQLRow;
67 ilm 19
import org.openconcerto.sql.model.SQLRowListRSH;
18 ilm 20
import org.openconcerto.sql.model.SQLRowValues;
21
import org.openconcerto.sql.model.SQLSelect;
22
import org.openconcerto.sql.model.SQLTable;
23
import org.openconcerto.sql.model.SQLTableListener;
67 ilm 24
import org.openconcerto.sql.model.UndefinedRowValuesCache;
18 ilm 25
import org.openconcerto.sql.request.SQLRowItemView;
26
import org.openconcerto.sql.sqlobject.itemview.RowItemViewComponent;
27
import org.openconcerto.sql.view.EditFrame;
151 ilm 28
import org.openconcerto.ui.FontUtils;
18 ilm 29
import org.openconcerto.ui.FrameUtil;
30
import org.openconcerto.ui.valuewrapper.ValueWrapper;
67 ilm 31
import org.openconcerto.utils.ExceptionHandler;
73 ilm 32
import org.openconcerto.utils.checks.EmptyChangeSupport;
18 ilm 33
import org.openconcerto.utils.checks.EmptyListener;
73 ilm 34
import org.openconcerto.utils.checks.EmptyObj;
18 ilm 35
import org.openconcerto.utils.checks.ValidListener;
21 ilm 36
import org.openconcerto.utils.checks.ValidState;
18 ilm 37
 
38
import java.awt.event.ActionEvent;
182 ilm 39
import java.awt.event.HierarchyEvent;
40
import java.awt.event.HierarchyListener;
18 ilm 41
import java.awt.event.MouseEvent;
42
import java.awt.event.MouseListener;
43
import java.beans.PropertyChangeListener;
44
import java.beans.PropertyChangeSupport;
45
import java.sql.SQLException;
46
import java.util.HashMap;
156 ilm 47
import java.util.HashSet;
18 ilm 48
import java.util.List;
49
import java.util.Map;
156 ilm 50
import java.util.Set;
67 ilm 51
import java.util.concurrent.ExecutionException;
18 ilm 52
 
53
import javax.swing.AbstractAction;
54
import javax.swing.JComponent;
55
import javax.swing.JPopupMenu;
56
import javax.swing.JTree;
142 ilm 57
import javax.swing.SwingWorker;
18 ilm 58
import javax.swing.event.TreeSelectionEvent;
59
import javax.swing.event.TreeSelectionListener;
60
import javax.swing.tree.DefaultTreeCellRenderer;
61
import javax.swing.tree.DefaultTreeModel;
62
import javax.swing.tree.TreePath;
63
import javax.swing.tree.TreeSelectionModel;
64
 
65
// TODO Drag'n drop des nodes
73 ilm 66
public class ITreeSelection extends JTree implements MouseListener, EmptyObj, ValueWrapper<Integer>, RowItemViewComponent {
18 ilm 67
 
68
    private SQLElement element;
69
 
70
    private ITreeSelectionNode rootNode;
71
    private DefaultTreeModel model;
72
 
73
    // Map <Id, Node>
182 ilm 74
    private final Map<Integer, ITreeSelectionNode> mapNode = new HashMap<Integer, ITreeSelectionNode>();
18 ilm 75
 
76
    protected static final int EMPTY_ID = SQLRow.MIN_VALID_ID - 1;
73 ilm 77
    private final EmptyChangeSupport helper;
18 ilm 78
    private final PropertyChangeSupport supp;
182 ilm 79
    private final SQLTableListener listener;
18 ilm 80
 
81
    public ITreeSelection() {
82
        this(null);
83
    }
84
 
85
    public ITreeSelection(SQLElement element) {
86
        super();
87
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
88
        renderer.setOpenIcon(null);
89
        renderer.setClosedIcon(null);
90
        renderer.setLeafIcon(null);
91
        this.setCellRenderer(renderer);
151 ilm 92
        // HighDPI
93
        this.setRowHeight(FontUtils.getPreferredRowHeight(this));
94
        // Selection
18 ilm 95
        this.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
96
        this.element = element;
97
 
98
        this.supp = new PropertyChangeSupport(this);
73 ilm 99
        this.helper = new EmptyChangeSupport(this);
18 ilm 100
 
101
        // Value changed
102
        this.addTreeSelectionListener(new TreeSelectionListener() {
103
            public void valueChanged(TreeSelectionEvent e) {
73 ilm 104
                ITreeSelection.this.supp.firePropertyChange("value", null, getValue());
105
                ITreeSelection.this.helper.fireEmptyChange(isEmpty());
18 ilm 106
            }
107
        });
108
 
182 ilm 109
        this.listener = new SQLTableListener() {
110
            public void rowModified(SQLTable table, int id) {
111
                final ITreeSelectionNode node = ITreeSelection.this.mapNode.get(Integer.valueOf(id));
112
                if (node != null) {
113
                    modifyNode(table.getRow(id), node);
114
                }
115
            }
116
 
117
            public void rowAdded(SQLTable table, int id) {
118
                final SQLRow row = table.getRow(id);
119
                int idPere = row.getInt("ID_" + element.getTable().getName() + "_PERE");
120
                addNewNode(null, row, idPere, new HashSet<>());
121
            }
122
 
123
            public void rowDeleted(SQLTable table, int id) {
124
                final ITreeSelectionNode node = ITreeSelection.this.mapNode.get(Integer.valueOf(id));
125
                for (int i = 0; i < node.getChildCount(); i++) {
126
                    removeNode(table.getRow(id), node);
127
                }
128
            }
129
        };
130
 
18 ilm 131
    }
132
 
133
    private void initTree() {
134
        if (this.element == null) {
135
            this.rootNode = new ITreeSelectionNode(null);
136
        } else {
182 ilm 137
            SQLRowValues row = UndefinedRowValuesCache.getInstance().getDefaultRowValues(this.element.getTable());
18 ilm 138
            this.rootNode = new ITreeSelectionNode(row);
139
        }
140
        this.model = new DefaultTreeModel(this.rootNode);
141
        this.setModel(this.model);
142
        loadTree();
143
        this.addMouseListener(this);
182 ilm 144
        this.element.getTable().addTableListener(this.listener);
145
        this.addHierarchyListener(new HierarchyListener() {
146
 
147
            @Override
148
            public void hierarchyChanged(HierarchyEvent e) {
149
                // check for Hierarchy event
150
                if (e.getChangeFlags() == HierarchyEvent.DISPLAYABILITY_CHANGED) {
151
                    // do the required action upon close
152
                    if (!isDisplayable()) {
153
                        ITreeSelection.this.element.getTable().removeTableListener(ITreeSelection.this.listener);
154
                    }
155
 
156
                }
157
 
158
            }
159
        });
18 ilm 160
    }
161
 
162
    public void mouseClicked(MouseEvent e) {
163
    }
164
 
165
    public void mouseEntered(MouseEvent e) {
166
    }
167
 
168
    public void mouseExited(MouseEvent e) {
83 ilm 169
    }
18 ilm 170
 
83 ilm 171
    public void mouseReleased(MouseEvent e) {
18 ilm 172
    }
173
 
174
    public void mousePressed(MouseEvent e) {
175
 
176
        TreePath path = this.getSelectionPath();
177
        if (path != null) {
178
            if (e.getButton() == MouseEvent.BUTTON3) {
179
 
180
                final int idSelect = getSelectedID();
181
 
182
                // Ajouter, supprimer, modifier un élément dans l'arbre
183
 
184
                JPopupMenu menu = new JPopupMenu();
185
                menu.add(new AbstractAction("Ajouter un élément") {
186
                    public void actionPerformed(ActionEvent e) {
187
                        addElement(idSelect);
188
                    }
189
                });
190
 
191
                if (idSelect > 1) {
192
                    menu.add(new AbstractAction("Modifier") {
193
                        public void actionPerformed(ActionEvent e) {
194
                            modifyElement(idSelect);
195
                        }
196
                    });
197
 
198
                    menu.add(new AbstractAction("Supprimer") {
199
                        public void actionPerformed(ActionEvent e) {
200
                            removeElement(idSelect);
201
                        }
202
                    });
203
                }
204
                menu.show(e.getComponent(), e.getPoint().x, e.getPoint().y);
205
            }
206
        }
207
    }
208
 
209
    public int getSelectedID() {
210
        TreePath path = this.getSelectionPath();
211
        int id = 1;
212
        if (path != null) {
213
            Object o = path.getLastPathComponent();
214
            if (o instanceof ITreeSelectionNode) {
215
                final ITreeSelectionNode nodeSelect = (ITreeSelectionNode) o;
216
                id = nodeSelect.getId();
217
            }
218
        }
219
        return id;
220
    }
221
 
222
    /**
223
     * Ajouter une feuille
224
     */
225
    public void addElement(int idRoot) {
182 ilm 226
        EditFrame frameAdd = new EditFrame(this.element, EditFrame.CREATION);
227
        SQLRowValues rowVals = new SQLRowValues(this.element.getTable());
18 ilm 228
        if (idRoot > 1) {
182 ilm 229
            rowVals.put("ID_" + this.element.getTable().getName() + "_PERE", idRoot);
18 ilm 230
            frameAdd.getSQLComponent().select(rowVals);
231
        }
232
        FrameUtil.showPacked(frameAdd);
233
 
234
    }
235
 
236
    /**
237
     * Supprimer la feuille
238
     */
239
    public void removeElement(int id) {
240
        if (id > 1) {
241
            try {
182 ilm 242
                this.element.archive(id);
18 ilm 243
            } catch (SQLException e1) {
244
                e1.printStackTrace();
245
            }
246
        }
247
    }
248
 
249
    /**
250
     * Modifier la feuille
251
     */
252
    public void modifyElement(int id) {
253
        if (id > 1) {
182 ilm 254
            EditFrame frameModFamille = new EditFrame(this.element, EditFrame.MODIFICATION);
18 ilm 255
            frameModFamille.selectionId(id, 1);
256
            FrameUtil.showPacked(frameModFamille);
257
        }
258
    }
259
 
260
    public JComponent getComp() {
261
        return this;
262
    }
263
 
264
    public void resetValue() {
265
        this.setValue(1);
266
    }
267
 
73 ilm 268
    @Override
18 ilm 269
    public void addEmptyListener(EmptyListener l) {
73 ilm 270
        this.helper.addEmptyListener(l);
18 ilm 271
    }
272
 
73 ilm 273
    @Override
274
    public void removeEmptyListener(EmptyListener l) {
275
        this.helper.removeEmptyListener(l);
276
    }
277
 
18 ilm 278
    public void addValueListener(PropertyChangeListener l) {
279
        this.supp.addPropertyChangeListener(l);
280
    }
281
 
282
    @Override
283
    public void rmValueListener(PropertyChangeListener l) {
284
        this.supp.removePropertyChangeListener(l);
285
    }
286
 
73 ilm 287
    public Integer getValue() {
18 ilm 288
        int id = 1;
289
        TreePath path = this.getSelectionPath();
290
 
291
        if (path != null) {
292
            Object o = path.getLastPathComponent();
293
 
294
            if (o instanceof ITreeSelectionNode) {
295
                final ITreeSelectionNode nodeSelect = (ITreeSelectionNode) o;
296
                id = nodeSelect.getId();
297
            }
298
        }
299
        return id;
300
    }
301
 
73 ilm 302
    @Override
18 ilm 303
    public boolean isEmpty() {
73 ilm 304
        return this.getValue().intValue() <= EMPTY_ID;
18 ilm 305
    }
306
 
307
    public void addValidListener(ValidListener l) {
308
    }
309
 
19 ilm 310
    @Override
311
    public void removeValidListener(ValidListener l) {
312
    }
313
 
21 ilm 314
    @Override
315
    public ValidState getValidState() {
316
        // return "Aucune valeur sélectionnée dans l'arbre";
317
        return ValidState.getTrueInstance();
18 ilm 318
    }
319
 
320
    @Override
321
    public void init(SQLRowItemView v) {
322
        if (this.element == null) {
323
            final SQLTable foreignTable = v.getField().getTable().getDBSystemRoot().getGraph().getForeignTable(v.getField());
324
            this.element = Configuration.getInstance().getDirectory().getElement(foreignTable);
325
        }
326
        initTree();
327
    }
328
 
329
    public void setValue(Integer val) {
83 ilm 330
        if (val == null) {
18 ilm 331
            val = EMPTY_ID;
83 ilm 332
        }
333
        final ITreeSelectionNode v = this.mapNode.get(val);
18 ilm 334
        if (v.getId() == val) {
335
            this.setExpandsSelectedPaths(true);
336
            this.setSelectionPath(new TreePath(v.getPath()));
337
        }
338
 
339
    }
340
 
341
    private void loadTree() {
142 ilm 342
        new SwingWorker<List<SQLRow>, Object>() {
67 ilm 343
            @Override
344
            protected List<SQLRow> doInBackground() throws Exception {
182 ilm 345
                final SQLTable table = ITreeSelection.this.element.getTable();
83 ilm 346
                final SQLSelect sel = new SQLSelect();
67 ilm 347
                sel.addSelectStar(table);
348
                return SQLRowListRSH.execute(sel);
349
            }
18 ilm 350
 
67 ilm 351
            @Override
352
            protected void done() {
353
                List<SQLRow> l;
354
                try {
355
                    l = get();
356
                    if (l != null) {
142 ilm 357
                        Map<Integer, SQLRow> familles = new HashMap<Integer, SQLRow>();
67 ilm 358
                        for (int i = 0; i < l.size(); i++) {
359
                            SQLRow row = l.get(i);
142 ilm 360
                            familles.put(row.getID(), row);
67 ilm 361
                        }
142 ilm 362
                        for (int i = 0; i < l.size(); i++) {
363
                            SQLRow row = l.get(i);
182 ilm 364
                            addNewNode(familles, row, row.getInt("ID_" + ITreeSelection.this.element.getTable().getName() + "_PERE"), new HashSet<>());
142 ilm 365
                        }
67 ilm 366
                        expandRow(0);
367
                    }
368
                } catch (InterruptedException e) {
369
                    ExceptionHandler.handle("", e);
370
                } catch (ExecutionException e) {
371
                    ExceptionHandler.handle("", e);
372
                }
18 ilm 373
            }
142 ilm 374
        }.execute();
18 ilm 375
    }
376
 
377
    /**
378
     * Ajoute une famille dans l'arbre
379
     *
380
     * @param id
381
     * @param idPere
382
     */
156 ilm 383
    private void addNewNode(Map<Integer, SQLRow> familles, SQLRow row, int idPere, Set<Integer> addedIDs) {
144 ilm 384
        if (row != null && this.mapNode.get(row.getID()) == null) {
142 ilm 385
            ITreeSelectionNode nodePere = this.mapNode.get(Integer.valueOf(idPere));
386
            if (idPere > 1 && nodePere == null && familles != null) {
144 ilm 387
                final SQLRow rowPere = familles.get(idPere);
156 ilm 388
                if (idPere != row.getID()) {
389
                    if (!addedIDs.contains(idPere)) {
390
                        addedIDs.add(idPere);
182 ilm 391
                        addNewNode(familles, rowPere, rowPere.getInt("ID_" + this.element.getTable().getName() + "_PERE"), addedIDs);
156 ilm 392
                    }
144 ilm 393
                }
142 ilm 394
                nodePere = this.mapNode.get(Integer.valueOf(idPere));
395
            }
144 ilm 396
            final ITreeSelectionNode newNode = new ITreeSelectionNode(row);
142 ilm 397
            this.mapNode.put(row.getID(), newNode);
144 ilm 398
            if (!row.isUndefined()) {
142 ilm 399
                if (nodePere != null && idPere > 1) {
400
                    addNode(newNode, nodePere);
401
                } else {
402
                    if (idPere == 1) {
182 ilm 403
                        addNode(newNode, this.rootNode);
142 ilm 404
                    }
18 ilm 405
                }
406
            }
407
        }
408
    }
409
 
410
    /**
411
     * Ajoute un noeud dans l'arbre dans l'ordre alphabétique
412
     *
413
     * @param nodeToAdd
414
     * @param nodeParent
415
     */
416
    private void addNode(ITreeSelectionNode nodeToAdd, ITreeSelectionNode nodeParent) {
417
        int n = 0;
83 ilm 418
        final int childCount = nodeParent.getChildCount();
419
        for (; n < childCount; n++) {
18 ilm 420
            if (nodeToAdd.toString().compareToIgnoreCase(nodeParent.getChildAt(n).toString()) < 0) {
421
                break;
422
            }
423
        }
182 ilm 424
        this.model.insertNodeInto(nodeToAdd, nodeParent, n);
18 ilm 425
    }
426
 
427
    /**
428
     *
429
     * @param row
430
     * @param nodeParent
431
     */
432
    private void modifyNode(SQLRow row, ITreeSelectionNode node) {
83 ilm 433
        if (row.isArchived() && node.getParent() != null) {
182 ilm 434
            this.model.removeNodeFromParent(node);
18 ilm 435
        } else {
436
            node.setRow(row);
182 ilm 437
            this.model.nodeChanged(node);
18 ilm 438
        }
439
    }
440
 
441
    /**
442
     * Suppression d'un noeud
443
     *
444
     * @param row
445
     * @param nodeParent
446
     */
447
    private void removeNode(SQLRow row, ITreeSelectionNode nodeParent) {
83 ilm 448
        final int childCount = nodeParent.getChildCount();
449
        for (int i = 0; i < childCount; i++) {
450
            final ITreeSelectionNode v = (ITreeSelectionNode) nodeParent.getChildAt(i);
18 ilm 451
            if (v.getId() == row.getID()) {
182 ilm 452
                this.model.removeNodeFromParent(v);
18 ilm 453
            }
454
        }
455
    }
456
 
457
    /**
458
     * Table listener permettant de rafraichir l'arbre
459
     *
460
     */
461
    private void setTableListener() {
462
 
182 ilm 463
        this.element.getTable().addTableListener(this.listener);
18 ilm 464
    }
465
}