OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 142 | 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.sqlobject;
15
 
73 ilm 16
import org.openconcerto.sql.TM;
17
import org.openconcerto.sql.element.RIVPanel;
17 ilm 18
import org.openconcerto.sql.element.SQLComponent;
19
import org.openconcerto.sql.element.SQLElement;
20
import org.openconcerto.sql.model.SQLRow;
25 ilm 21
import org.openconcerto.sql.request.ComboSQLRequest;
17 ilm 22
import org.openconcerto.sql.request.SQLRowItemView;
23
import org.openconcerto.sql.view.EditFrame;
24
import org.openconcerto.sql.view.EditPanel;
142 ilm 25
import org.openconcerto.sql.view.EditPanel.EditMode;
17 ilm 26
import org.openconcerto.sql.view.EditPanelListener;
27
import org.openconcerto.sql.view.IListButton;
28
import org.openconcerto.sql.view.IListFrame;
151 ilm 29
import org.openconcerto.sql.view.IListPanel;
17 ilm 30
import org.openconcerto.sql.view.ListeAddPanel;
31
import org.openconcerto.ui.DefaultGridBagConstraints;
32
import org.openconcerto.ui.FrameUtil;
73 ilm 33
import org.openconcerto.ui.component.ITextCombo;
93 ilm 34
import org.openconcerto.ui.component.InteractionMode;
17 ilm 35
import org.openconcerto.ui.list.selection.BaseListStateModel;
36
import org.openconcerto.utils.cc.ITransformer;
37
 
38
import java.awt.Dimension;
39
import java.awt.GridBagConstraints;
40
import java.awt.GridBagLayout;
41
import java.awt.event.ActionEvent;
42
import java.awt.event.ActionListener;
43
import java.beans.PropertyChangeEvent;
44
import java.beans.PropertyChangeListener;
45
 
46
import javax.swing.AbstractAction;
47
import javax.swing.Icon;
48
import javax.swing.JButton;
49
import javax.swing.JFrame;
151 ilm 50
import javax.swing.UIManager;
17 ilm 51
 
52
/**
53
 * A SQLRequestComboBox with an SQLElement allowing it to have buttons for zooming on a selected
54
 * item, or listing the items in a separate window.
55
 *
56
 * @author Sylvain CUAZ
57
 */
58
public class ElementComboBox extends SQLRequestComboBox implements ActionListener {
59
 
60
    /**
61
     * This system property is used as the initial value for {@link #setCanModify(boolean)}.
62
     */
63
    public static final String CAN_MODIFY = "org.openconcerto.sql.comboCanModify";
64
 
151 ilm 65
    private static Icon icon = null;
66
    private static Icon iconModif = null;
67
    private static Icon iconAdd = null;
68
    static int iconSize;
17 ilm 69
 
70
    private static ITransformer<ElementComboBox, Boolean> globalRowDisplayer = null;
71
 
72
    // no need for synchronization, all in EDT
73
    private static void checkLoaded() {
74
        if (icon == null) {
151 ilm 75
            final boolean twoX = UIManager.get("dpi.scale") != null && ((Float) UIManager.get("dpi.scale")) >= 2f;
76
            iconSize = twoX ? 32 : 16;
77
            icon = IListPanel.getIcon(ElementComboBox.class, "loupe.png", twoX);
78
            iconAdd = IListPanel.getIcon(ElementComboBox.class, "plus.png", twoX);
79
            iconModif = IListPanel.getIcon(ElementComboBox.class, "pen.png", twoX);
17 ilm 80
        }
81
    }
82
 
83
    private static Icon getDetailsIcon() {
84
        checkLoaded();
85
        return icon;
86
    }
87
 
88
    private static Icon getModifIcon() {
89
        checkLoaded();
90
        return iconModif;
91
    }
92
 
93
    private static Icon getAddIcon() {
94
        checkLoaded();
95
        return iconAdd;
96
    }
97
 
98
    /**
99
     * Set an alternative way to display a row for the view button.
100
     *
101
     * @param transf will be passed the comboBox and must return whether the row was displayed, can
102
     *        be <code>null</code>.
103
     */
104
    public static void setGlobalRowDisplayer(final ITransformer<ElementComboBox, Boolean> transf) {
105
        globalRowDisplayer = transf;
106
    }
107
 
108
    // on l'a pas à l'instanciation
109
    private SQLElement element;
110
 
111
    // Interface graphique
112
    // true if viewButton can sometimes modify
113
    private Boolean canModif = null;
114
    // true if viewButton can currently modify the selection
115
    private Boolean isModif = null;
116
    private final JButton viewButton = new JButton();
117
    private final IListButton listButton = new IListButton();
118
    private final JButton addButton = new JButton();
119
 
120
    // Frames
121
    private IListFrame listFrame = null;
122
    private EditFrame viewFrame = null;
123
    private EditFrame addFrame = null;
124
 
125
    private boolean minimal = false;
126
 
127
    public ElementComboBox() {
128
        super();
129
    }
130
 
131
    public ElementComboBox(boolean addUndefined) {
132
        super(addUndefined);
133
    }
134
 
135
    public ElementComboBox(boolean addUndefined, int preferredWidthInChar) {
136
        super(addUndefined, preferredWidthInChar);
137
    }
138
 
139
    /**
140
     * Init de l'interface graphique.
141
     *
142
     * @param element which table to display and how.
143
     * @return this
144
     */
145
    public final ElementComboBox init(SQLElement element) {
25 ilm 146
        return this.init(element, element.getComboRequest());
147
    }
148
 
149
    public final ElementComboBox init(SQLElement element, final ComboSQLRequest req) {
150
        if (element.getTable() != req.getPrimaryTable())
151
            throw new IllegalArgumentException("Tables are different " + element.getTable().getSQLName() + " != " + req.getPrimaryTable().getSQLName());
17 ilm 152
        this.element = element;
25 ilm 153
        this.uiInit(req);
17 ilm 154
        return this;
155
    }
156
 
157
    @Override
73 ilm 158
    public void added(RIVPanel sqlComp, SQLRowItemView v) {
159
        final SQLElement foreignElement = sqlComp.getDirectory().getElement(v.getField().getForeignTable());
25 ilm 160
        if (this.getElement() == null)
73 ilm 161
            this.init(foreignElement);
162
        else if (this.getElement() != foreignElement)
163
            throw new IllegalArgumentException("Elements are different " + getElement() + " != " + foreignElement);
17 ilm 164
    }
165
 
166
    public final SQLElement getElement() {
167
        return this.element;
168
    }
169
 
170
    /**
171
     * Whether the first button allow one to view or modify the selection.
172
     *
173
     * @param canModif <code>false</code> to only view the selection.
174
     */
175
    public final void setCanModify(boolean canModif) {
176
        if (this.canModif == null || this.canModif != canModif) {
177
            this.canModif = canModif;
178
            this.updateViewBtn();
179
        }
180
    }
181
 
182
    private final void setViewBtn(boolean modif) {
183
        if (this.isModif == null || this.isModif != modif) {
184
            this.isModif = modif;
185
            this.viewFrame = null;
186
            if (this.isModif) {
187
                this.viewButton.setToolTipText("Modifier");
188
                this.viewButton.setIcon(getModifIcon());
151 ilm 189
 
17 ilm 190
            } else {
191
                this.viewButton.setToolTipText("Voir plus de détails");
192
                this.viewButton.setIcon(getDetailsIcon());
193
            }
151 ilm 194
            this.viewButton.setPreferredSize(new Dimension(iconSize + 8, iconSize));
195
            DefaultGridBagConstraints.lockMinimumSize(this.viewButton);
17 ilm 196
            // each time its icon change, otherwise (at least on Mac) the opacity is wrong
197
            IListButton.initButton(this.viewButton);
198
        }
199
    }
200
 
201
    @Override
202
    protected void uiLayout() {
203
        this.setLayout(new GridBagLayout());
204
 
205
        GridBagConstraints c = new GridBagConstraints();
206
        c.gridx = 0;
207
        c.gridy = 0;
208
        c.gridheight = 1;
209
        c.gridwidth = 1;
210
        c.fill = GridBagConstraints.HORIZONTAL;
211
        c.weighty = 0;
212
        c.weightx = 1;
213
 
214
        this.combo.getActions().add(new AbstractAction("Tout afficher") {
215
            @Override
216
            public void actionPerformed(ActionEvent e) {
217
                ElementComboBox.this.actionPerformed(e);
218
            }
219
        });
220
 
221
        this.add(this.combo, c);
222
 
223
        if (!this.minimal) {
224
            c.weightx = 0;
225
            c.gridx++;
226
            this.setCanModify(Boolean.getBoolean(CAN_MODIFY));
227
            add(this.viewButton, c);
228
            c.gridx++;
73 ilm 229
            this.listButton.setToolTipText(TM.getInstance().trM("combo.list", "element", this.element.getName()));
17 ilm 230
            add(this.listButton, c);
231
 
232
            // Add button
151 ilm 233
            this.addButton.setPreferredSize(new Dimension(iconSize + 8, iconSize));
17 ilm 234
            this.addButton.setIcon(getAddIcon());
235
            IListButton.initButton(this.addButton);
73 ilm 236
            this.addButton.setToolTipText(EditFrame.getCreateMessage(this.element));
17 ilm 237
            c.gridx++;
238
            DefaultGridBagConstraints.lockMinimumSize(this.addButton);
239
            add(this.addButton, c);
240
            this.addButton.addActionListener(this);
241
            setAddIconVisible(Boolean.getBoolean("org.openconcerto.ui.addComboButton"));
242
 
243
            this.viewButton.addActionListener(this);
244
            this.listButton.addActionListener(this);
245
            this.addValueListener(new PropertyChangeListener() {
246
                public void propertyChange(PropertyChangeEvent evt) {
73 ilm 247
                    valueChanged();
17 ilm 248
                }
249
            });
250
 
73 ilm 251
            if (Boolean.getBoolean(ITextCombo.SIMPLE_TRAVERSAL)) {
17 ilm 252
                this.viewButton.setFocusable(false);
253
                this.listButton.setFocusable(false);
254
                this.addButton.setFocusable(false);
255
            }
256
        } else {
257
            this.setCanModify(false);
258
        }
259
        // don't want NPE
260
        assert this.canModif != null && this.isModif != null : "Modif booleans not initialized, this.canModif: " + this.canModif + ", this.isModif: " + this.isModif;
261
    }
262
 
263
    private void valueChanged() {
264
        updateViewBtn();
265
        if (this.viewFrame != null) {
266
            // changer la frame du détail
73 ilm 267
            this.viewFrame.selectionId(this.getWantedID());
17 ilm 268
        }
269
        if (this.listFrame != null) {
73 ilm 270
            this.listFrame.getPanel().getListe().selectID(this.getWantedID());
17 ilm 271
        }
272
    }
273
 
274
    private final boolean displayRow() {
275
        if (globalRowDisplayer == null)
276
            return false;
277
        else
278
            return globalRowDisplayer.transformChecked(this);
279
    }
280
 
281
    /*
282
     * (non-Javadoc)
283
     *
284
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
285
     */
286
    public void actionPerformed(ActionEvent e) {
287
        if (e.getSource() == this.viewButton) {
288
            final boolean displayed;
289
            if ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0) {
290
                displayed = displayRow();
291
            } else {
292
                displayed = false;
293
            }
294
            if (!displayed) {
295
                if (this.viewFrame == null) {
142 ilm 296
                    this.viewFrame = createEditFrame(this.isModif ? EditPanel.MODIFICATION : EditPanel.READONLY);
17 ilm 297
                    // dispose since if we change canModif, the old frame will be orphaned
298
                    this.viewFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
299
                }
73 ilm 300
                this.viewFrame.selectionId(getWantedID());
17 ilm 301
                FrameUtil.show(this.viewFrame);
302
            }
303
        } else if (e.getSource() == this.addButton) {
304
            FrameUtil.show(this.getAddFrame());
305
        } else if (e.getSource() == this.listButton || e.getSource() == this.combo) {
306
            if (this.listFrame == null) {
307
                this.listFrame = new IListFrame(new ListeAddPanel(this.element));
308
                // listen to userSelection (eg avoid emptying the selection, when the search or the
309
                // hibernation empties the list)
310
                this.listFrame.getPanel().getListe().getSelection().addPropertyChangeListener("userSelectedID", new PropertyChangeListener() {
311
                    @Override
312
                    public void propertyChange(PropertyChangeEvent evt) {
313
                        final int newID = ((Number) evt.getNewValue()).intValue();
314
                        setValue(newID == BaseListStateModel.INVALID_ID ? null : newID);
315
                    }
316
                });
73 ilm 317
                this.listFrame.getPanel().getListe().selectID(getWantedID());
17 ilm 318
            }
319
            FrameUtil.show(this.listFrame);
320
        }
321
    }
322
 
323
    private final EditFrame getAddFrame() {
324
        if (this.addFrame == null) {
142 ilm 325
            this.addFrame = createEditFrame(EditPanel.CREATION);
17 ilm 326
            this.addFrame.addEditPanelListener(new EditPanelListener() {
327
                @Override
328
                public void cancelled() {
329
                }
330
 
331
                @Override
332
                public void deleted() {
333
                }
334
 
335
                @Override
336
                public void inserted(int mid) {
337
                    ElementComboBox.this.setValue(mid);
338
                }
339
 
340
                @Override
341
                public void modified() {
342
                }
343
            });
344
        }
345
        return this.addFrame;
346
    }
347
 
142 ilm 348
    protected final EditFrame createEditFrame(final EditMode mode) {
349
        final SQLComponent res = this.createSQLComponent(mode);
350
        if (res.getElement() != this.getElement())
351
            throw new IllegalStateException("Wrong element");
352
        return new EditFrame(res, mode);
353
    }
354
 
355
    protected SQLComponent createSQLComponent(final EditMode mode) {
356
        return this.element.createDefaultComponent();
357
    }
358
 
17 ilm 359
    /**
360
     * The sql component of the add frame.
361
     *
362
     * @return the sql component (creating the frame if necessary).
363
     */
364
    public final SQLComponent getAddComp() {
365
        return this.getAddFrame().getSQLComponent();
366
    }
367
 
368
    public String toString() {
369
        return this.getClass().getName() + " " + this.element;
370
    }
371
 
93 ilm 372
    @Override
373
    protected void modeChanged(InteractionMode mode) {
17 ilm 374
        super.modeChanged(mode);
375
        updateViewBtn();
93 ilm 376
        this.listButton.setEnabled(mode.isEditable());
377
        this.addButton.setEnabled(mode.isEditable());
17 ilm 378
    }
379
 
380
    private void updateViewBtn() {
381
        final boolean modif, enabled;
93 ilm 382
        final InteractionMode mode = getInteractionMode();
383
        if (!mode.isEnabled() || this.getWantedID() < SQLRow.MIN_VALID_ID) {
17 ilm 384
            // disabled
385
            modif = this.canModif;
386
            enabled = false;
93 ilm 387
        } else if (this.canModif && mode.isEditable()) {
17 ilm 388
            // modification enabled
389
            modif = true;
390
            enabled = true;
391
        } else {
392
            // view enabled
393
            modif = false;
394
            enabled = true;
395
        }
396
        this.setViewBtn(modif);
397
        this.viewButton.setEnabled(enabled);
398
    }
399
 
400
    public void setMinimal() {
401
        this.minimal = true;
402
    }
403
 
404
    /**
405
     * Toggle l'icone d'accès à la loupe
406
     *
407
     * @param b <code>true</code> if "info" must be visible.
408
     */
409
    public void setInfoIconVisible(boolean b) {
410
        this.viewButton.setVisible(b);
411
    }
412
 
413
    /**
414
     * Toggle l'icone d'accès à la liste
415
     *
416
     * @param b <code>true</code> if "list" must be visible.
417
     */
418
    public void setListIconVisible(boolean b) {
419
        this.listButton.setVisible(b);
420
    }
421
 
422
    public void setAddIconVisible(boolean b) {
423
        this.addButton.setVisible(b);
424
    }
425
 
426
    public void setButtonsVisible(boolean b) {
427
        this.setInfoIconVisible(b);
428
        this.setListIconVisible(b);
429
        this.setAddIconVisible(b);
430
    }
431
 
432
}