OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 83 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 83 Rev 182
Line 1... Line 1...
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
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
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
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.
9
 * language governing permissions and limitations under the License.
Line 50... Line 50...
50
import javax.swing.JTextField;
50
import javax.swing.JTextField;
51
import javax.swing.ListCellRenderer;
51
import javax.swing.ListCellRenderer;
52
import javax.swing.event.DocumentEvent;
52
import javax.swing.event.DocumentEvent;
53
import javax.swing.event.TableModelEvent;
53
import javax.swing.event.TableModelEvent;
54
import javax.swing.event.TableModelListener;
54
import javax.swing.event.TableModelListener;
-
 
55
import javax.swing.table.TableModel;
55
import javax.swing.text.BadLocationException;
56
import javax.swing.text.BadLocationException;
56
 
57
 
57
import net.jcip.annotations.Immutable;
58
import net.jcip.annotations.Immutable;
58
 
59
 
59
public class SearchItemComponent extends JPanel {
60
public class SearchItemComponent extends JPanel {
Line 87... Line 88...
87
        public final int getIndex() {
88
        public final int getIndex() {
88
            return this.index;
89
            return this.index;
89
        }
90
        }
90
    }
91
    }
91
 
92
 
92
    private JTextField textFieldRecherche = new JTextField(10);
93
    private final JTextField textFieldRecherche = new JTextField(10);
93
    private final JComboBox comboColonnePourRecherche;
94
    private final JComboBox<Column> comboColonnePourRecherche;
94
    private final JComboBox searchMode;
95
    private final JComboBox<String> searchMode;
95
    private JCheckBox invertSearch = new JCheckBox(TM.tr("toReverse"));
96
    private final JCheckBox invertSearch = new JCheckBox(TM.tr("toReverse"));
96
    private JButton buttonAdd = new JButton("+");
97
    private final JButton buttonAdd = new JButton("+");
97
    private JButton buttonRemove = new JButton();
98
    private final JButton buttonRemove = new JButton();
98
    final SearchListComponent list;
99
    final SearchListComponent list;
-
 
100
    // final to ease removing listener, SearchListComponent.reset() removes every item
-
 
101
    // when the TableModel changes.
-
 
102
    private final TableModel tableModel;
99
    private String text = "";
103
    private String text = "";
100
 
104
 
101
    public SearchItemComponent(final SearchListComponent list) {
105
    public SearchItemComponent(final SearchListComponent list) {
102
        super();
106
        super();
103
        this.list = list;
107
        this.list = list;
-
 
108
        this.tableModel = this.list.getTableModel();
104
        this.setOpaque(false);
109
        this.setOpaque(false);
105
        // Initialisation de l'interface graphique
110
        // Initialisation de l'interface graphique
-
 
111
        this.searchMode = new JComboBox<>(
106
        this.searchMode = new JComboBox(new String[] { TM.tr("contains"), TM.tr("contains.exactly"), TM.tr("isLessThan"), TM.tr("isEqualTo"), TM.tr("isExactlyEqualTo"), TM.tr("isGreaterThan"),
112
                new String[] { TM.tr("contains"), TM.tr("contains.exactly"), TM.tr("isLessThan"), TM.tr("isEqualTo"), TM.tr("isExactlyEqualTo"), TM.tr("isGreaterThan"), TM.tr("isEmpty") });
107
                TM.tr("isEmpty") });
-
 
108
        final ListComboBoxModel comboModel = new ListComboBoxModel(Arrays.asList(TOUT));
113
        final ListComboBoxModel<Column> comboModel = new ListComboBoxModel<>(Arrays.asList(TOUT));
109
        comboModel.setSelectOnAdd(false);
114
        comboModel.setSelectOnAdd(false);
110
        // allow getColIndex() and thus getSearchItem() to work from now on
115
        // allow getColIndex() and thus getSearchItem() to work from now on
111
        assert comboModel.getSelectedItem() != null;
116
        assert comboModel.getSelectedItem() != null;
112
        this.comboColonnePourRecherche = new JComboBox(comboModel);
117
        this.comboColonnePourRecherche = new JComboBox<>(comboModel);
113
        uiInit();
118
        uiInit();
114
    }
119
    }
115
 
120
 
-
 
121
    final TableModel getTableModel() {
-
 
122
        return this.tableModel;
-
 
123
    }
-
 
124
 
116
    private void uiInit() {
125
    private void uiInit() {
117
        this.setLayout(new GridBagLayout());
126
        this.setLayout(new GridBagLayout());
118
        final GridBagConstraints c = new GridBagConstraints();
127
        final GridBagConstraints c = new GridBagConstraints();
119
        c.gridx = 0;
128
        c.gridx = 0;
120
        c.gridy = 0;
129
        c.gridy = 0;
121
        c.insets = new Insets(0, 2, 0, 2);
130
        c.insets = new Insets(0, 2, 0, 2);
122
        c.fill = GridBagConstraints.HORIZONTAL;
131
        c.fill = GridBagConstraints.HORIZONTAL;
123
 
132
 
124
        // designation
133
        // designation
125
        // don't just use DefaultListCellRenderer, it fails on some l&f
134
        // don't just use DefaultListCellRenderer, it fails on some l&f
-
 
135
        @SuppressWarnings("unchecked")
126
        final ListCellRenderer old = this.comboColonnePourRecherche.getRenderer();
136
        final ListCellRenderer<Object> old = (ListCellRenderer<Object>) this.comboColonnePourRecherche.getRenderer();
127
        this.comboColonnePourRecherche.setRenderer(new ListCellRenderer() {
137
        this.comboColonnePourRecherche.setRenderer(new ListCellRenderer<Column>() {
128
            @Override
138
            @Override
129
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
139
            public Component getListCellRendererComponent(JList<? extends Column> list, Column value, int index, boolean isSelected, boolean cellHasFocus) {
130
                return old.getListCellRendererComponent(list, ((Column) value).getLabel(), index, isSelected, cellHasFocus);
140
                return old.getListCellRendererComponent(list, value.getLabel(), index, isSelected, cellHasFocus);
131
            }
141
            }
132
        });
142
        });
133
        // hand tuned for a IListPanel width of 1024px
143
        // hand tuned for a IListPanel width of 1024px
134
        this.comboColonnePourRecherche.setMinimumSize(new Dimension(150, 20));
144
        this.comboColonnePourRecherche.setMinimumSize(new Dimension(150, 20));
135
        this.comboColonnePourRecherche.setOpaque(false);
145
        this.comboColonnePourRecherche.setOpaque(false);
Line 169... Line 179...
169
        initCombo();
179
        initCombo();
170
        initSearchText();
180
        initSearchText();
171
        initInvertSearch();
181
        initInvertSearch();
172
 
182
 
173
        this.buttonAdd.addActionListener(new ActionListener() {
183
        this.buttonAdd.addActionListener(new ActionListener() {
-
 
184
            @Override
174
            public void actionPerformed(ActionEvent e) {
185
            public void actionPerformed(ActionEvent e) {
175
                SearchItemComponent.this.list.addNewSearchItem();
186
                SearchItemComponent.this.list.addNewSearchItem();
176
            }
187
            }
177
        });
188
        });
178
        this.buttonRemove.addActionListener(new ActionListener() {
189
        this.buttonRemove.addActionListener(new ActionListener() {
-
 
190
            @Override
179
            public void actionPerformed(ActionEvent e) {
191
            public void actionPerformed(ActionEvent e) {
180
                SearchItemComponent.this.list.removeSearchItem(SearchItemComponent.this);
192
                SearchItemComponent.this.list.removeSearchItem(SearchItemComponent.this);
181
            }
193
            }
182
        });
194
        });
183
    }
195
    }
184
 
196
 
185
    private void initInvertSearch() {
197
    private void initInvertSearch() {
186
        this.invertSearch.addActionListener(new ActionListener() {
198
        this.invertSearch.addActionListener(new ActionListener() {
-
 
199
            @Override
187
            public void actionPerformed(ActionEvent e) {
200
            public void actionPerformed(ActionEvent e) {
188
                updateSearchList();
201
                updateSearchList();
189
            }
202
            }
190
        });
203
        });
191
    }
204
    }
192
 
205
 
193
    private void initSearchText() {
206
    private void initSearchText() {
194
        this.textFieldRecherche.getDocument().addDocumentListener(new SimpleDocumentListener() {
207
        this.textFieldRecherche.getDocument().addDocumentListener(new SimpleDocumentListener() {
-
 
208
            @Override
195
            public void update(DocumentEvent e) {
209
            public void update(DocumentEvent e) {
196
                try {
210
                try {
197
                    // One ne peut pas appeler chercher() car le texte n'est pas encore a jour
211
                    // One ne peut pas appeler chercher() car le texte n'est pas encore a jour
198
                    SearchItemComponent.this.text = e.getDocument().getText(0, e.getDocument().getLength()).trim();
212
                    SearchItemComponent.this.text = e.getDocument().getText(0, e.getDocument().getLength()).trim();
199
                    updateSearchList();
213
                    updateSearchList();
200
                } catch (BadLocationException exn) {
214
                } catch (final BadLocationException exn) {
201
                    // impossible
215
                    // impossible
202
                    exn.printStackTrace();
216
                    exn.printStackTrace();
203
                }
217
                }
204
            }
218
            }
205
        });
219
        });
206
    }
220
    }
207
 
221
 
208
    private void initCombo() {
222
    private void initCombo() {
209
        final ItemListener listener = new ItemListener() {
223
        final ItemListener listener = new ItemListener() {
-
 
224
            @Override
210
            public void itemStateChanged(ItemEvent e) {
225
            public void itemStateChanged(ItemEvent e) {
211
                updateSearchList();
226
                updateSearchList();
212
            }
227
            }
213
        };
228
        };
214
        this.searchMode.addItemListener(listener);
229
        this.searchMode.addItemListener(listener);
Line 221... Line 236...
221
                }
236
                }
222
            }
237
            }
223
        };
238
        };
224
        // allow the TableModel to die
239
        // allow the TableModel to die
225
        this.addHierarchyListener(new HierarchyListener() {
240
        this.addHierarchyListener(new HierarchyListener() {
-
 
241
            @Override
226
            public void hierarchyChanged(HierarchyEvent e) {
242
            public void hierarchyChanged(HierarchyEvent e) {
227
                if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
243
                if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
228
                    if (e.getChanged().isDisplayable()) {
244
                    if (e.getChanged().isDisplayable()) {
229
                        columnsChanged(listener);
245
                        columnsChanged(listener);
230
                        SearchItemComponent.this.list.getTableModel().addTableModelListener(tableModelL);
246
                        SearchItemComponent.this.getTableModel().addTableModelListener(tableModelL);
231
                    } else {
247
                    } else {
232
                        SearchItemComponent.this.list.getTableModel().removeTableModelListener(tableModelL);
248
                        SearchItemComponent.this.getTableModel().removeTableModelListener(tableModelL);
233
                    }
249
                    }
234
                }
250
                }
235
            }
251
            }
236
        });
252
        });
237
        // that way the TableModelListener will get added automatically
253
        // that way the TableModelListener will get added automatically
Line 242... Line 258...
242
        this.comboColonnePourRecherche.setSelectedIndex(0);
258
        this.comboColonnePourRecherche.setSelectedIndex(0);
243
    }
259
    }
244
 
260
 
245
    private void fillColumnCombo(ItemListener listener) {
261
    private void fillColumnCombo(ItemListener listener) {
246
        // sort column names alphabetically
262
        // sort column names alphabetically
247
        final int columnCount = this.list.getTableModel().getColumnCount();
263
        final int columnCount = this.getTableModel().getColumnCount();
248
        final String[][] names = new String[columnCount][];
264
        final String[][] names = new String[columnCount][];
249
        final int[] indexes = new int[columnCount];
265
        final int[] indexes = new int[columnCount];
250
        for (int i = 0; i < columnCount; i++) {
266
        for (int i = 0; i < columnCount; i++) {
251
            names[i] = this.list.getColumnNames(i);
267
            names[i] = this.list.getColumnNames(i);
252
            indexes[i] = 0;
268
            indexes[i] = 0;
253
        }
269
        }
254
        // use column index as columns names are not unique
270
        // use column index as columns names are not unique
255
        final SortedMap<String, Integer> map = solve(names, indexes);
271
        final SortedMap<String, Integer> map = solve(names, indexes);
256
        final List<Column> cols = new ArrayList<Column>(columnCount);
272
        final List<Column> cols = new ArrayList<>(columnCount);
257
        cols.add(TOUT);
273
        cols.add(TOUT);
258
        for (final Entry<String, Integer> e : map.entrySet()) {
274
        for (final Entry<String, Integer> e : map.entrySet()) {
259
            final int colIndex = e.getValue().intValue();
275
            final int colIndex = e.getValue().intValue();
260
            final String[] colNames = names[colIndex];
276
            final String[] colNames = names[colIndex];
261
            cols.add(new Column(e.getKey(), colNames[colNames.length - 1], colIndex));
277
            cols.add(new Column(e.getKey(), colNames[colNames.length - 1], colIndex));
262
        }
278
        }
263
 
279
 
264
        // don't fire when filling, we will fire when selecting
280
        // don't fire when filling, we will fire when selecting
265
        this.comboColonnePourRecherche.removeItemListener(listener);
281
        this.comboColonnePourRecherche.removeItemListener(listener);
266
        final ListComboBoxModel comboModel = (ListComboBoxModel) this.comboColonnePourRecherche.getModel();
282
        final ListComboBoxModel<Column> comboModel = (ListComboBoxModel<Column>) this.comboColonnePourRecherche.getModel();
267
        assert !comboModel.isSelectOnAdd() : "Otherwise our following select might not fire";
283
        assert !comboModel.isSelectOnAdd() : "Otherwise our following select might not fire";
268
        comboModel.removeAllElements();
284
        comboModel.removeAllElements();
269
        comboModel.addAll(cols);
285
        comboModel.addAll(cols);
270
        this.comboColonnePourRecherche.addItemListener(listener);
286
        this.comboColonnePourRecherche.addItemListener(listener);
271
    }
287
    }
272
 
288
 
273
    private void columnsChanged(final ItemListener listener) {
289
    private void columnsChanged(final ItemListener listener) {
274
        final String currentID = ((Column) this.comboColonnePourRecherche.getSelectedItem()).getID();
290
        final String currentID = ((Column) this.comboColonnePourRecherche.getSelectedItem()).getID();
275
        fillColumnCombo(listener);
291
        fillColumnCombo(listener);
276
        final ListComboBoxModel comboModel = (ListComboBoxModel) this.comboColonnePourRecherche.getModel();
292
        final ListComboBoxModel<Column> comboModel = (ListComboBoxModel<Column>) this.comboColonnePourRecherche.getModel();
277
        // no selection since the model was just emptied
293
        // no selection since the model was just emptied
278
        assert this.comboColonnePourRecherche.getSelectedIndex() == -1 && this.comboColonnePourRecherche.getSelectedItem() == null;
294
        assert this.comboColonnePourRecherche.getSelectedIndex() == -1 && this.comboColonnePourRecherche.getSelectedItem() == null;
279
        // try to reselect the same column if it's still there
295
        // try to reselect the same column if it's still there
280
        for (final Object o : comboModel.getList()) {
296
        for (final Object o : comboModel.getList()) {
281
            final Column col = (Column) o;
297
            final Column col = (Column) o;
Line 294... Line 310...
294
     * @return a sorted map.
310
     * @return a sorted map.
295
     */
311
     */
296
    private SortedMap<String, Integer> solve(final String[][] names, final int[] indexes) {
312
    private SortedMap<String, Integer> solve(final String[][] names, final int[] indexes) {
297
        final int columnCount = names.length;
313
        final int columnCount = names.length;
298
        // columns' index by name
314
        // columns' index by name
299
        final ListMap<String, Integer> collisions = new ListMap<String, Integer>(columnCount);
315
        final ListMap<String, Integer> collisions = new ListMap<>(columnCount);
300
        for (int i = 0; i < columnCount; i++) {
316
        for (int i = 0; i < columnCount; i++) {
301
            final int index = indexes[i];
317
            final int index = indexes[i];
302
            if (index >= names[i].length)
318
            if (index >= names[i].length)
303
                throw new IllegalStateException("Ran out of names for " + i + " : " + Arrays.asList(names[i]));
319
                throw new IllegalStateException("Ran out of names for " + i + " : " + Arrays.asList(names[i]));
304
            final String columnName = names[i][index];
320
            final String columnName = names[i][index];
305
            collisions.add(columnName, i);
321
            collisions.add(columnName, i);
306
        }
322
        }
307
        final SortedMap<String, Integer> res = new TreeMap<String, Integer>();
323
        final SortedMap<String, Integer> res = new TreeMap<>();
308
        for (Entry<String, ? extends Collection<Integer>> e : collisions.entrySet()) {
324
        for (final Entry<String, ? extends Collection<Integer>> e : collisions.entrySet()) {
309
            final Collection<Integer> indexesWithCollision = e.getValue();
325
            final Collection<Integer> indexesWithCollision = e.getValue();
310
            if (indexesWithCollision.size() > 1) {
326
            if (indexesWithCollision.size() > 1) {
311
                // increment only the minimum indexes to try to solve the conflict with the lowest
327
                // increment only the minimum indexes to try to solve the conflict with the lowest
312
                // possible indexes
328
                // possible indexes
313
                int minIndex = Integer.MAX_VALUE;
329
                int minIndex = Integer.MAX_VALUE;