OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 17 | Rev 25 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
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.sql.view;
15
 
16
import org.openconcerto.sql.element.BaseSQLComponent;
17
import org.openconcerto.sql.element.SQLComponent;
21 ilm 18
import org.openconcerto.sql.element.SQLComponent.Mode;
17 ilm 19
import org.openconcerto.sql.element.SQLElement;
20
import org.openconcerto.sql.model.SQLField;
21
import org.openconcerto.sql.model.SQLRow;
22
import org.openconcerto.sql.model.SQLRowValues;
23
import org.openconcerto.sql.model.SQLTable;
24
import org.openconcerto.sql.users.rights.TableAllRights;
25
import org.openconcerto.sql.users.rights.UserRights;
26
import org.openconcerto.sql.users.rights.UserRightsManager;
27
import org.openconcerto.sql.view.list.IListe;
28
import org.openconcerto.utils.ExceptionHandler;
29
import org.openconcerto.utils.checks.ValidListener;
30
import org.openconcerto.utils.checks.ValidObject;
21 ilm 31
import org.openconcerto.utils.checks.ValidState;
17 ilm 32
import org.openconcerto.utils.doc.Documented;
33
 
34
import java.awt.Container;
35
import java.awt.Dimension;
36
import java.awt.GraphicsEnvironment;
37
import java.awt.GridBagConstraints;
38
import java.awt.GridBagLayout;
39
import java.awt.Insets;
40
import java.awt.Rectangle;
41
import java.awt.event.ActionEvent;
42
import java.awt.event.ActionListener;
43
import java.awt.event.ComponentListener;
44
import java.awt.event.KeyEvent;
45
import java.awt.event.MouseAdapter;
46
import java.awt.event.MouseEvent;
47
import java.beans.PropertyChangeEvent;
48
import java.beans.PropertyChangeListener;
49
import java.util.Collections;
50
import java.util.List;
51
import java.util.Vector;
52
 
53
import javax.swing.AbstractAction;
54
import javax.swing.JButton;
55
import javax.swing.JCheckBox;
56
import javax.swing.JComponent;
57
import javax.swing.JOptionPane;
58
import javax.swing.JPanel;
59
import javax.swing.JScrollPane;
60
import javax.swing.JSeparator;
61
import javax.swing.KeyStroke;
62
import javax.swing.border.Border;
63
 
64
/**
65
 * @author ilm Created on 8 oct. 2003
66
 */
67
public class EditPanel extends JPanel implements IListener, ActionListener, Documented {
68
    public static enum EditMode {
69
        CREATION {
70
            @Override
71
            protected Mode getCompMode() {
72
                return Mode.INSERTION;
73
            }
74
        },
75
        MODIFICATION {
76
            @Override
77
            protected Mode getCompMode() {
78
                return Mode.MODIFICATION;
79
            }
80
        },
81
        READONLY {
82
            @Override
83
            protected Mode getCompMode() {
84
                return null;
85
            }
86
        };
87
        protected abstract Mode getCompMode();
88
    };
89
 
90
    /**
91
     * If this system property is true, then new lines are always added at the end of the list.
92
     * Otherwise they're added after the selection.
93
     */
94
    public final static String ADD_AT_THE_END = "org.openconcerto.sql.editPanel.endAdd";
95
 
96
    public final static EditMode CREATION = EditMode.CREATION;
97
    public final static EditMode MODIFICATION = EditMode.MODIFICATION;
98
    public final static EditMode READONLY = EditMode.READONLY;
99
 
100
    private final EditMode mode;
101
    private JButton jButtonSupprimer;
102
    private JButton jButtonModifier;
103
    private JButton jButtonAjouter;
104
    private JButton jButtonAnnuler;
105
    private final SQLComponent component;
106
 
107
    private JCheckBox keepOpen = new JCheckBox("ne pas fermer la fenêtre");
108
 
109
    private final List<EditPanelListener> panelListeners = new Vector<EditPanelListener>();// EditPanelListener
110
    private JScrollPane p;
111
    private final SQLElement element;
112
    private IListe l;
113
    // whether our component is valid
21 ilm 114
    private ValidState valid = ValidState.getNoReasonInstance(false);
17 ilm 115
 
116
    /**
117
     * Creates an creation panel
118
     *
119
     * @param e the element to display.
120
     */
121
    public EditPanel(SQLElement e) {
122
        this(e, CREATION);
123
    }
124
 
125
    public EditPanel(SQLElement e, EditMode mode) {
126
        this(e.createComponent(), mode);
127
    }
128
 
129
    public EditPanel(SQLComponent e, EditMode mode) {
130
        this(e, mode, Collections.<SQLField> emptyList());
131
    }
132
 
133
    public EditPanel(SQLElement e, EditMode mode, List<SQLField> hiddenFields) {
134
        this(e.createComponent(), mode, hiddenFields);
135
    }
136
 
137
    /**
138
     * Creates an instance:
139
     * <ul>
140
     * <li>to create if mode is CREATION</li>
141
     * <li>to modify if MODIFICATION</li>
142
     * <li>to view if READONLY</li>
143
     * </ul>
144
     * use "org.openconcerto.editpanel.noborder" and "org.openconcerto.editpanel.separator" for custom style
145
     *
146
     * @param e the element to display.
147
     * @param mode the edit mode, one of CREATION, MODIFICATION or READONLY.
148
     * @param hiddenFields
149
     */
150
    public EditPanel(SQLComponent e, EditMode mode, List<SQLField> hiddenFields) {
151
        super();
152
 
153
        this.l = null;
154
 
155
        // ATTN verification seulement dans uiInit()
156
        this.mode = mode;
157
        this.element = e.getElement();
158
 
159
        this.component = e;
160
        try {
161
            this.component.setMode(mode.getCompMode());
162
            this.component.setNonExistantEditable(this.mode == CREATION);
163
            if (this.component instanceof BaseSQLComponent) {
164
                for (int i = 0; i < hiddenFields.size(); i++) {
165
                    final SQLField hiddenField = hiddenFields.get(i);
166
                    ((BaseSQLComponent) this.component).doNotShow(hiddenField);
167
                }
168
            }
169
 
170
            if (this.mode == READONLY) {
171
                this.component.setEditable(false);
172
            } else {
173
                // on écoute les changements de validation,
174
                // avant component.uiInit() car il fait un fireValidChange()
175
                this.component.addValidListener(new ValidListener() {
176
                    @Override
21 ilm 177
                    public void validChange(ValidObject src, ValidState newValue) {
17 ilm 178
                        // expensive so cache it
179
                        EditPanel.this.valid = newValue;
180
                        updateBtns();
181
                    }
182
                });
183
                ((BaseSQLComponent) this.component).addSelectionListener(new PropertyChangeListener() {
184
                    @Override
185
                    public void propertyChange(PropertyChangeEvent evt) {
186
                        updateBtns();
187
                    }
188
                });
189
            }
190
 
191
            this.uiInit();
192
            this.component.uiInit();
193
 
194
            if (Boolean.getBoolean("org.openconcerto.editpanel.noborder")) {
195
                this.setInnerBorder(null);
196
            }
197
        } catch (Exception ex) {
198
            ExceptionHandler.handle("Erreur d'initialisation", ex);
199
        }
200
    }
201
 
202
    private void updateBtns() {
203
        updateBtn(this.jButtonAjouter, true, false, "d'ajouter", TableAllRights.ADD_ROW_TABLE);
204
        updateBtn(this.jButtonModifier, true, true, "de modifier", TableAllRights.MODIFY_ROW_TABLE);
205
        updateBtn(this.jButtonSupprimer, false, true, "de supprimer", TableAllRights.DELETE_ROW_TABLE);
206
    }
207
 
208
    private void updateBtn(final JButton b, final boolean needValid, final boolean needID, final String desc, final String code) {
209
        if (b != null) {
21 ilm 210
            final ValidState res;
17 ilm 211
            final boolean idOK = this.getSQLComponent().getSelectedID() >= SQLRow.MIN_VALID_ID;
212
            final UserRights rights = UserRightsManager.getCurrentUserRights();
213
            if (!TableAllRights.hasRight(rights, code, getSQLComponent().getElement().getTable())) {
21 ilm 214
                res = ValidState.createCached(false, "Vous n'avez pas le droit " + desc);
17 ilm 215
            } else if (needID && !idOK)
21 ilm 216
                res = ValidState.createCached(false, "cet élément n'existe pas");
217
            else if (needValid && !this.valid.isValid())
218
                res = this.valid;
17 ilm 219
            else
21 ilm 220
                res = ValidState.getTrueInstance();
221
            updateBtn(b, res);
17 ilm 222
        }
223
    }
224
 
225
    private final void uiInit() {
226
        this.fill();
227
 
228
        // les raccourcis claviers
229
        this.component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.CTRL_DOWN_MASK), "add");
230
        this.component.getActionMap().put("add", new AbstractAction() {
231
            public void actionPerformed(ActionEvent e) {
232
                ajouter();
233
            }
234
        });
235
    }
236
 
237
    protected void fill() {
238
        Container container = this;
239
 
240
        container.setLayout(new GridBagLayout());
241
        GridBagConstraints c = new GridBagConstraints();
242
        c.gridx = 0;
243
        c.gridy = 0;
244
        c.gridheight = 1;
245
        c.gridwidth = 4;
246
        c.fill = GridBagConstraints.HORIZONTAL;
247
        c.weighty = 1;
248
        c.weightx = 0;
249
        c.insets = new Insets(2, 2, 1, 2);
250
        // container.add(new JLabel(this.getTitle()), c);
251
 
252
        c.weighty = 1;
253
        c.weightx = 1;
254
        c.fill = GridBagConstraints.BOTH;
255
 
256
        this.p = new JScrollPane(this.component);
257
        this.p.getVerticalScrollBar().setUnitIncrement(9);
258
        this.p.setOpaque(false);
259
        this.p.getViewport().setOpaque(false);
260
 
261
        container.add(this.p, c);
262
 
263
        // Separator, if needed
264
        if (Boolean.getBoolean("org.openconcerto.editpanel.separator")) {
265
            c.gridy++;
266
            c.weightx = 1;
267
            c.weighty = 0;
268
            c.gridwidth = GridBagConstraints.REMAINDER;
269
            c.fill = GridBagConstraints.BOTH;
270
            final JSeparator comp = new JSeparator();
271
            // Evite les tremblements verticaux
272
            comp.setMinimumSize(new Dimension(comp.getPreferredSize()));
273
            container.add(comp, c);
274
        }
275
 
276
        // Buttons
277
        c.gridy++;
278
        c.weightx = 1;
279
        c.weighty = 0;
280
        c.gridwidth = 1;
281
        c.gridheight = 1;
282
        c.fill = GridBagConstraints.NONE;
283
        this.keepOpen.setOpaque(false);
284
        if (this.mode == CREATION) {
285
 
286
            c.gridx = 1;
287
            c.fill = GridBagConstraints.HORIZONTAL;
288
            c.anchor = GridBagConstraints.EAST;
289
            if (!Boolean.getBoolean("org.openconcerto.editpanel.hideKeepOpen")) {
290
                container.add(this.keepOpen, c);
291
            }
292
            this.keepOpen.addActionListener(this);
293
            c.fill = GridBagConstraints.NONE;
294
            c.gridx = 2;
295
            c.anchor = GridBagConstraints.EAST;
296
            this.jButtonAjouter = new JButton("Ajouter");
297
            container.add(this.jButtonAjouter, c);
298
            // Listeners
299
            this.jButtonAjouter.addActionListener(this);
300
            this.jButtonAjouter.addMouseListener(new MouseAdapter() {
301
                // not mouseClicked() since we'd be called after mouse release, i.e. after the
302
                // action. In an EditFrame (with "do not close" checked) on an IListPanel when add
303
                // is performed the list will select the new row, in doing so it first clears the
304
                // selection, which empties us, then we get called and thus display that all
305
                // required fields are empty
306
                @Override
307
                public void mousePressed(MouseEvent e) {
308
                    if (!jButtonAjouter.isEnabled()) {
309
                        final String toolTipText = jButtonAjouter.getToolTipText();
310
                        if (toolTipText != null && !toolTipText.isEmpty()) {
311
                            JOptionPane.showMessageDialog(EditPanel.this, toolTipText);
312
                        }
313
                    }
314
                }
315
            });
316
 
317
        } else if (this.mode == MODIFICATION) {
318
            c.gridx = 1;
319
            c.anchor = GridBagConstraints.EAST;
320
            this.jButtonModifier = new JButton("Enregistrer les modifications");
321
            container.add(this.jButtonModifier, c);
322
            c.weightx = 0;
323
            c.gridx = 2;
324
            this.jButtonSupprimer = new JButton("Supprimer");
325
            container.add(this.jButtonSupprimer, c);
326
            // Listeners
327
            this.jButtonModifier.addActionListener(this);
328
            this.jButtonSupprimer.addActionListener(this);
329
        }
330
        c.weightx = 0;
331
        c.gridx = 3;
332
        c.anchor = GridBagConstraints.EAST;
333
        if (this.mode == READONLY)
334
            this.jButtonAnnuler = new JButton("Fermer");
335
        else
336
            this.jButtonAnnuler = new JButton("Annuler");
337
        container.add(this.jButtonAnnuler, c);
338
        // Listeners
339
        this.jButtonAnnuler.addActionListener(this);
340
        // this.getContentPane().add(container);
341
        // this.getContentPane().add(new JScrollPane(container));
342
    }
343
 
344
    /**
345
     * Redimensionne la frame pour qu'elle soit de taille maximum sans déborder de l'écran. <img
346
     * src="doc-files/resizeFrame.png"/>
347
     */
348
    public Dimension getViewResizedDimesion(Dimension frameSize) {
349
 
350
        // MAYBE remonter la frame pour pas qu'elle dépasse en bas
351
        final Dimension viewSize = this.p.getViewport().getView().getSize();
352
        final int verticalHidden = viewSize.height - this.p.getVerticalScrollBar().getVisibleAmount();
353
        final int horizontalHidden = viewSize.width - this.p.getHorizontalScrollBar().getVisibleAmount();
354
 
355
        final Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
356
        final int maxV = ((int) bounds.getMaxY()) - this.getY();
357
        final int maxH = ((int) bounds.getMaxX()) - this.getX();
358
 
359
        final int vertical = Math.min(frameSize.height + verticalHidden, maxV);
360
        final int horizontal = Math.min(frameSize.width + horizontalHidden, maxH);
361
 
362
        return new Dimension(horizontal, vertical);
363
 
364
    }
365
 
366
    public void setInnerBorder(Border b) {
367
        this.p.setBorder(b);
368
    }
369
 
370
    public void selectionId(int id, int field) {
371
        // inutile de ne se remplir qu'avec des valeurs valides (pour éviter le resetValue() qd
372
        // déselection et donc l'écrasement des modif en cours) car de toute façon on est obligé de
373
        // laisser passer les valides qui écrasent tout autant.
374
        if (id < SQLRow.MIN_VALID_ID)
375
            this.component.select(null);
376
        else if (this.mode == CREATION) {
377
            this.component.select(this.element.createCopy(id));
378
        } else {
379
            this.component.select(id);
380
        }
381
    }
382
 
383
    /*
384
     * (non-Javadoc)
385
     *
386
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
387
     */
388
    public void actionPerformed(ActionEvent e) {
389
 
390
        if (e.getSource() == this.jButtonAnnuler) {
391
            try {
392
                this.fireCancelled();// this.dispose();
393
            } catch (Throwable ex) {
394
                ExceptionHandler.handle("Erreur pendant l'annulation", ex);
395
            }
396
        } else if (e.getSource() == this.jButtonModifier) {
397
            try {
398
                modifier();
399
            } catch (Throwable ex) {
400
                ExceptionHandler.handle("Erreur pendant la modification", ex);
401
            }
402
        } else if (e.getSource() == this.jButtonAjouter) {
403
            try {
404
                ajouter();
405
            } catch (Throwable ex) {
406
                ExceptionHandler.handle("Erreur pendant l'ajout", ex);
407
            }
408
        } else if (e.getSource() == this.jButtonSupprimer) {
409
            try {
410
                if (this.element.askArchive(this, this.component.getSelectedID())) {
411
                    this.fireDeleted();
412
                    // this.dispose(); // on ferme la fenetre
413
                }
414
            } catch (Throwable ex) {
415
                ExceptionHandler.handle("Erreur pendant la suppression", ex);
416
            }
417
        }
418
 
419
    }
420
 
421
    /**
422
     *
423
     */
424
    public void modifier() {
425
        this.component.update();
426
        this.fireModified();
427
    }
428
 
429
    public boolean alwaysVisible() {
430
        return this.keepOpen.isSelected();
431
    }
432
 
433
    public void setAlwaysVisible(boolean b) {
434
        this.keepOpen.setSelected(true);
435
    }
436
 
437
    private void ajouter() {
438
        // ne pas laisser ajouter par le raccourci clavier quand le bouton est grisé
439
        if (this.jButtonAjouter.isEnabled()) {
440
            final int id;
21 ilm 441
            if (!Boolean.getBoolean(ADD_AT_THE_END) && this.l != null && !this.l.isDead() && this.l.getDesiredRow() != null)
17 ilm 442
                id = this.component.insert(this.l.getDesiredRow());
443
            else
444
                id = this.component.insert();
445
            if (this.l != null)
446
                this.l.selectID(id);
447
            this.fireInserted(id);
448
        }
449
    }
450
 
451
    private void fireDeleted() {
452
        for (int i = 0; i < this.panelListeners.size(); i++) {
453
            EditPanelListener listener = this.panelListeners.get(i);
454
            listener.deleted();
455
        }
456
    }
457
 
458
    private void fireInserted(int id) {
459
        for (int i = 0; i < this.panelListeners.size(); i++) {
460
            EditPanelListener listener = this.panelListeners.get(i);
461
            listener.inserted(id);
462
        }
463
    }
464
 
465
    private void fireModified() {
466
        for (int i = 0; i < this.panelListeners.size(); i++) {
467
            EditPanelListener listener = this.panelListeners.get(i);
468
            listener.modified();
469
        }
470
    }
471
 
472
    private void fireCancelled() {
473
        for (int i = 0; i < this.panelListeners.size(); i++) {
474
            EditPanelListener listener = this.panelListeners.get(i);
475
            listener.cancelled();
476
        }
477
    }
478
 
479
    public void addEditPanelListener(EditPanelListener listener) {
480
        if (listener == null) {
481
            throw new IllegalArgumentException("null listener");
482
        }
483
        if (!this.panelListeners.contains(listener)) {
484
            this.panelListeners.add(listener);
485
        }
486
    }
487
 
488
    public void removeEditPanelListener(EditPanelListener listener) {
489
        if (listener == null) {
490
            throw new IllegalArgumentException("null listener");
491
        }
492
        if (this.panelListeners.contains(listener)) {
493
            this.panelListeners.remove(listener);
494
        }
495
    }
496
 
21 ilm 497
    static void updateBtn(JButton btn, ValidState validState) {
498
        btn.setEnabled(validState.isValid());
499
        btn.setToolTipText(computeTooltip(validState));
17 ilm 500
    }
501
 
21 ilm 502
    static String computeTooltip(ValidState validState) {
503
        return computeTooltip(validState.isValid(), validState.getValidationText());
504
    }
505
 
506
    static private String computeTooltip(boolean valid, final String cause) {
17 ilm 507
        final String res;
508
        if (valid)
509
            res = null;
510
        else {
21 ilm 511
            final String c = cause == null ? "" : cause.trim();
17 ilm 512
            String validationText = "Les champs de saisie ne sont pas remplis correctement.\n\nVous ne pouvez enregistrer les modifications car";
513
            if (c.length() > 0)
514
                validationText += "\n" + c;
515
            else
516
                validationText += " elles ne sont pas valides";
517
            res = "<html>" + validationText.replaceAll("\n", "<br>") + "</html>";
518
        }
519
        return res;
520
    }
521
 
522
    public void disableCancel() {
523
        this.jButtonAnnuler.setVisible(false);
524
    }
525
 
526
    public void disableDelete() {
527
        this.jButtonSupprimer.setVisible(false);
528
    }
529
 
530
    public void resetValue() {
531
        this.component.resetValue();
532
    }
533
 
534
    public void addComponentListenerOnViewPort(ComponentListener l) {
535
        this.p.getViewport().getView().addComponentListener(l);
536
    }
537
 
538
    public void setModifyLabel(String label) {
539
        this.jButtonModifier.setText(label);
540
 
541
    }
542
 
543
    public SQLComponent getSQLComponent() {
544
        return this.component;
545
    }
546
 
547
    /**
548
     * Permet de forcer qq valeur
549
     */
550
    public void setValues(List<SQLRow> sqlRows) {
551
        // eg /BATIMENT/
552
        final SQLTable t = this.component.getElement().getTable();
553
        final SQLRowValues vals = new SQLRowValues(t);
554
        final String parentForeignField = this.component.getElement().getParentForeignField();
555
        if (parentForeignField == null)
556
            return;
557
        // eg |BATIMENT.ID_SITE|
558
        final SQLField parentFF = t.getField(parentForeignField);
559
        // eg /SITE/
560
        final SQLTable foreignT = t.getBase().getGraph().getForeignTable(parentFF);
561
 
562
        for (int i = 0; i < sqlRows.size(); i++) {
563
            final SQLRow row = sqlRows.get(i);
564
            if (row.getTable().equals(foreignT)) {
565
                vals.put(parentFF.getName(), row.getID());
566
            }
567
        }
568
 
569
        this.component.select(vals);
570
    }
571
 
572
    public void setIList(IListe l) {
573
        this.l = l;
574
    }
575
 
576
    public String getDocId() {
577
        return this.mode + "_" + this.element.getTable().getName();
578
    }
579
 
580
    public String getGenericDoc() {
581
        return "";
582
    }
583
 
584
    public boolean onScreen() {
585
        return false;
586
    }
587
 
588
    public boolean isDocTransversable() {
589
        return true;
590
    }
591
}