OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 21 | Rev 27 | 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);
25 ilm 260
        this.p.setMinimumSize(new Dimension(60, 60));
17 ilm 261
 
262
        container.add(this.p, c);
263
 
264
        // Separator, if needed
265
        if (Boolean.getBoolean("org.openconcerto.editpanel.separator")) {
266
            c.gridy++;
267
            c.weightx = 1;
268
            c.weighty = 0;
269
            c.gridwidth = GridBagConstraints.REMAINDER;
270
            c.fill = GridBagConstraints.BOTH;
271
            final JSeparator comp = new JSeparator();
272
            // Evite les tremblements verticaux
273
            comp.setMinimumSize(new Dimension(comp.getPreferredSize()));
274
            container.add(comp, c);
275
        }
276
 
277
        // Buttons
278
        c.gridy++;
279
        c.weightx = 1;
280
        c.weighty = 0;
281
        c.gridwidth = 1;
282
        c.gridheight = 1;
283
        c.fill = GridBagConstraints.NONE;
284
        this.keepOpen.setOpaque(false);
285
        if (this.mode == CREATION) {
286
 
287
            c.gridx = 1;
288
            c.fill = GridBagConstraints.HORIZONTAL;
289
            c.anchor = GridBagConstraints.EAST;
290
            if (!Boolean.getBoolean("org.openconcerto.editpanel.hideKeepOpen")) {
291
                container.add(this.keepOpen, c);
292
            }
293
            this.keepOpen.addActionListener(this);
294
            c.fill = GridBagConstraints.NONE;
295
            c.gridx = 2;
296
            c.anchor = GridBagConstraints.EAST;
297
            this.jButtonAjouter = new JButton("Ajouter");
298
            container.add(this.jButtonAjouter, c);
299
            // Listeners
300
            this.jButtonAjouter.addActionListener(this);
301
            this.jButtonAjouter.addMouseListener(new MouseAdapter() {
302
                // not mouseClicked() since we'd be called after mouse release, i.e. after the
303
                // action. In an EditFrame (with "do not close" checked) on an IListPanel when add
304
                // is performed the list will select the new row, in doing so it first clears the
305
                // selection, which empties us, then we get called and thus display that all
306
                // required fields are empty
307
                @Override
308
                public void mousePressed(MouseEvent e) {
309
                    if (!jButtonAjouter.isEnabled()) {
310
                        final String toolTipText = jButtonAjouter.getToolTipText();
311
                        if (toolTipText != null && !toolTipText.isEmpty()) {
312
                            JOptionPane.showMessageDialog(EditPanel.this, toolTipText);
313
                        }
314
                    }
315
                }
316
            });
317
 
318
        } else if (this.mode == MODIFICATION) {
319
            c.gridx = 1;
320
            c.anchor = GridBagConstraints.EAST;
321
            this.jButtonModifier = new JButton("Enregistrer les modifications");
322
            container.add(this.jButtonModifier, c);
323
            c.weightx = 0;
324
            c.gridx = 2;
325
            this.jButtonSupprimer = new JButton("Supprimer");
326
            container.add(this.jButtonSupprimer, c);
327
            // Listeners
328
            this.jButtonModifier.addActionListener(this);
329
            this.jButtonSupprimer.addActionListener(this);
330
        }
331
        c.weightx = 0;
332
        c.gridx = 3;
333
        c.anchor = GridBagConstraints.EAST;
334
        if (this.mode == READONLY)
335
            this.jButtonAnnuler = new JButton("Fermer");
336
        else
337
            this.jButtonAnnuler = new JButton("Annuler");
338
        container.add(this.jButtonAnnuler, c);
339
        // Listeners
340
        this.jButtonAnnuler.addActionListener(this);
341
        // this.getContentPane().add(container);
342
        // this.getContentPane().add(new JScrollPane(container));
343
    }
344
 
345
    /**
346
     * Redimensionne la frame pour qu'elle soit de taille maximum sans déborder de l'écran. <img
347
     * src="doc-files/resizeFrame.png"/>
348
     */
349
    public Dimension getViewResizedDimesion(Dimension frameSize) {
350
 
351
        // MAYBE remonter la frame pour pas qu'elle dépasse en bas
352
        final Dimension viewSize = this.p.getViewport().getView().getSize();
353
        final int verticalHidden = viewSize.height - this.p.getVerticalScrollBar().getVisibleAmount();
354
        final int horizontalHidden = viewSize.width - this.p.getHorizontalScrollBar().getVisibleAmount();
355
 
356
        final Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
357
        final int maxV = ((int) bounds.getMaxY()) - this.getY();
358
        final int maxH = ((int) bounds.getMaxX()) - this.getX();
359
 
360
        final int vertical = Math.min(frameSize.height + verticalHidden, maxV);
361
        final int horizontal = Math.min(frameSize.width + horizontalHidden, maxH);
362
 
363
        return new Dimension(horizontal, vertical);
364
 
365
    }
366
 
367
    public void setInnerBorder(Border b) {
368
        this.p.setBorder(b);
369
    }
370
 
371
    public void selectionId(int id, int field) {
372
        // inutile de ne se remplir qu'avec des valeurs valides (pour éviter le resetValue() qd
373
        // déselection et donc l'écrasement des modif en cours) car de toute façon on est obligé de
374
        // laisser passer les valides qui écrasent tout autant.
375
        if (id < SQLRow.MIN_VALID_ID)
376
            this.component.select(null);
377
        else if (this.mode == CREATION) {
378
            this.component.select(this.element.createCopy(id));
379
        } else {
380
            this.component.select(id);
381
        }
382
    }
383
 
384
    /*
385
     * (non-Javadoc)
386
     *
387
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
388
     */
389
    public void actionPerformed(ActionEvent e) {
390
 
391
        if (e.getSource() == this.jButtonAnnuler) {
392
            try {
393
                this.fireCancelled();// this.dispose();
394
            } catch (Throwable ex) {
395
                ExceptionHandler.handle("Erreur pendant l'annulation", ex);
396
            }
397
        } else if (e.getSource() == this.jButtonModifier) {
398
            try {
399
                modifier();
400
            } catch (Throwable ex) {
401
                ExceptionHandler.handle("Erreur pendant la modification", ex);
402
            }
403
        } else if (e.getSource() == this.jButtonAjouter) {
404
            try {
405
                ajouter();
406
            } catch (Throwable ex) {
407
                ExceptionHandler.handle("Erreur pendant l'ajout", ex);
408
            }
409
        } else if (e.getSource() == this.jButtonSupprimer) {
410
            try {
411
                if (this.element.askArchive(this, this.component.getSelectedID())) {
412
                    this.fireDeleted();
413
                    // this.dispose(); // on ferme la fenetre
414
                }
415
            } catch (Throwable ex) {
416
                ExceptionHandler.handle("Erreur pendant la suppression", ex);
417
            }
418
        }
419
 
420
    }
421
 
422
    /**
423
     *
424
     */
425
    public void modifier() {
426
        this.component.update();
427
        this.fireModified();
428
    }
429
 
430
    public boolean alwaysVisible() {
431
        return this.keepOpen.isSelected();
432
    }
433
 
434
    public void setAlwaysVisible(boolean b) {
435
        this.keepOpen.setSelected(true);
436
    }
437
 
438
    private void ajouter() {
439
        // ne pas laisser ajouter par le raccourci clavier quand le bouton est grisé
440
        if (this.jButtonAjouter.isEnabled()) {
441
            final int id;
21 ilm 442
            if (!Boolean.getBoolean(ADD_AT_THE_END) && this.l != null && !this.l.isDead() && this.l.getDesiredRow() != null)
17 ilm 443
                id = this.component.insert(this.l.getDesiredRow());
444
            else
445
                id = this.component.insert();
446
            if (this.l != null)
447
                this.l.selectID(id);
448
            this.fireInserted(id);
449
        }
450
    }
451
 
452
    private void fireDeleted() {
453
        for (int i = 0; i < this.panelListeners.size(); i++) {
454
            EditPanelListener listener = this.panelListeners.get(i);
455
            listener.deleted();
456
        }
457
    }
458
 
459
    private void fireInserted(int id) {
460
        for (int i = 0; i < this.panelListeners.size(); i++) {
461
            EditPanelListener listener = this.panelListeners.get(i);
462
            listener.inserted(id);
463
        }
464
    }
465
 
466
    private void fireModified() {
467
        for (int i = 0; i < this.panelListeners.size(); i++) {
468
            EditPanelListener listener = this.panelListeners.get(i);
469
            listener.modified();
470
        }
471
    }
472
 
473
    private void fireCancelled() {
474
        for (int i = 0; i < this.panelListeners.size(); i++) {
475
            EditPanelListener listener = this.panelListeners.get(i);
476
            listener.cancelled();
477
        }
478
    }
479
 
480
    public void addEditPanelListener(EditPanelListener listener) {
481
        if (listener == null) {
482
            throw new IllegalArgumentException("null listener");
483
        }
484
        if (!this.panelListeners.contains(listener)) {
485
            this.panelListeners.add(listener);
486
        }
487
    }
488
 
489
    public void removeEditPanelListener(EditPanelListener listener) {
490
        if (listener == null) {
491
            throw new IllegalArgumentException("null listener");
492
        }
493
        if (this.panelListeners.contains(listener)) {
494
            this.panelListeners.remove(listener);
495
        }
496
    }
497
 
21 ilm 498
    static void updateBtn(JButton btn, ValidState validState) {
499
        btn.setEnabled(validState.isValid());
500
        btn.setToolTipText(computeTooltip(validState));
17 ilm 501
    }
502
 
21 ilm 503
    static String computeTooltip(ValidState validState) {
504
        return computeTooltip(validState.isValid(), validState.getValidationText());
505
    }
506
 
507
    static private String computeTooltip(boolean valid, final String cause) {
17 ilm 508
        final String res;
509
        if (valid)
510
            res = null;
511
        else {
21 ilm 512
            final String c = cause == null ? "" : cause.trim();
17 ilm 513
            String validationText = "Les champs de saisie ne sont pas remplis correctement.\n\nVous ne pouvez enregistrer les modifications car";
514
            if (c.length() > 0)
515
                validationText += "\n" + c;
516
            else
517
                validationText += " elles ne sont pas valides";
518
            res = "<html>" + validationText.replaceAll("\n", "<br>") + "</html>";
519
        }
520
        return res;
521
    }
522
 
523
    public void disableCancel() {
524
        this.jButtonAnnuler.setVisible(false);
525
    }
526
 
527
    public void disableDelete() {
528
        this.jButtonSupprimer.setVisible(false);
529
    }
530
 
531
    public void resetValue() {
532
        this.component.resetValue();
533
    }
534
 
535
    public void addComponentListenerOnViewPort(ComponentListener l) {
536
        this.p.getViewport().getView().addComponentListener(l);
537
    }
538
 
539
    public void setModifyLabel(String label) {
540
        this.jButtonModifier.setText(label);
541
 
542
    }
543
 
544
    public SQLComponent getSQLComponent() {
545
        return this.component;
546
    }
547
 
548
    /**
549
     * Permet de forcer qq valeur
550
     */
551
    public void setValues(List<SQLRow> sqlRows) {
552
        // eg /BATIMENT/
553
        final SQLTable t = this.component.getElement().getTable();
554
        final SQLRowValues vals = new SQLRowValues(t);
555
        final String parentForeignField = this.component.getElement().getParentForeignField();
556
        if (parentForeignField == null)
557
            return;
558
        // eg |BATIMENT.ID_SITE|
559
        final SQLField parentFF = t.getField(parentForeignField);
560
        // eg /SITE/
561
        final SQLTable foreignT = t.getBase().getGraph().getForeignTable(parentFF);
562
 
563
        for (int i = 0; i < sqlRows.size(); i++) {
564
            final SQLRow row = sqlRows.get(i);
565
            if (row.getTable().equals(foreignT)) {
566
                vals.put(parentFF.getName(), row.getID());
567
            }
568
        }
569
 
570
        this.component.select(vals);
571
    }
572
 
573
    public void setIList(IListe l) {
574
        this.l = l;
575
    }
576
 
577
    public String getDocId() {
578
        return this.mode + "_" + this.element.getTable().getName();
579
    }
580
 
581
    public String getGenericDoc() {
582
        return "";
583
    }
584
 
585
    public boolean onScreen() {
586
        return false;
587
    }
588
 
589
    public boolean isDocTransversable() {
590
        return true;
591
    }
592
}