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 18... |
Line 18... |
18 |
import org.openconcerto.sql.Log;
|
18 |
import org.openconcerto.sql.Log;
|
19 |
import org.openconcerto.sql.TM;
|
19 |
import org.openconcerto.sql.TM;
|
20 |
import org.openconcerto.sql.element.SQLComponent;
|
20 |
import org.openconcerto.sql.element.SQLComponent;
|
21 |
import org.openconcerto.sql.element.SQLElement;
|
21 |
import org.openconcerto.sql.element.SQLElement;
|
22 |
import org.openconcerto.sql.element.SQLElementDirectory;
|
22 |
import org.openconcerto.sql.element.SQLElementDirectory;
|
- |
|
23 |
import org.openconcerto.sql.model.RowRef;
|
23 |
import org.openconcerto.sql.model.SQLField;
|
24 |
import org.openconcerto.sql.model.SQLField;
|
24 |
import org.openconcerto.sql.model.SQLRow;
|
25 |
import org.openconcerto.sql.model.SQLRow;
|
25 |
import org.openconcerto.sql.model.SQLRowAccessor;
|
26 |
import org.openconcerto.sql.model.SQLRowAccessor;
|
26 |
import org.openconcerto.sql.model.SQLRowValues;
|
27 |
import org.openconcerto.sql.model.SQLRowValues;
|
27 |
import org.openconcerto.sql.model.SQLTable;
|
28 |
import org.openconcerto.sql.model.SQLTable;
|
28 |
import org.openconcerto.sql.model.Where;
|
29 |
import org.openconcerto.sql.model.Where;
|
- |
|
30 |
import org.openconcerto.sql.request.ComboSQLRequest.KeepMode;
|
29 |
import org.openconcerto.sql.request.ListSQLRequest;
|
31 |
import org.openconcerto.sql.request.ListSQLRequest;
|
30 |
import org.openconcerto.sql.request.UpdateBuilder;
|
32 |
import org.openconcerto.sql.request.UpdateBuilder;
|
31 |
import org.openconcerto.sql.users.User;
|
33 |
import org.openconcerto.sql.users.User;
|
32 |
import org.openconcerto.sql.users.UserManager;
|
34 |
import org.openconcerto.sql.users.UserManager;
|
33 |
import org.openconcerto.sql.users.rights.TableAllRights;
|
35 |
import org.openconcerto.sql.users.rights.TableAllRights;
|
34 |
import org.openconcerto.sql.view.FileTransfertHandler;
|
36 |
import org.openconcerto.sql.view.FileTransfertHandler;
|
35 |
import org.openconcerto.sql.view.IListener;
|
37 |
import org.openconcerto.sql.view.IListener;
|
- |
|
38 |
import org.openconcerto.sql.view.RowMetadata;
|
- |
|
39 |
import org.openconcerto.sql.view.RowMetadataCache;
|
36 |
import org.openconcerto.sql.view.list.IListeAction.ButtonsBuilder;
|
40 |
import org.openconcerto.sql.view.list.IListeAction.ButtonsBuilder;
|
37 |
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
|
41 |
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
|
38 |
import org.openconcerto.sql.view.list.IListeAction.PopupBuilder;
|
42 |
import org.openconcerto.sql.view.list.IListeAction.PopupBuilder;
|
39 |
import org.openconcerto.sql.view.list.IListeAction.PopupEvent;
|
43 |
import org.openconcerto.sql.view.list.IListeAction.PopupEvent;
|
40 |
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
|
44 |
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
|
- |
|
45 |
import org.openconcerto.sql.view.list.action.ListEvent;
|
- |
|
46 |
import org.openconcerto.sql.view.list.action.SQLRowValuesAction;
|
41 |
import org.openconcerto.ui.FontUtils;
|
47 |
import org.openconcerto.ui.FontUtils;
|
42 |
import org.openconcerto.ui.FormatEditor;
|
48 |
import org.openconcerto.ui.FormatEditor;
|
43 |
import org.openconcerto.ui.MenuUtils;
|
49 |
import org.openconcerto.ui.MenuUtils;
|
44 |
import org.openconcerto.ui.PopupMouseListener;
|
50 |
import org.openconcerto.ui.PopupMouseListener;
|
45 |
import org.openconcerto.ui.SwingThreadUtils;
|
51 |
import org.openconcerto.ui.SwingThreadUtils;
|
Line 89... |
Line 95... |
89 |
import java.sql.Time;
|
95 |
import java.sql.Time;
|
90 |
import java.sql.Timestamp;
|
96 |
import java.sql.Timestamp;
|
91 |
import java.text.DateFormat;
|
97 |
import java.text.DateFormat;
|
92 |
import java.text.Format;
|
98 |
import java.text.Format;
|
93 |
import java.util.ArrayList;
|
99 |
import java.util.ArrayList;
|
94 |
import java.util.Calendar;
|
- |
|
95 |
import java.util.Collection;
|
100 |
import java.util.Collection;
|
96 |
import java.util.Collections;
|
101 |
import java.util.Collections;
|
97 |
import java.util.Date;
|
102 |
import java.util.Date;
|
98 |
import java.util.EventObject;
|
103 |
import java.util.EventObject;
|
99 |
import java.util.HashMap;
|
104 |
import java.util.HashMap;
|
100 |
import java.util.HashSet;
|
105 |
import java.util.HashSet;
|
- |
|
106 |
import java.util.IdentityHashMap;
|
101 |
import java.util.LinkedHashMap;
|
107 |
import java.util.LinkedHashMap;
|
102 |
import java.util.List;
|
108 |
import java.util.List;
|
103 |
import java.util.Locale;
|
109 |
import java.util.Locale;
|
104 |
import java.util.Map;
|
110 |
import java.util.Map;
|
105 |
import java.util.Map.Entry;
|
111 |
import java.util.Map.Entry;
|
106 |
import java.util.Set;
|
112 |
import java.util.Set;
|
107 |
import java.util.concurrent.ExecutionException;
|
113 |
import java.util.concurrent.ExecutionException;
|
- |
|
114 |
import java.util.function.BiFunction;
|
108 |
|
115 |
|
109 |
import javax.swing.AbstractAction;
|
116 |
import javax.swing.AbstractAction;
|
110 |
import javax.swing.Action;
|
117 |
import javax.swing.Action;
|
111 |
import javax.swing.DropMode;
|
118 |
import javax.swing.DropMode;
|
112 |
import javax.swing.InputMap;
|
119 |
import javax.swing.InputMap;
|
Line 144... |
Line 151... |
144 |
*
|
151 |
*
|
145 |
* @author ILM Informatique
|
152 |
* @author ILM Informatique
|
146 |
*/
|
153 |
*/
|
147 |
public final class IListe extends JPanel {
|
154 |
public final class IListe extends JPanel {
|
148 |
|
155 |
|
149 |
static private final class LockAction extends RowAction {
|
156 |
static private final class LockAction extends SQLRowValuesAction {
|
150 |
private final boolean lock;
|
157 |
private final boolean lock;
|
151 |
|
158 |
|
152 |
public LockAction(final boolean lock) {
|
159 |
public LockAction(final boolean lock) {
|
153 |
super(new AbstractAction(TM.tr(lock ? "ilist.lockRows" : "ilist.unlockRows")) {
|
- |
|
154 |
@Override
|
160 |
super(false, true, (e) -> {
|
155 |
public void actionPerformed(ActionEvent e) {
|
- |
|
156 |
final IListe list = IListe.get(e);
|
- |
|
157 |
final List<Integer> ids = list.getSelection().getSelectedIDs();
|
161 |
final List<Number> ids = e.getSelectedIDs();
|
158 |
final SQLTable t = list.getSource().getPrimaryTable();
|
162 |
final SQLTable t = e.getTable();
|
159 |
final UpdateBuilder update = new UpdateBuilder(t);
|
163 |
final UpdateBuilder update = new UpdateBuilder(t);
|
160 |
update.setObject(SQLComponent.READ_ONLY_FIELD, lock ? SQLComponent.READ_ONLY_VALUE : SQLComponent.READ_WRITE_VALUE);
|
164 |
update.setObject(SQLComponent.READ_ONLY_FIELD, lock ? SQLComponent.READ_ONLY_VALUE : SQLComponent.READ_WRITE_VALUE);
|
161 |
final User user = UserManager.getUser();
|
165 |
final User user = UserManager.getUser();
|
162 |
if (user != null)
|
166 |
if (user != null)
|
163 |
update.setObject(SQLComponent.READ_ONLY_USER_FIELD, user.getId());
|
167 |
update.setObject(SQLComponent.READ_ONLY_USER_FIELD, user.getId());
|
164 |
update.setWhere(new Where(t.getKey(), ids));
|
168 |
update.setWhere(new Where(t.getKey(), ids));
|
165 |
t.getDBSystemRoot().getDataSource().execute(update.asString());
|
169 |
t.getDBSystemRoot().getDataSource().execute(update.asString());
|
166 |
// don't fire too many times, as each one will cause UpdateQueue to issue a
|
170 |
// don't fire too many times, as each one will cause UpdateQueue to issue a
|
167 |
// request
|
171 |
// request
|
168 |
final Collection<? extends Number> fireIDs = ids.size() < 12 ? ids : Collections.singleton(SQLRow.NONEXISTANT_ID);
|
172 |
final Collection<? extends Number> fireIDs = ids.size() < 12 ? ids : Collections.singleton(SQLRow.NONEXISTANT_ID);
|
169 |
for (final Number fireID : fireIDs)
|
173 |
for (final Number fireID : fireIDs)
|
170 |
t.fireTableModified(fireID.intValue(), update.getFieldsNames());
|
174 |
t.fireTableModified(fireID.intValue(), update.getFieldsNames());
|
171 |
}
|
175 |
});
|
172 |
}, false, true);
|
176 |
this.setName(TM.tr(lock ? "ilist.lockRows" : "ilist.unlockRows"));
|
173 |
this.lock = lock;
|
177 |
this.lock = lock;
|
174 |
}
|
178 |
}
|
175 |
|
179 |
|
176 |
@Override
|
180 |
@Override
|
177 |
public boolean enabledFor(IListeEvent evt) {
|
181 |
public boolean enabledFor(ListEvent evt) {
|
178 |
boolean hasRight = TableAllRights.currentUserHasRight(this.lock ? TableAllRights.USER_UI_LOCK_ROW : TableAllRights.USER_UI_UNLOCK_ROW, evt.getTable());
|
182 |
boolean hasRight = TableAllRights.currentUserHasRight(this.lock ? TableAllRights.USER_UI_LOCK_ROW : TableAllRights.USER_UI_UNLOCK_ROW, evt.getTable());
|
179 |
return !evt.getSelectedRows().isEmpty() && hasRight;
|
183 |
return !evt.getSelectedRowAccessors().isEmpty() && hasRight;
|
180 |
}
|
184 |
}
|
181 |
}
|
185 |
}
|
182 |
|
186 |
|
183 |
private static LockAction LOCK_ACTION;
|
187 |
private static LockAction LOCK_ACTION;
|
184 |
private static LockAction UNLOCK_ACTION;
|
188 |
private static LockAction UNLOCK_ACTION;
|
Line 197... |
Line 201... |
197 |
if (UNLOCK_ACTION == null)
|
201 |
if (UNLOCK_ACTION == null)
|
198 |
UNLOCK_ACTION = new LockAction(false);
|
202 |
UNLOCK_ACTION = new LockAction(false);
|
199 |
return UNLOCK_ACTION;
|
203 |
return UNLOCK_ACTION;
|
200 |
}
|
204 |
}
|
201 |
|
205 |
|
- |
|
206 |
private static final int MD_BATCH_SIZE = 100;
|
- |
|
207 |
private static final RowMetadataCache MD_CACHE = new RowMetadataCache(120, 5000, IListe.class.getName());
|
- |
|
208 |
|
202 |
/**
|
209 |
/**
|
203 |
* When this system property is set, table {@link JTableStateManager state} is never read nor
|
210 |
* When this system property is set, table {@link JTableStateManager state} is never read nor
|
204 |
* written. I.e. the user can change the table state but it will be reset at each launch.
|
211 |
* written. I.e. the user can change the table state but it will be reset at each launch.
|
205 |
*/
|
212 |
*/
|
206 |
public static final String STATELESS_TABLE_PROP = "org.openconcerto.sql.list.statelessTable";
|
213 |
public static final String STATELESS_TABLE_PROP = "org.openconcerto.sql.list.statelessTable";
|
Line 331... |
Line 338... |
331 |
this.naListeners = new ArrayList<IListener>();
|
338 |
this.naListeners = new ArrayList<IListener>();
|
332 |
this.modelPCListeners = new ArrayList<PropertyChangeListener>();
|
339 |
this.modelPCListeners = new ArrayList<PropertyChangeListener>();
|
333 |
|
340 |
|
334 |
this.sorter = new TableSorter();
|
341 |
this.sorter = new TableSorter();
|
335 |
this.jTable = new JTable(this.sorter) {
|
342 |
this.jTable = new JTable(this.sorter) {
|
- |
|
343 |
|
- |
|
344 |
// By default the tooltip doesn't follow the mouse if the string remains the same
|
- |
|
345 |
// (probably for performance reasons)
|
- |
|
346 |
private final boolean followMouseWorkaround = !Boolean.getBoolean("jtable.tooltip_follow_mouse.disable");
|
- |
|
347 |
|
336 |
@Override
|
348 |
@Override
|
337 |
public String getToolTipText(MouseEvent event) {
|
349 |
public String getToolTipText(MouseEvent event) {
|
338 |
final String original = super.getToolTipText(event);
|
350 |
final String original = super.getToolTipText(event);
|
339 |
|
351 |
|
340 |
// Locate the row under the event location
|
352 |
// Locate the row under the event location
|
Line 351... |
Line 363... |
351 |
infoL.add(original.substring(html.length(), original.length() - html.length() - 1));
|
363 |
infoL.add(original.substring(html.length(), original.length() - html.length() - 1));
|
352 |
else
|
364 |
else
|
353 |
infoL.add(original);
|
365 |
infoL.add(original);
|
354 |
}
|
366 |
}
|
355 |
|
367 |
|
356 |
final SQLRowValues row = ITableModel.getLine(this.getModel(), rowIndex).getRow();
|
368 |
final SQLRowAccessor row = ITableModel.getLine(this.getModel(), rowIndex).getRowAccessor();
|
- |
|
369 |
|
- |
|
370 |
final RowRef cacheKey = row.getRowRef();
|
- |
|
371 |
final RowMetadata md = MD_CACHE.get(cacheKey);
|
- |
|
372 |
if (md != null) {
|
- |
|
373 |
final String create = getLine(true, md);
|
- |
|
374 |
final String modif = getLine(false, md);
|
- |
|
375 |
if (create == null && modif == null) {
|
- |
|
376 |
infoL.add(TM.tr("ilist.metadata.na"));
|
- |
|
377 |
} else {
|
- |
|
378 |
if (create != null)
|
- |
|
379 |
infoL.add(create);
|
- |
|
380 |
if (modif != null)
|
- |
|
381 |
infoL.add(modif);
|
- |
|
382 |
}
|
- |
|
383 |
// TODO locked by
|
- |
|
384 |
|
- |
|
385 |
} else {
|
- |
|
386 |
final int half = MD_BATCH_SIZE / 2;
|
- |
|
387 |
final int firstIndex = Math.max(0, rowIndex - half);
|
- |
|
388 |
final int lastIndex = Math.min(getRowCount(), rowIndex + half);
|
- |
|
389 |
final Set<Number> ids = CollectionUtils.newHashSet(MD_BATCH_SIZE);
|
- |
|
390 |
for (int i = firstIndex; i < lastIndex; i++) {
|
- |
|
391 |
ids.add(ITableModel.getLine(this.getModel(), i).getRowAccessor().getIDNumber());
|
- |
|
392 |
}
|
- |
|
393 |
MD_CACHE.fetch(cacheKey, ids);
|
357 |
|
394 |
|
358 |
final String create = getLine(true, row, getSource().getPrimaryTable().getCreationUserField(), getSource().getPrimaryTable().getCreationDateField());
|
- |
|
359 |
if (create != null)
|
- |
|
360 |
infoL.add(create);
|
395 |
infoL.add(TM.tr("ilist.metadata.loading"));
|
361 |
final String modif = getLine(false, row, getSource().getPrimaryTable().getModifUserField(), getSource().getPrimaryTable().getModifDateField());
|
- |
|
362 |
if (modif != null)
|
- |
|
363 |
infoL.add(modif);
|
- |
|
364 |
// TODO locked by
|
396 |
}
|
365 |
|
397 |
|
366 |
final String info;
|
398 |
final String info;
|
367 |
if (infoL.size() == 0)
|
399 |
if (infoL.size() == 0) {
|
368 |
info = null;
|
400 |
info = null;
|
369 |
else
|
401 |
} else {
|
- |
|
402 |
final StringBuilder sb = new StringBuilder(256);
|
- |
|
403 |
sb.append("<html>");
|
370 |
info = "<html>" + CollectionUtils.join(infoL, "<br/>") + "</html>";
|
404 |
sb.append(CollectionUtils.join(infoL, "<br/>"));
|
- |
|
405 |
sb.append("</html>");
|
- |
|
406 |
if (this.followMouseWorkaround) {
|
371 |
// ATTN doesn't follow the mouse if info remains the same, MAYBE add an identifier
|
407 |
// This force the JRE to repaint the tooltip at the mouse location :
|
- |
|
408 |
// 1. even without mainInfo changing (e.g. "unavailable")
|
- |
|
409 |
// 2. but only when changing row
|
- |
|
410 |
// Otherwise (e.g. adding or not a space at the end, for each call) the
|
- |
|
411 |
// tooltip is drawn continuously and CPU load is quite heavy.
|
- |
|
412 |
sb.append("<!--");
|
- |
|
413 |
sb.append(rowIndex);
|
- |
|
414 |
sb.append("-->");
|
- |
|
415 |
}
|
- |
|
416 |
info = sb.toString();
|
- |
|
417 |
}
|
- |
|
418 |
|
372 |
return info;
|
419 |
return info;
|
373 |
}
|
420 |
}
|
374 |
|
421 |
|
375 |
public String getLine(final boolean created, final SQLRowValues row, final SQLField userF, final SQLField dateF) {
|
422 |
public String getLine(final boolean created, final RowMetadata md) {
|
376 |
final Calendar date = dateF == null ? null : row.getDate(dateF.getName());
|
423 |
final Date date = created ? md.getCreation() : md.getModification();
|
377 |
final SQLRowAccessor user = userF == null || row.getObject(userF.getName()) == null || row.isForeignEmpty(userF.getName()) ? null : row.getForeign(userF.getName());
|
424 |
final Integer userID = created ? md.getUserCreate() : md.getUserModify();
|
378 |
if (user == null && date == null)
|
425 |
if (userID == null && date == null)
|
379 |
return null;
|
426 |
return null;
|
380 |
|
427 |
|
381 |
final int userParam;
|
428 |
final int userParam;
|
382 |
final String firstName, lastName;
|
429 |
final String firstName, lastName;
|
383 |
if (user != null) {
|
430 |
if (userID != null) {
|
384 |
userParam = 1;
|
431 |
userParam = 1;
|
- |
|
432 |
final User user = UserManager.getInstance().getUser(userID);
|
385 |
firstName = user.getString("PRENOM");
|
433 |
firstName = user.getFirstName();
|
386 |
lastName = user.getString("NOM");
|
434 |
lastName = user.getName();
|
387 |
} else {
|
435 |
} else {
|
388 |
userParam = 0;
|
436 |
userParam = 0;
|
389 |
firstName = null;
|
437 |
firstName = null;
|
390 |
lastName = null;
|
438 |
lastName = null;
|
391 |
}
|
439 |
}
|
392 |
|
440 |
|
393 |
return TM.tr("ilist.metadata", created ? 1 : 0, userParam, firstName, lastName, date == null ? 0 : 1, date == null ? null : date.getTime());
|
441 |
return TM.tr("ilist.metadata", created ? 1 : 0, userParam, firstName, lastName, date == null ? 0 : 1, date);
|
394 |
}
|
442 |
}
|
395 |
|
443 |
|
396 |
@Override
|
444 |
@Override
|
397 |
protected TableColumnModel createDefaultColumnModel() {
|
445 |
protected TableColumnModel createDefaultColumnModel() {
|
398 |
// allow to hide columns
|
446 |
// allow to hide columns
|
Line 599... |
Line 647... |
599 |
final RowAction res = new PredicateRowAction(action, false, true, id).setPredicate(IListeEvent.getSingleSelectionPredicate());
|
647 |
final RowAction res = new PredicateRowAction(action, false, true, id).setPredicate(IListeEvent.getSingleSelectionPredicate());
|
600 |
this.addIListeAction(res);
|
648 |
this.addIListeAction(res);
|
601 |
return res;
|
649 |
return res;
|
602 |
}
|
650 |
}
|
603 |
|
651 |
|
- |
|
652 |
// Transitional class while we convert RowAction to SQLRowValuesAction
|
- |
|
653 |
@Deprecated
|
- |
|
654 |
static public final class ConvertedAction extends SQLRowValuesAction {
|
- |
|
655 |
private final RowAction rowAction;
|
- |
|
656 |
|
- |
|
657 |
public ConvertedAction(final RowAction a) {
|
- |
|
658 |
super(a.inHeader(), a.inPopupMenu(), a.getID(), (evt) -> {
|
- |
|
659 |
a.getAction().actionPerformed(new ActionEvent(evt.getSource(), ActionEvent.ACTION_PERFORMED, null));
|
- |
|
660 |
});
|
- |
|
661 |
this.rowAction = a;
|
- |
|
662 |
if (a.getAction().getValue(Action.NAME) != null)
|
- |
|
663 |
this.setName(String.valueOf(a.getAction().getValue(Action.NAME)));
|
- |
|
664 |
}
|
- |
|
665 |
|
- |
|
666 |
@Override
|
- |
|
667 |
public boolean enabledFor(ListEvent evt) {
|
- |
|
668 |
return this.getRowAction().enabledFor(evt);
|
- |
|
669 |
}
|
- |
|
670 |
|
- |
|
671 |
public final RowAction getRowAction() {
|
- |
|
672 |
return this.rowAction;
|
- |
|
673 |
}
|
- |
|
674 |
}
|
- |
|
675 |
|
- |
|
676 |
public final RowAction addRowValuesAction(SQLRowValuesAction a) {
|
- |
|
677 |
final RowAction action;
|
- |
|
678 |
if (a instanceof ConvertedAction) {
|
- |
|
679 |
action = ((ConvertedAction) a).getRowAction();
|
- |
|
680 |
} else {
|
- |
|
681 |
action = new RowAction(new AbstractAction(a.getName()) {
|
- |
|
682 |
@Override
|
- |
|
683 |
public void actionPerformed(ActionEvent e) {
|
- |
|
684 |
a.getAction().accept(IListe.get(e).createListEvent());
|
- |
|
685 |
}
|
- |
|
686 |
}, a.inHeader(), a.inPopupMenu(), a.getID()) {
|
- |
|
687 |
|
- |
|
688 |
@Override
|
- |
|
689 |
public boolean enabledFor(ListEvent evt) {
|
- |
|
690 |
return a.enabledFor(evt);
|
- |
|
691 |
}
|
- |
|
692 |
|
- |
|
693 |
};
|
- |
|
694 |
}
|
- |
|
695 |
if (this.addIListeAction(action))
|
- |
|
696 |
return action;
|
- |
|
697 |
else
|
- |
|
698 |
return null;
|
- |
|
699 |
}
|
- |
|
700 |
|
- |
|
701 |
public final Map<SQLRowValuesAction, IListeAction> addRowValuesActions(Collection<? extends SQLRowValuesAction> actions) {
|
- |
|
702 |
final Map<SQLRowValuesAction, IListeAction> res = new IdentityHashMap<>();
|
- |
|
703 |
for (final SQLRowValuesAction a : actions) {
|
- |
|
704 |
final RowAction action = addRowValuesAction(a);
|
- |
|
705 |
if (action != null)
|
- |
|
706 |
res.put(a, action);
|
- |
|
707 |
}
|
- |
|
708 |
return res;
|
- |
|
709 |
}
|
- |
|
710 |
|
604 |
public final void addIListeActions(Collection<? extends IListeAction> actions) {
|
711 |
public final void addIListeActions(Collection<? extends IListeAction> actions) {
|
605 |
for (final IListeAction a : actions)
|
712 |
for (final IListeAction a : actions)
|
606 |
this.addIListeAction(a);
|
713 |
this.addIListeAction(a);
|
607 |
}
|
714 |
}
|
608 |
|
715 |
|
Line 617... |
Line 724... |
617 |
}
|
724 |
}
|
618 |
}
|
725 |
}
|
619 |
return -1;
|
726 |
return -1;
|
620 |
}
|
727 |
}
|
621 |
|
728 |
|
622 |
public final void addIListeAction(IListeAction action) {
|
729 |
public final boolean addIListeAction(IListeAction action) {
|
623 |
// we need to handle addition of an already added action at least for setDefaultRowAction()
|
730 |
// we need to handle addition of an already added action at least for setDefaultRowAction()
|
624 |
if (this.rowActions.containsKey(action))
|
731 |
if (this.rowActions.containsKey(action))
|
625 |
return;
|
732 |
return false;
|
626 |
final ButtonsBuilder headerBtns = action.getHeaderButtons();
|
733 |
final ButtonsBuilder headerBtns = action.getHeaderButtons();
|
627 |
this.rowActions.put(action, headerBtns);
|
734 |
this.rowActions.put(action, headerBtns);
|
628 |
if (headerBtns.getContent().size() > 0) {
|
735 |
if (headerBtns.getContent().size() > 0) {
|
629 |
updateButton(headerBtns, new IListeEvent(this));
|
736 |
updateButton(headerBtns, this.createListEvent());
|
630 |
for (final JButton headerBtn : headerBtns.getContent().keySet()) {
|
737 |
for (final JButton headerBtn : headerBtns.getContent().keySet()) {
|
631 |
headerBtn.setOpaque(false);
|
738 |
headerBtn.setOpaque(false);
|
632 |
this.btnPanel.add(headerBtn, findGroupIndex((String) headerBtn.getClientProperty(ButtonsBuilder.GROUPNAME_PROPNAME)));
|
739 |
this.btnPanel.add(headerBtn, findGroupIndex((String) headerBtn.getClientProperty(ButtonsBuilder.GROUPNAME_PROPNAME)));
|
633 |
}
|
740 |
}
|
634 |
this.btnPanel.setVisible(true);
|
741 |
this.btnPanel.setVisible(true);
|
635 |
}
|
742 |
}
|
- |
|
743 |
return true;
|
636 |
}
|
744 |
}
|
637 |
|
745 |
|
638 |
public final void removeIListeActions(Collection<? extends IListeAction> actions) {
|
746 |
public final void removeIListeActions(Collection<? extends IListeAction> actions) {
|
639 |
for (final IListeAction a : actions)
|
747 |
for (final IListeAction a : actions)
|
640 |
this.removeIListeAction(a);
|
748 |
this.removeIListeAction(a);
|
Line 654... |
Line 762... |
654 |
if (action.equals(this.defaultRowAction))
|
762 |
if (action.equals(this.defaultRowAction))
|
655 |
this.setDefaultRowAction(null);
|
763 |
this.setDefaultRowAction(null);
|
656 |
}
|
764 |
}
|
657 |
|
765 |
|
658 |
private void updateButtons() {
|
766 |
private void updateButtons() {
|
659 |
final IListeEvent evt = new IListeEvent(this);
|
767 |
final IListeEvent evt = this.createListEvent();
|
660 |
for (final ButtonsBuilder btns : this.rowActions.values()) {
|
768 |
for (final ButtonsBuilder btns : this.rowActions.values()) {
|
661 |
this.updateButton(btns, evt);
|
769 |
this.updateButton(btns, evt);
|
662 |
}
|
770 |
}
|
663 |
}
|
771 |
}
|
664 |
|
772 |
|
Line 668... |
Line 776... |
668 |
}
|
776 |
}
|
669 |
}
|
777 |
}
|
670 |
|
778 |
|
671 |
private JPopupMenu updatePopupMenu(final boolean onRows) {
|
779 |
private JPopupMenu updatePopupMenu(final boolean onRows) {
|
672 |
this.popup.removeAll();
|
780 |
this.popup.removeAll();
|
673 |
final PopupEvent evt = new PopupEvent(this, onRows);
|
781 |
final PopupEvent evt = this.createPopupEvent(onRows);
|
674 |
final Action defaultAction = this.defaultRowAction != null ? this.defaultRowAction.getDefaultAction(evt) : null;
|
782 |
final Action defaultAction = this.defaultRowAction != null ? this.defaultRowAction.getDefaultAction(evt) : null;
|
675 |
final VirtualMenu menu = VirtualMenu.createRoot(null);
|
783 |
final VirtualMenu menu = VirtualMenu.createRoot(null);
|
676 |
for (final IListeAction a : this.rowActions.keySet()) {
|
784 |
for (final IListeAction a : this.rowActions.keySet()) {
|
677 |
final PopupBuilder popupContent = a.getPopupContent(evt);
|
785 |
final PopupBuilder popupContent = a.getPopupContent(evt);
|
678 |
if (defaultAction != null && a == this.defaultRowAction) {
|
786 |
if (defaultAction != null && a == this.defaultRowAction) {
|
Line 719... |
Line 827... |
719 |
|
827 |
|
720 |
private void performDefaultAction(MouseEvent e) {
|
828 |
private void performDefaultAction(MouseEvent e) {
|
721 |
// special method needed since sometimes getPopupContent() can access the DB (optionally
|
829 |
// special method needed since sometimes getPopupContent() can access the DB (optionally
|
722 |
// creating threads) or be slow
|
830 |
// creating threads) or be slow
|
723 |
if (this.defaultRowAction != null) {
|
831 |
if (this.defaultRowAction != null) {
|
724 |
final Action defaultAction = this.defaultRowAction.getDefaultAction(new IListeEvent(this));
|
832 |
final Action defaultAction = this.defaultRowAction.getDefaultAction(this.createListEvent());
|
725 |
if (defaultAction != null)
|
833 |
if (defaultAction != null)
|
726 |
defaultAction.actionPerformed(new ActionEvent(e.getSource(), e.getID(), null, e.getWhen(), e.getModifiers()));
|
834 |
defaultAction.actionPerformed(new ActionEvent(e.getSource(), e.getID(), null, e.getWhen(), e.getModifiers()));
|
727 |
}
|
835 |
}
|
728 |
}
|
836 |
}
|
729 |
|
837 |
|
- |
|
838 |
final IListeEvent createListEvent() {
|
- |
|
839 |
return createEvent((vals, accessors) -> new IListeEvent(this, vals, accessors));
|
- |
|
840 |
}
|
- |
|
841 |
|
- |
|
842 |
final PopupEvent createPopupEvent(final boolean onRows) {
|
- |
|
843 |
return createEvent((vals, accessors) -> new PopupEvent(this, vals, accessors, onRows));
|
- |
|
844 |
}
|
- |
|
845 |
|
- |
|
846 |
private final <E extends ListEvent> E createEvent(final BiFunction<List<SQLRowValues>, List<? extends SQLRowAccessor>, E> ctor) {
|
- |
|
847 |
final List<SQLRowValues> vals;
|
- |
|
848 |
final List<? extends SQLRowAccessor> accessors;
|
- |
|
849 |
if (this.getSource().getKeepMode() == KeepMode.GRAPH) {
|
- |
|
850 |
vals = this.getSelectedRows();
|
- |
|
851 |
accessors = vals;
|
- |
|
852 |
} else {
|
- |
|
853 |
vals = null;
|
- |
|
854 |
accessors = this.getSelectedRowAccessors();
|
- |
|
855 |
}
|
- |
|
856 |
return ctor.apply(vals, accessors);
|
- |
|
857 |
}
|
- |
|
858 |
|
730 |
private void uiInit() {
|
859 |
private void uiInit() {
|
731 |
// * filter
|
860 |
// * filter
|
732 |
this.filter.addMouseListener(new MouseAdapter() {
|
861 |
this.filter.addMouseListener(new MouseAdapter() {
|
733 |
@Override
|
862 |
@Override
|
734 |
public void mouseClicked(MouseEvent e) {
|
863 |
public void mouseClicked(MouseEvent e) {
|
Line 778... |
Line 907... |
778 |
final XTableColumnModel colModel = (XTableColumnModel) getJTable().getColumnModel();
|
907 |
final XTableColumnModel colModel = (XTableColumnModel) getJTable().getColumnModel();
|
779 |
final JComponent cb = (JComponent) e.getSource();
|
908 |
final JComponent cb = (JComponent) e.getSource();
|
780 |
final int columnIndex = ((Number) cb.getClientProperty(COL_INDEX_KEY)).intValue();
|
909 |
final int columnIndex = ((Number) cb.getClientProperty(COL_INDEX_KEY)).intValue();
|
781 |
final TableColumn col = colModel.getColumn(columnIndex, false);
|
910 |
final TableColumn col = colModel.getColumn(columnIndex, false);
|
782 |
final boolean newValue = !colModel.isColumnVisible(col);
|
911 |
final boolean newValue = !colModel.isColumnVisible(col);
|
- |
|
912 |
// Workaround for crash on linux Java 16 with Nimbus L&F or Flat L&F
|
- |
|
913 |
IListe.this.jTable.getTableHeader().setDraggedColumn(null);
|
- |
|
914 |
|
783 |
// don't remove last column
|
915 |
// don't remove last column
|
784 |
if (newValue || colModel.getColumnCount(true) > 1)
|
916 |
if (newValue || colModel.getColumnCount(true) > 1)
|
785 |
colModel.setColumnVisible(col, newValue);
|
917 |
colModel.setColumnVisible(col, newValue);
|
786 |
}
|
918 |
}
|
787 |
};
|
919 |
};
|
Line 947... |
Line 1079... |
947 |
|
1079 |
|
948 |
this.setOpaque(false);
|
1080 |
this.setOpaque(false);
|
949 |
this.setTransferHandler(new FileTransfertHandler(getSource().getPrimaryTable()));
|
1081 |
this.setTransferHandler(new FileTransfertHandler(getSource().getPrimaryTable()));
|
950 |
|
1082 |
|
951 |
if (this.getSource().getPrimaryTable().getFieldRaw(SQLComponent.READ_ONLY_FIELD) != null) {
|
1083 |
if (this.getSource().getPrimaryTable().getFieldRaw(SQLComponent.READ_ONLY_FIELD) != null) {
|
952 |
this.addIListeAction(getUnlockAction());
|
1084 |
this.addRowValuesAction(getUnlockAction());
|
953 |
this.addIListeAction(getLockAction());
|
1085 |
this.addRowValuesAction(getLockAction());
|
954 |
}
|
1086 |
}
|
955 |
}
|
1087 |
}
|
956 |
|
1088 |
|
957 |
protected synchronized final void invertDebug() {
|
1089 |
protected synchronized final void invertDebug() {
|
958 |
this.setDebug(!this.debugFilter);
|
1090 |
this.setDebug(!this.debugFilter);
|
Line 1147... |
Line 1279... |
1147 |
final ListSQLLine line = this.getLine(index);
|
1279 |
final ListSQLLine line = this.getLine(index);
|
1148 |
final Object toCast;
|
1280 |
final Object toCast;
|
1149 |
if (clazz == SQLRowValues.class) {
|
1281 |
if (clazz == SQLRowValues.class) {
|
1150 |
toCast = line.getRow().toImmutable();
|
1282 |
toCast = line.getRow().toImmutable();
|
1151 |
} else if (clazz == SQLRow.class) {
|
1283 |
} else if (clazz == SQLRow.class) {
|
- |
|
1284 |
toCast = line.getRowAccessor().asRow();
|
- |
|
1285 |
} else if (clazz == SQLRowAccessor.class) {
|
1152 |
toCast = line.getRow().asRow();
|
1286 |
toCast = line.getRowAccessor();
|
1153 |
} else if (clazz == ListSQLLine.class) {
|
1287 |
} else if (clazz == ListSQLLine.class) {
|
1154 |
toCast = line;
|
1288 |
toCast = line;
|
1155 |
} else {
|
1289 |
} else {
|
1156 |
throw new IllegalArgumentException("Not implemented : " + clazz);
|
1290 |
throw new IllegalArgumentException("Not implemented : " + clazz);
|
1157 |
}
|
1291 |
}
|
Line 1171... |
Line 1305... |
1171 |
|
1305 |
|
1172 |
public SQLRowValues getSelectedRow() {
|
1306 |
public SQLRowValues getSelectedRow() {
|
1173 |
return this.getSelectedRow(SQLRowValues.class);
|
1307 |
return this.getSelectedRow(SQLRowValues.class);
|
1174 |
}
|
1308 |
}
|
1175 |
|
1309 |
|
- |
|
1310 |
public SQLRowAccessor getSelectedRowAccessor() {
|
- |
|
1311 |
return this.getSelectedRow(SQLRowAccessor.class);
|
- |
|
1312 |
}
|
- |
|
1313 |
|
1176 |
// selected row cannot be inferred from iterateSelectedRows() since the user might have selected
|
1314 |
// selected row cannot be inferred from iterateSelectedRows() since the user might have selected
|
1177 |
// the last row anywhere in the selection
|
1315 |
// the last row anywhere in the selection
|
1178 |
private final <R extends SQLRowAccessor> R getSelectedRow(final Class<R> clazz) {
|
1316 |
private final <R extends SQLRowAccessor> R getSelectedRow(final Class<R> clazz) {
|
1179 |
final int selectedIndex = this.state.getSelectedIndex().intValue();
|
1317 |
final int selectedIndex = this.state.getSelectedIndex().intValue();
|
1180 |
if (selectedIndex == BaseListStateModel.INVALID_INDEX)
|
1318 |
if (selectedIndex == BaseListStateModel.INVALID_INDEX)
|
Line 1193... |
Line 1331... |
1193 |
|
1331 |
|
1194 |
public final List<ListSQLLine> getSelectedLines() {
|
1332 |
public final List<ListSQLLine> getSelectedLines() {
|
1195 |
return iterateSelectedRows(ListSQLLine.class);
|
1333 |
return iterateSelectedRows(ListSQLLine.class);
|
1196 |
}
|
1334 |
}
|
1197 |
|
1335 |
|
- |
|
1336 |
public final List<SQLRowAccessor> getSelectedRowAccessors() {
|
- |
|
1337 |
return iterateSelectedRows(SQLRowAccessor.class);
|
- |
|
1338 |
}
|
- |
|
1339 |
|
1198 |
private final <R> List<R> iterateSelectedRows(final Class<R> clazz) {
|
1340 |
private final <R> List<R> iterateSelectedRows(final Class<R> clazz) {
|
1199 |
final ListSelectionModel selectionModel = this.getJTable().getSelectionModel();
|
1341 |
final ListSelectionModel selectionModel = this.getJTable().getSelectionModel();
|
1200 |
if (selectionModel.isSelectionEmpty())
|
1342 |
if (selectionModel.isSelectionEmpty())
|
1201 |
return Collections.emptyList();
|
1343 |
return Collections.emptyList();
|
1202 |
|
1344 |
|
Line 1469... |
Line 1611... |
1469 |
this.tableStateManager.beginAutoSave();
|
1611 |
this.tableStateManager.beginAutoSave();
|
1470 |
loadTableState();
|
1612 |
loadTableState();
|
1471 |
}
|
1613 |
}
|
1472 |
}
|
1614 |
}
|
1473 |
|
1615 |
|
- |
|
1616 |
public final boolean saveTableState() throws IOException {
|
- |
|
1617 |
final boolean hasFile = this.getConfigFile() != null;
|
- |
|
1618 |
if (hasFile)
|
- |
|
1619 |
this.tableStateManager.saveState();
|
- |
|
1620 |
return hasFile;
|
- |
|
1621 |
}
|
- |
|
1622 |
|
1474 |
private boolean loadTableState() {
|
1623 |
private boolean loadTableState() {
|
1475 |
// - if configFile changes setConfigFile() calls us
|
1624 |
// - if configFile changes setConfigFile() calls us
|
1476 |
// - if the model changes, fireTableStructureChanged() is called and thus
|
1625 |
// - if the model changes, fireTableStructureChanged() is called and thus
|
1477 |
// JTable.createDefaultColumnsFromModel() which calls us
|
1626 |
// JTable.createDefaultColumnsFromModel() which calls us
|
1478 |
if (this.getConfigFile() != null && this.getModel() != null)
|
1627 |
if (this.getConfigFile() != null && this.getModel() != null)
|