Files
VisualSapfor/src/Common/Visual/DataSetControlForm.java
2025-03-13 00:32:20 +03:00

585 lines
24 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package Common.Visual;
import Common.CommonConstants;
import Common.Database.Objects.DBObject;
import Common.Database.Objects.Grid.TableVisualData;
import Common.Database.Tables.DBTable;
import Common.Database.Tables.DataSet;
import Common.Database.Tables.FKBehaviour;
import Common.MainModule_;
import Common.Passes.PassCode_;
import Common.Utils.TextLog;
import Common.Utils.Utils_;
import Common.Visual.Menus.DataMenuBar;
import Common.Visual.Menus.TableMenu;
import Common.Visual.Tables.*;
import Common.Visual.Tables.Grid.GridAnchestor;
import Common.Visual.Windows.Dialog.DBObjectDialog;
import javax.swing.*;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public abstract class DataSetControlForm<D extends DBObject> extends ControlForm<DataTable> {
protected DataSet<?, D> dataSource; //источник данных
protected D current = null; //заменить все обращения к мейн модулю.
protected DataMenuBar bar = null; //верхняя панель меню
protected int current_row_i; //индекс текущей строки.
protected boolean events_on = true;
protected String colNamesAndSizes = "";
protected Vector<DBObjectFilter_<D>> allFilters = new Vector<>();
Vector<ColumnInfo<D>> columns = new Vector<>(); //информация о столбцах и их оформлении
MatchesCounter counter_ui = null;
//--
Object savedCurrentKey = null;
Vector<Object> savedSelectedKeys = new Vector<>();
public DataSetControlForm(DataSet<?, D> dataSource_in, JPanel mountPanel_in) {
super(DataTable.class, mountPanel_in);
dataSource = dataSource_in;
//--
columns.clear();
columns.add(createPKColumn());
if (hasCheckBox())
columns.add(createCheckBoxColummn());
createColumns();
//--
createFilters();
//--
if (hasMenuBar()) {
try {
if (!MainModule_.instance.getUI().menuBars.containsKey(dataSource.getClass())) {
bar = createMenuBar();
if (hasCheckBox())
bar.createSelectionButtons(dataSource);
MainModule_.instance.getUI().menuBars.put(dataSource.getClass(), bar);
} else {
bar = MainModule_.instance.getUI().menuBars.get(dataSource.getClass());
bar.setDataSource(dataSource);
}
mountPanel.add(bar, BorderLayout.NORTH);
//--
counter_ui = (count -> bar.countLabel.setText(String.valueOf(count)));
//--фильтры всегда в конец бара.
// bar.add(new JSeparator());
for (FilterFlag filter : getFilters(FilterFlag.class)) {
bar.add(filter.getControl());
}
for (JMenu filter : getFilters(DataSetFiltersMenu.class)) {
bar.addMenus(filter);
}
//------------------------
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
//--
public DataMenuBar getMenuBar() {
return bar;
}
protected boolean isPKVisible() {
return true;
}
protected ColumnInfo<D> createPKColumn() {
return new ColumnInfo<D>(dataSource.getPKName()) {
@Override
public Object getFieldAt(D object) {
return object.getPK();
}
@Override
public boolean isVisible() {
return isPKVisible();
}
};
}
protected boolean hasCheckBox() {
return true;
}
protected ColumnInfo<D> createCheckBoxColummn() {
return new ColumnInfo<D>("") {
@Override
public Object getFieldAt(D object) {
return object.isSelected();
}
@Override
public int getMinWidth() {
return 25;
}
@Override
public int getMaxWidth() {
return 25;
}
@Override
public Class getRendererClass() {
return DBObjectSelectionRenderer.class;
}
@Override
public Class getEditorClass() {
return DBObjectSelector.class;
}
};
}
<M> Vector<M> getFilters(Class<M> f) {
Vector<M> res = new Vector<>();
for (DBObjectFilter_ filter_ : allFilters) {
//либо М, либо наследует от М
if (filter_.getClass().equals(f) || filter_.getClass().getSuperclass().equals(f)) {
res.add((M) filter_);
}
}
return res;
}
protected final void AddFilters(DBObjectFilter_<D>... new_filters) {
Collections.addAll(allFilters, new_filters);
}
protected final void AddColumns(ColumnInfo<D>... new_columns) {
Collections.addAll(columns, new_columns);
}
public ColumnInfo<D> getColumnInfo(int i) {
return columns.get(i);
}
//--
void SaveColumns() {
if (MainModule_.instance.getDb() != null) {
try {
if (needsCurrent()) {
Vector<String> widths = IntStream.range(0, columns.size()).mapToObj(i -> String.valueOf(control.getColumnModel().getColumn(i).getWidth())).collect(Collectors.toCollection(Vector::new));
String packed = String.join("|", widths);
TableVisualData tableVisualData;
if (MainModule_.instance.getDb().tablesVisualData.containsKey(getCurrentName())) {
tableVisualData = MainModule_.instance.getDb().tablesVisualData.get(getCurrentName());
} else {
tableVisualData = new TableVisualData(getCurrentName());
MainModule_.instance.getDb().Insert(tableVisualData);
}
tableVisualData.sizes = packed;
MainModule_.instance.getDb().Update(tableVisualData);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Vector<String> getHeaders() {
return columns.stream().map(ColumnInfo::getName).collect(Collectors.toCollection(Vector::new));
}
protected Comparator<D> getDefaultComparator() {
return null;
}
Vector<Object> getVisibleKeys() {
Comparator comparator = getDefaultComparator();
Vector<Object> res_keys = new Vector<>();
if (comparator == null) {
for (D object : dataSource.Data.values()) {
if (isObjectVisible(object))
res_keys.add(object.getPK());
}
} else {
Vector<D> raw = new Vector<>();
for (D object : dataSource.Data.values()) {
if (isObjectVisible(object))
raw.add(object);
}
raw.sort(comparator);
for (D object : raw)
res_keys.add(object.getPK());
}
return res_keys;
}
@Override
protected void createControl() {
GridAnchestor table_data_model = new GridAnchestor(getHeaders(), getVisibleKeys()) {
@SuppressWarnings("unchecked")
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object key = data.get(rowIndex);
D object = dataSource.get((key));
return columns.get(columnIndex).getFieldAt(object);
}
@Override
public boolean isCellEditable(int row, int col) {
return columns.get(col).isEditable();
}
//------------------------------------------------------------------------------------
@Override
public void setValueAt(Object value, int row, int col) {
fireTableCellUpdated(row, col);
}
};
control = new DataTable(table_data_model) {
@Override
public TableMenu CreateMenu() {
return new TableMenu(this);
}
//строго говоря эта штука нужна только для рендереров и едиторов клеток.
@Override
public DBObject getRowObject(int rowIndex) {
//вот так делать НЕЛЬЗЯ. модель только для внутреннего пользования
// Object key = table_data_model.data.get(rowIndex);
//из таблицы можно пользоваться только getValueAt
//иначе сортировка не будет работать.
Object key = getValueAt(rowIndex, 0);
return dataSource.get(key);
}
//-----------------------------NEW-------------------------------------
@Override
public void CorrectColumnsSizes() {
if ((MainModule_.instance.getDb() != null)
&& needsCurrent()
&& MainModule_.instance.getDb().tablesVisualData.containsKey(getCurrentName())) {
if (!getColumnsProfile().equalsIgnoreCase(colNamesAndSizes)) {
TableVisualData grid = MainModule_.instance.getDb().tablesVisualData.get(getCurrentName());
String[] data = grid.sizes.split("\\|");
for (int i = 0; i < columns.size(); ++i) {
if (i <= (data.length - 1)) {
int width = Integer.parseInt(data[i]);
getColumnModel().getColumn(i).setPreferredWidth(width);
getColumnModel().getColumn(i).setWidth(width);
}
}
}
} else
super.CorrectColumnsSizes(); //обычный авторазмер.
}
public String getColumnsProfile() {
String res = "";
for (int i = 0; i < getColumnModel().getColumnCount(); i++) {
if (i > 0) res += ",";
TableColumn column = getColumnModel().getColumn(i);
res += column.getHeaderValue();
res += ":";
res += column.getWidth();
}
return res;
}
@Override
public void Init() {
for (int i = 0; i < columns.size(); i++) {
ColumnInfo columnInfo = columns.get(i);
if (columnInfo.isVisible()) {
if (columnInfo.hasRenderer())
getColumnModel().getColumn(i).setCellRenderer(MainModule_.instance.getUI().getTableRenderer(columnInfo.getRendererClass()));
if (columnInfo.hasEditor())
getColumnModel().getColumn(i).setCellEditor(MainModule_.instance.getUI().getTableEditor(columnInfo.getEditorClass()));
if (columnInfo.hasMaxWidth())
getColumnModel().getColumn((i)).setMaxWidth(columnInfo.getMaxWidth());
if (columnInfo.hasMinWidth())
getColumnModel().getColumn((i)).setMinWidth(columnInfo.getMinWidth());
} else {
getColumnModel().getColumn(i).setMinWidth(0);
getColumnModel().getColumn(i).setMaxWidth(0);
}
}
//обновление в БД при ручном изменении размера столбиков.--------->>
getTableHeader().addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent arg0) {
String new_colNamesAndSizes = getColumnsProfile();
// check if changed, if yes, persist...
if (!colNamesAndSizes.equals(new_colNamesAndSizes)) {
colNamesAndSizes = new_colNamesAndSizes;
SaveColumns();
}
}
});
//------------------------->>
}
};
if (needsCurrent()) {
current_row_i = CommonConstants.Nan;
ListSelectionModel selModel = control.getSelectionModel();
selModel.addListSelectionListener(e -> {
int row = control.getSelectedRow();
if ((row >= 0)) {
if (row != current_row_i) {
current_row_i = row;
setCurrent((D) control.getRowObject(row));
if (events_on) {
try {
ShowCurrentObject();
} catch (Exception ex) {
Utils_.MainLog.PrintException(ex);
}
}
}
} else {
current_row_i = CommonConstants.Nan;
dropCurrent();
if (events_on) {
try {
ShowNoCurrentObject();
} catch (Exception ex) {
Utils_.MainLog.PrintException(ex);
}
}
}
});
//двойной клик мыши.------------------------------------------------------
control.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if ((e.getClickCount() == 2) && (getCurrent() != null)) {
try {
MouseAction2();
} catch (Exception ex) {
Utils_.MainLog.PrintException(ex);
}
}
}
});
control.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_DELETE:
if (getDeletePassCode() != null) {
MainModule_.instance.getPass(getDeletePassCode()).Do();
}
break;
case KeyEvent.VK_ENTER:
try {
MouseAction2();
} catch (Exception ex) {
Utils_.MainLog.PrintException(ex);
}
break;
}
}
}
);
//----------------------------------------------------------------------------
//при переотображении таблицы скидываем текущий объект!!
dropCurrent();
try {
ShowNoCurrentObject();
} catch (Exception e) {
Utils_.MainLog.PrintException(e);
}
}
for (HeaderTextFilter filter : getFilters(HeaderTextFilter.class))
filter.Mount(getControl());
}
protected DataMenuBar createMenuBar() {
return new DataMenuBar(dataSource.getPluralDescription());
}
protected void createFilters() {
}
protected abstract void createColumns();
boolean ApplyFilters(D object) {
for (DBObjectFilter_ filterInterface : allFilters) {
if (!filterInterface.Validate(object))
return false;
}
return true;
}
@Override
protected void redrawControl() {
control.CorrectSizes();
}
protected void ShowCurrentObject() throws Exception {
if (dataSource instanceof DBTable) {
DBTable table = (DBTable) dataSource;
for (Class dep : table.getFKDependencies().keySet()) {
FKBehaviour behaviour = table.getFKDependencies().get(dep);
switch (behaviour.ui) {
case ACTIVE:
table.getDb().getTable(dep).ShowUI();
break;
case PASSIVE:
break;
}
}
}
}
protected void ShowNoCurrentObject() throws Exception {
if (dataSource instanceof DBTable) {
DBTable table = (DBTable) dataSource;
for (Class dep : table.getFKDependencies().keySet()) {
FKBehaviour behaviour = table.getFKDependencies().get(dep);
switch (behaviour.ui) {
case ACTIVE:
table.getDb().getTable(dep).ClearUI();
break;
case PASSIVE:
break;
}
}
}
}
protected void MouseAction2() throws Exception {
}
//-
protected boolean hasMenuBar() {
return true;
}
public void dropCurrent() {
current = null;
}
@SuppressWarnings("unchecked")
protected DBObjectDialog getDialog() {
return null;
}
protected boolean isObjectEditable(D object) {
return true;
}
//БАЗОВЫЙ ФУНКЦИОНАЛ ФОРМЫ
@Override
public void Show() {
for (DBObjectFilter_ filter_ : allFilters) filter_.DropMatchesCount();
super.Show();
if (counter_ui != null) counter_ui.ShowMatchesCount(getRowCount());
for (DBObjectFilter_ filter_ : allFilters) filter_.ShowMatchesCount();
}
public void Show(Object pk) {
Show();
SetCurrentByPK(pk);
}
@Override
public void Clear() {
super.Clear();
if (counter_ui != null) counter_ui.ShowNoMatches();
}
public int getRowCount() {
return control.getRowCount();
}
//ТЕКУЩИЕ И ВЫБРАННЫЕ ОБЪЕКТЫ
public void SaveLastCurrent() {
savedCurrentKey = null;
savedSelectedKeys.clear();
if (needsCurrent() && (getCurrent() != null)) {
savedCurrentKey = getCurrent().getPK();
}
savedSelectedKeys = getAllSelectedKeys();
}
public void RestoreLastCurrent() {
for (Object key : savedSelectedKeys) {
if (dataSource.containsKey(key))
dataSource.get(key).Select(true);
}
if ((savedCurrentKey != null) && (dataSource.containsKey(savedCurrentKey))) {
SetCurrentByPK(savedCurrentKey);
}
}
public boolean isObjectVisible(D object) {
return ApplyFilters(object);
}
public int getSelectedCount() {
return (int) dataSource.Data.values().stream().filter(d -> isObjectVisible(d) && d.isSelected()).count();
}
public Vector<D> getSelectedItems() {
return dataSource.Data.values().stream().filter(d -> isObjectVisible(d) && d.isSelected()).collect(Collectors.toCollection(Vector::new));
}
public Vector<Object> getSelectedKeys() {
return dataSource.Data.values().stream().filter(d -> isObjectVisible(d) && d.isSelected()).map(d -> d.getPK()).collect(Collectors.toCollection(Vector::new));
}
//в том числе и невидимые. нужно для сохранения галок при перезакачке бд.
public Vector<Object> getAllSelectedKeys() {
return dataSource.Data.values().stream().filter(DBObject::isSelected).map(d -> d.getPK()).collect(Collectors.toCollection(Vector::new));
}
public boolean CheckCurrent(TextLog log) {
if (current == null) {
log.Writeln_(dataSource.getSingleDescription() + " не выбран(а)");
return false;
}
return true;
}
public boolean matchCurrentID(int id_in) {
return (current != null) && (((int) current.getPK()) == id_in);
}
public boolean CheckSelectedOrCurrent(TextLog log) {
if ((getSelectedCount() == 0) && (!needsCurrent() || (getCurrent() == null))) {
log.Writeln_(dataSource.getPluralDescription() + ":");
log.Writeln_("Отсутствуют отмеченные объекты, или текущий объект!");
return false;
}
return true;
}
protected boolean needsCurrent() {
return true;
} //нужно ли отслеживать текущий объект.
protected String getCurrentName() {
return dataSource.d.getSimpleName();
}
public D getCurrent() {
return current;
}
public D setCurrent(D object) {
return current = object;
}
public Vector<D> getSelectedOrCurrent() {
Vector<D> res = new Vector<>();
if (getSelectedCount() > 0)
res = getSelectedItems();
else {
if (needsCurrent() && (getCurrent() != null)) {
res.add(getCurrent());
}
}
return res;
}
public Vector<Object> getSelectedOrCurrentKeys() {
Vector<Object> res = new Vector<>();
if (getSelectedCount() > 0)
res = getSelectedKeys();
else {
if (needsCurrent() && (getCurrent() != null)) {
res.add(getCurrent().getPK());
}
}
return res;
}
public void SetCurrentByPK(Object pk) {
if (isShown())
control.SelectRowByPK(pk);
}
public void ClearSelection() {
if (isShown()) control.clearSelection(); //строка сбросится сама. благодаря сбросу события выбора
}
public void SelectAll(boolean flag) {
for (D object : dataSource.Data.values()) {
if (isObjectVisible(object))
object.Select(flag);
}
RedrawControl();
}
//ДИАЛОГИ
public boolean ShowAddObjectDialog(D object) {
return getDialog().ShowDialog(dataSource.getSingleDescription() + ": добавление", object);
}
public boolean ShowEditObjectDialog(D object) {
DBObjectDialog dialog = getDialog();
dialog.edit = true;
dialog.SetEditLimits();
String title = dataSource.getSingleDescription() + ": ";
if (isObjectEditable(object)) {
title += "редактирование";
} else {
title += "просмотр";
dialog.SetReadonly();
dialog.BlockButtons();
}
return dialog.ShowDialog(title, object);
}
public boolean ShowDeleteObjectDialog(D object) {
return UI.Warning(dataSource.getSingleDescription() + " " + object.getBDialogName() + " будет удален(а)");
}
public boolean ShowDeleteObjectsDialog(int toDeleteCount) {
return UI.Warning(dataSource.getPluralDescription() + " в количестве " + toDeleteCount + " будут удалены)");
}
public PassCode_ getDeletePassCode() {
return null;
}
public Object getCurrentPK(Object nanValue) {
return current == null ? nanValue : current.getPK();
}
public boolean canModifyCurrent(TextLog Log) {
return CheckCurrent(Log);
}
}