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 extends ControlForm { protected DataSet dataSource; //источник данных protected D current = null; //заменить все обращения к мейн модулю. protected DataMenuBar bar = null; //верхняя панель меню protected int current_row_i; //индекс текущей строки. protected boolean events_on = true; protected String colNamesAndSizes = ""; protected Vector> allFilters = new Vector<>(); Vector> columns = new Vector<>(); //информация о столбцах и их оформлении MatchesCounter counter_ui = null; //-- Object savedCurrentKey = null; Vector savedSelectedKeys = new Vector<>(); public DataSetControlForm(DataSet 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 createPKColumn() { return new ColumnInfo(dataSource.getPKName()) { @Override public Object getFieldAt(D object) { return object.getPK(); } @Override public boolean isVisible() { return isPKVisible(); } }; } protected boolean hasCheckBox() { return true; } protected ColumnInfo createCheckBoxColummn() { return new ColumnInfo("") { @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; } }; } Vector getFilters(Class f) { Vector 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_... new_filters) { Collections.addAll(allFilters, new_filters); } protected final void AddColumns(ColumnInfo... new_columns) { Collections.addAll(columns, new_columns); } public ColumnInfo getColumnInfo(int i) { return columns.get(i); } //-- void SaveColumns() { if (MainModule_.instance.getDb() != null) { try { if (needsCurrent()) { Vector 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 getHeaders() { return columns.stream().map(ColumnInfo::getName).collect(Collectors.toCollection(Vector::new)); } protected Comparator getDefaultComparator() { return null; } Vector getVisibleKeys() { Comparator comparator = getDefaultComparator(); Vector res_keys = new Vector<>(); if (comparator == null) { for (D object : dataSource.Data.values()) { if (isObjectVisible(object)) res_keys.add(object.getPK()); } } else { Vector 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 getSelectedItems() { return dataSource.Data.values().stream().filter(d -> isObjectVisible(d) && d.isSelected()).collect(Collectors.toCollection(Vector::new)); } public Vector getSelectedKeys() { return dataSource.Data.values().stream().filter(d -> isObjectVisible(d) && d.isSelected()).map(d -> d.getPK()).collect(Collectors.toCollection(Vector::new)); } //в том числе и невидимые. нужно для сохранения галок при перезакачке бд. public Vector 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 getSelectedOrCurrent() { Vector res = new Vector<>(); if (getSelectedCount() > 0) res = getSelectedItems(); else { if (needsCurrent() && (getCurrent() != null)) { res.add(getCurrent()); } } return res; } public Vector getSelectedOrCurrentKeys() { Vector 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); } }