From b75652dc438f16b7e0bee2d5266b4a35f756fe91 Mon Sep 17 00:00:00 2001 From: vito Date: Fri, 24 Nov 2023 15:37:47 +0800 Subject: [PATCH 1/3] =?UTF-8?q?REPORT-99485=20UI=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=88=86=E7=A6=BBDemo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../connect/ConnectionComboBoxPanel.java | 200 ++++--- .../connect/ConnectionTableProcedurePane.java | 548 +++++++++--------- .../connect/ItemEditableComboBoxPanel.java | 182 ------ .../tabledatapane/DBTableDataPane.java | 505 ++++------------ .../tabledatapane/DBTableDataViewModel.java | 281 +++++++++ 5 files changed, 787 insertions(+), 929 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java index 76f32d6f0c..d3b1a720d7 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java @@ -1,7 +1,9 @@ package com.fr.design.data.datapane.connect; +import com.fine.state.livedata.LiveData; +import com.fine.swing.ui.layout.Row; +import com.fr.base.BaseUtils; import com.fr.base.svg.IconUtils; -import com.fr.data.impl.AbstractDatabaseConnection; import com.fr.data.impl.Connection; import com.fr.data.impl.NameDatabaseConnection; import com.fr.design.DesignerEnvManager; @@ -9,22 +11,23 @@ import com.fr.design.editlock.ConnectionLockChangeChecker; import com.fr.design.editlock.EditLockUtils; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UILockButton; -import com.fr.file.ConnectionConfig; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.i18n.Toolkit; +import com.fr.log.FineLoggerFactory; import com.fr.report.LockItem; import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; -import com.fr.workspace.server.connection.DBConnectAuth; +import org.jetbrains.annotations.Nullable; +import javax.swing.DefaultComboBoxModel; import javax.swing.SwingUtilities; -import java.awt.Dimension; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; import java.util.List; +import java.util.Objects; +import java.util.concurrent.CancellationException; +import java.util.function.Consumer; + +import static com.fine.swing.ui.layout.Layouts.cell; /** * 选择数据连接的下拉框 @@ -32,86 +35,150 @@ import java.util.List; * @editor zhou * @since 2012-3-28下午3:02:30 */ -public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { - /** - * - */ +public class ConnectionComboBoxPanel extends Row { private static final long serialVersionUID = 1L; - private Class cls; // 所取的Connection都是cls及其子类 - private List nameList = new ArrayList(); - public ConnectionComboBoxPanel(Class cls) { - super(); + private static final String PENDING = Toolkit.i18nText("Fine-Design_Basic_Loading") + "..."; + + protected static final Object EMPTY = new Object() { + public String toString() { + return ""; + } + }; - this.cls = cls; + protected UIComboBox itemComboBox; + protected UIButton editButton; + + // 记录原来选中的Item,重新加载后需要再次选中 + private Object lastSelectedItem; + + private final LiveData> names; + private final Consumer fetchNames; + + public ConnectionComboBoxPanel( + LiveData> names, + LiveData selectedItem, + @Nullable Consumer fetchNames, + @Nullable Consumer selecteChangeConsumer + ) { + super(); + this.names = names; + this.fetchNames = fetchNames; + initComponents(); // alex:添加item change监听,当改变时改变DesignerEnvManager中的最近选中的数据连接 - this.itemComboBox.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - String selected = ConnectionComboBoxPanel.this.getSelectedItem(); - if (StringUtils.isNotBlank(selected)) { - DesignerEnvManager.getEnvManager().setRecentSelectedConnection(selected); + this.itemComboBox.addItemListener(e -> { + String selected = ConnectionComboBoxPanel.this.getSelectedItem(); + if(PENDING.equals(selected)){ + return; + } + if (StringUtils.isNotBlank(selected)) { + DesignerEnvManager.getEnvManager().setRecentSelectedConnection(selected); + } + if(!Objects.isNull(selecteChangeConsumer)){ + selecteChangeConsumer.accept(selected); + } + }); + names.observeForever(strings -> { + try { + itemComboBox.setModel(new DefaultComboBoxModel<>(strings.toArray(new String[0]))); +// // 如果加载成功 但是下拉框是可见的 下拉框高度是会固定为原始高度 不会因为填充了更多下拉项而变化 +// // 需要重新设置下拉框高度 但值一样时相关事件不会生效 所以先加再减下 +// if (itemComboBox.isPopupVisible()) { +// itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() + 1); +// itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() - 1); +// } +// // 存在两种场景之前只考虑了填充场景 有populate会填充下 把这边的填充逻辑删了 所以没有问题 +// // 如果是纯通过刷新按钮 没有populate 需要手动设置下上次选中的内容 + if (lastSelectedItem != null) { + itemComboBox.setSelectedItem(lastSelectedItem); + } + } catch (Exception e) { + if (!(e instanceof CancellationException)) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); } } }); + + + lastSelectedItem = selectedItem.getValue(); refreshItems(); } - @Override - protected UIButton initEditButton(UIButton editButton, Dimension buttonSize) { - editButton = new UILockButton( + private void initComponents() { + setSpacing(5); + add( + cell(new UIComboBox()).weight(1.0).with(uiComboBox -> { + this.itemComboBox= uiComboBox; + uiComboBox.setEnabled(true); + + }), + cell(new UIButton(BaseUtils.readIcon("/com/fr/design/images/control/refresh.png"))) + .with(btn -> btn.addActionListener(e -> refreshItems())), + cell(initEditButton()).with(uiButton -> editButton = uiButton) + ); + } + + + /** + * 给itemComboBox添加ActionListener + */ + public void addComboBoxActionListener(ActionListener l) { + itemComboBox.addActionListener(l); + } + + /* + * 刷新itemComboBox的内容 + */ + protected void refreshItems() { + lastSelectedItem = itemComboBox.getSelectedItem(); + DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); + + model.removeAllElements(); + + // 先加EMPTY,再加items + model.addElement(PENDING); + if(!Objects.isNull(fetchNames)){ + fetchNames.accept(null); + } + } + + protected UIButton initEditButton() { + UIButton editButton = new UILockButton( EditLockUtils.CONNECTION_LOCKED_ICON, IconUtils.readIcon("/com/fr/design/images/m_web/connection"), EditLockUtils.CONNECTION_LOCKED_TOOLTIPS, null ); - editButton.setPreferredSize(buttonSize); - editButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - editItems(); - } - }); +// editButton.setPreferredSize(buttonSize); + editButton.addActionListener(evt -> editItems()); ConnectionLockChangeChecker.getInstance().addEditLockChangeListener((UILockButton) editButton); return editButton; } /* - * 刷新ComboBox.items + * 得到其中的itemComboBox所选中的Item */ - protected Iterator items() { - ConnectionConfig mgr = ConnectionConfig.getInstance(); - Iterator nameIt = mgr.getConnections().keySet().iterator(); - - Collection noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections(); + public String getSelectedItem() { + Object selected = itemComboBox.getSelectedItem(); - nameList = new ArrayList<>(); - - if (noAuthConnections == null) { - return nameList.iterator(); - } - while (nameIt.hasNext()) { - String conName = nameIt.next(); - if (noAuthConnections.contains(conName)) { - continue; - } - Connection connection = mgr.getConnection(conName); - // nameList依赖items方法初始化,父类ItemEditableComboBoxPanel里异步执行item方法 - filterConnection(connection, conName, nameList); - } - - return nameList.iterator(); + return selected instanceof String ? (String)selected : null; } - protected void filterConnection(Connection connection, String conName, List nameList) { - connection.addConnection(nameList, conName, new Class[]{AbstractDatabaseConnection.class}); + /* + * 选中name项 + */ + public void setSelectedItem(String name) { + DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); + model.setSelectedItem(name); } public int getConnectionSize() { - return nameList.size(); + return names.getValue().size(); } public String getConnection(int i) { - return nameList.get(i); + return names.getValue().get(i); } /* @@ -148,9 +215,7 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { protected void setRecentConnection() { String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); if (StringUtils.isNotBlank(s)) { - // 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白 - // 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置 - if (nameList.contains(s)) { + if (names.getValue().contains(s)) { this.setSelectedItem(s); } } @@ -160,12 +225,5 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { } } - /** - * 是否无选中状态(空白item也视为无选中) - * @return - */ - protected boolean isSelectedItemEmpty() { - String selectedItem = this.getSelectedItem(); - return selectedItem == null || StringUtils.equals(selectedItem, EMPTY.toString()); - } -} + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java index 41556dae83..de5d1ed8a7 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java @@ -1,13 +1,14 @@ package com.fr.design.data.datapane.connect; +import com.fine.state.livedata.LiveData; +import com.fine.state.livedata.MutableLiveData; import com.fr.base.BaseUtils; import com.fr.base.svg.IconUtils; import com.fr.data.core.db.TableProcedure; -import com.fr.data.impl.AbstractDatabaseConnection; import com.fr.data.impl.Connection; +import com.fr.design.DesignerEnvManager; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.UIConstants; -import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icontainer.UIScrollPane; @@ -18,21 +19,24 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.general.GeneralContext; import com.fr.stable.ArrayUtils; +import com.fr.stable.StringUtils; import javax.swing.BorderFactory; -import javax.swing.DefaultComboBoxModel; import javax.swing.JPanel; import javax.swing.ToolTipManager; +import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.BorderLayout; import java.awt.Dimension; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.function.Consumer; /** * 数据集编辑面板左边的部分 @@ -41,277 +45,269 @@ import java.util.List; * @since 2012-3-28下午10:14:59 */ public class ConnectionTableProcedurePane extends BasicPane { - private static int WIDTH = 155; - private ConnectionComboBoxPanel connectionComboBox; - private UICheckBox tableCheckBox; - private UICheckBox viewCheckBox; - protected UITextField searchField; - private TableViewList tableViewList; - private java.util.List listeners = new java.util.ArrayList(); - - public ConnectionTableProcedurePane() { - init(null); - } - - /** - * 传入父容器 - * @param parent - */ - public ConnectionTableProcedurePane(SwitchableTableDataPane parent) { - init(parent); - } - - private void init(SwitchableTableDataPane parent) { - this.setLayout(new BorderLayout(4, 4)); - // 初始化数据连接下拉框 - initConnectionComboBox(parent); - // 初始化中间的面板 - JPanel centerPane = initCenterPane(); - this.add(connectionComboBox, BorderLayout.NORTH); - this.add(centerPane, BorderLayout.CENTER); - this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); - addKeyMonitor(); - } - - private JPanel initCenterPane() { - JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - // 搜索面板 - centerPane.add(createSearchPane(), BorderLayout.NORTH); - // 数据库表视图面板 - centerPane.add(createTableViewBorderPane(), BorderLayout.CENTER); - return centerPane; - } - - private void initConnectionComboBox(SwitchableTableDataPane parent) { - connectionComboBox = new ConnectionComboBoxPanel(com.fr.data.impl.Connection.class) { - - @Override - protected void filterConnection(Connection connection, String conName, List nameList) { - filter(connection, conName, nameList); - } - - @Override - protected void refreshItems() { - super.refreshItems(); - if (tableViewList != null) { - search(true); - } - } - - @Override - protected void afterRefreshItems() { - // 刷新完成后,如果未选中(在nameList初始化完成之前可能会出现),则尝试再次设置 - if (isSelectedItemEmpty()) { - setRecentConnection(); - } - // 获取数据连接之后,让父容器切换面板 - if (parent != null) { - parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); - } - DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); - model.removeElement(EMPTY); - } - - @Override - protected void refreshItemsError() { - // 获取数据连接出现错误时,也让父容器从Loading面板切换至内容面板 - if (parent != null) { - parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); - } - } - }; - connectionComboBox.addComboBoxActionListener(filter); - } - - private JPanel createTableViewBorderPane() { - tableViewList = new TableViewList(); - ToolTipManager.sharedInstance().registerComponent(tableViewList); - - tableViewList.addMouseListener(new MouseAdapter() { - public void mouseClicked(MouseEvent evt) { - if (evt.getClickCount() >= 2) { - Object obj = tableViewList.getSelectedValue(); - TableProcedure tableProcedure = null; - if (obj instanceof TableProcedure) { - tableProcedure = (TableProcedure) obj; - } else { - return; - } - for (int i = 0; i < ConnectionTableProcedurePane.this.listeners.size(); i++) { - ConnectionTableProcedurePane.this.listeners.get(i).actionPerformed(tableProcedure); - } - } - } - }); - UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); - tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); - JPanel tableViewBorderPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - tableViewBorderPane.add(tableViewListPane, BorderLayout.CENTER); - JPanel checkBoxgroupPane = createCheckBoxgroupPane(); - if (checkBoxgroupPane != null) { - tableViewBorderPane.add(createCheckBoxgroupPane(), BorderLayout.SOUTH); - } - return tableViewBorderPane; - } - - /** - * 创建搜索Panel,用于搜索表或视图 - * @return - */ - private JPanel createSearchPane() { - JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel searchPane = new JPanel(new BorderLayout(10, 0)); - searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + private static int WIDTH = 155; + private ConnectionComboBoxPanel connectionComboBox; + private UICheckBox tableCheckBox; + private UICheckBox viewCheckBox; + protected UITextField searchField; + private TableViewList tableViewList; + private List listeners = new ArrayList(); + + private ConnectionTableState state; + + public MutableLiveData selected = new MutableLiveData<>(); + public Consumer selecteChangeConsumer; + + public static class ConnectionTableState { + public LiveData> names; + public Consumer namesConsumer; + public LiveData> tableProcedures; + public Consumer tableProcedureBeanConsumer; + + public ConnectionTableState(LiveData> names, Consumer namesConsumer, LiveData> tableProcedures, Consumer tableProcedureBeanConsumer) { + this.names = names; + this.namesConsumer = namesConsumer; + this.tableProcedures = tableProcedures; + this.tableProcedureBeanConsumer = tableProcedureBeanConsumer; + } + } + + public ConnectionTableProcedurePane() { + init(); + } + + public ConnectionTableProcedurePane(ConnectionTableState state) { + this.state = state; + init(); + } + + + private void init() { + selecteChangeConsumer = selectedName -> { + selected.setValue(selectedName); + }; + this.setLayout(new BorderLayout(4, 4)); + + // 初始化中间的面板 + JPanel centerPane = initCenterPane(); + this.add(centerPane, BorderLayout.CENTER); + // 初始化数据连接下拉框 + initConnectionComboBox(); + this.add(connectionComboBox, BorderLayout.NORTH); + setBorder(new EmptyBorder( + 10, 10, 10, 10 + )); + this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); + addKeyMonitor(); + state.names.observeForever(strings -> { + search(true); + }); + } + + + protected void filter(Connection connection, String conName, List nameList) { + + } + + private JPanel initCenterPane() { + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // 搜索面板 + centerPane.add(createSearchPane(), BorderLayout.NORTH); + // 数据库表视图面板 + centerPane.add(createTableViewBorderPane(), BorderLayout.CENTER); + return centerPane; + } + + private void initConnectionComboBox() { + connectionComboBox = new ConnectionComboBoxPanel(state.names, selected,state.namesConsumer, selecteChangeConsumer); + connectionComboBox.addComboBoxActionListener(filter); + } + + + + private JPanel createTableViewBorderPane() { + tableViewList = new TableViewList(state.tableProcedures, state.tableProcedureBeanConsumer); + ToolTipManager.sharedInstance().registerComponent(tableViewList); + + tableViewList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() >= 2) { + Object obj = tableViewList.getSelectedValue(); + TableProcedure tableProcedure = null; + if (obj instanceof TableProcedure) { + tableProcedure = (TableProcedure) obj; + } else { + return; + } + for (DoubleClickSelectedNodeOnTreeListener listener : ConnectionTableProcedurePane.this.listeners) { + listener.actionPerformed(tableProcedure); + } + } + } + }); + UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); + tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + JPanel tableViewBorderPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tableViewBorderPane.add(tableViewListPane, BorderLayout.CENTER); + JPanel checkBoxgroupPane = createCheckBoxgroupPane(); + if (checkBoxgroupPane != null) { + tableViewBorderPane.add(createCheckBoxgroupPane(), BorderLayout.SOUTH); + } + return tableViewBorderPane; + } + + /** + * 创建搜索Panel,用于搜索表或视图 + * + * @return + */ + private JPanel createSearchPane() { + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + JPanel searchPane = new JPanel(new BorderLayout(10, 0)); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); // searchPane.setBackground(Color.WHITE); - searchField = new UITextField(); - searchField.setBorderPainted(false); - searchField.setPlaceholder(Toolkit.i18nText("Fine-Design_Basic_Table_Search")); - searchField.getDocument().addDocumentListener(searchListener); - searchField.addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - super.mouseEntered(e); - searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.CHECKBOX_HOVER_SELECTED)); - } - - @Override - public void mouseExited(MouseEvent e) { - super.mouseExited(e); - searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); - } - }); - // 搜索图标 - UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); - searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); - searchPane.add(searchField, BorderLayout.CENTER); - searchPane.add(searchLabel, BorderLayout.EAST); - panel.add(searchPane, BorderLayout.CENTER); - return panel; - } - - protected void filter(Connection connection, String conName, List nameList) { - connection.addConnection(nameList, conName, new Class[]{AbstractDatabaseConnection.class}); - } - - protected void addKeyMonitor() { - //do nothing - } - - protected JPanel createCheckBoxgroupPane() { - JPanel checkBoxgroupPane = FRGUIPaneFactory.createNColumnGridInnerContainer_S_Pane(2); - JPanel first = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - tableCheckBox = new UICheckBox(); - tableCheckBox.setSelected(true); - tableCheckBox.addActionListener(filter); - first.add(tableCheckBox); - - JPanel second = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - viewCheckBox = new UICheckBox(); - viewCheckBox.setSelected(true); - viewCheckBox.addActionListener(filter); - second.add(viewCheckBox); - - // 根据环境是否为中文设置不同的显示 - if (GeneralContext.isChineseEnv()) { - first.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table"), - BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING)); - second.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View"), - BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING)); - } else { - UILabel ui1 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING); - UILabel ui2 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING); - ui1.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); - ui2.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); - first.add(ui1); - second.add(ui2); - } - checkBoxgroupPane.add(first); - checkBoxgroupPane.add(second); - - return checkBoxgroupPane; - } - - /** - * 给 itemComboBox 加上 itemListener - * - * @param itemListener - */ - public void addItemListener(ItemListener itemListener) { - connectionComboBox.itemComboBox.addItemListener(itemListener); - } - - private DocumentListener searchListener = new DocumentListener() { - - @Override - public void removeUpdate(DocumentEvent e) { - search(false); - } - - @Override - public void insertUpdate(DocumentEvent e) { - search(false); - } - - @Override - public void changedUpdate(DocumentEvent e) { - search(false); - } - }; - - private ActionListener filter = new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - search(false); - } - }; - - /** - * 选项改变,需要重新刷新下拉列表里面的项 - */ - protected void search(boolean refresh) { - String selectedObj = connectionComboBox.getSelectedItem(); - - String[] types = ArrayUtils.EMPTY_STRING_ARRAY; - if (tableCheckBox != null) { - if (tableCheckBox.isSelected()) { - types = (String[]) ArrayUtils.add(types, TableProcedure.TABLE); - } - if (viewCheckBox.isSelected()) { - types = (String[]) ArrayUtils.add(types, TableProcedure.VIEW); - } - } else { - types = (String[]) ArrayUtils.add(types, TableProcedure.PROCEDURE); - } - tableViewList.populate(selectedObj, searchField.getText().trim(), refresh, types); - } - - @Override - protected String title4PopupWindow() { - return "Connection"; - } - - /** - * @param l - */ - public void addDoubleClickListener(DoubleClickSelectedNodeOnTreeListener l) { - this.listeners.add(l); - } - - public void setSelectedDatabaseConnection(com.fr.data.impl.Connection db) { - connectionComboBox.populate(db); - } - - public String getSelectedDatabaseConnnectonName() { - return connectionComboBox.getSelectedItem(); - } - - public static interface DoubleClickSelectedNodeOnTreeListener { - /** - * 处理双击事件 - * - * @param target - */ - public void actionPerformed(TableProcedure target); - } + searchField = new UITextField(); + searchField.setBorderPainted(false); + searchField.setPlaceholder(Toolkit.i18nText("Fine-Design_Basic_Table_Search")); + searchField.getDocument().addDocumentListener(searchListener); + searchField.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.CHECKBOX_HOVER_SELECTED)); + } + + @Override + public void mouseExited(MouseEvent e) { + super.mouseExited(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + } + }); + // 搜索图标 + UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); + searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + searchPane.add(searchField, BorderLayout.CENTER); + searchPane.add(searchLabel, BorderLayout.EAST); + panel.add(searchPane, BorderLayout.CENTER); + return panel; + } + + protected void addKeyMonitor() { + //do nothing + } + + protected JPanel createCheckBoxgroupPane() { + JPanel checkBoxgroupPane = FRGUIPaneFactory.createNColumnGridInnerContainer_S_Pane(2); + JPanel first = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + tableCheckBox = new UICheckBox(); + tableCheckBox.setSelected(true); + tableCheckBox.addActionListener(filter); + first.add(tableCheckBox); + + JPanel second = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + viewCheckBox = new UICheckBox(); + viewCheckBox.setSelected(true); + viewCheckBox.addActionListener(filter); + second.add(viewCheckBox); + + // 根据环境是否为中文设置不同的显示 + if (GeneralContext.isChineseEnv()) { + first.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table"), + BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING)); + second.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View"), + BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING)); + } else { + UILabel ui1 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING); + UILabel ui2 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING); + ui1.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); + ui2.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); + first.add(ui1); + second.add(ui2); + } + checkBoxgroupPane.add(first); + checkBoxgroupPane.add(second); + + return checkBoxgroupPane; + } + + /** + * 给 itemComboBox 加上 itemListener + * + * @param itemListener + */ + public void addItemListener(ItemListener itemListener) { + connectionComboBox.itemComboBox.addItemListener(itemListener); + } + + private final DocumentListener searchListener = new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + search(false); + } + + @Override + public void insertUpdate(DocumentEvent e) { + search(false); + } + + @Override + public void changedUpdate(DocumentEvent e) { + search(false); + } + }; + + private final ActionListener filter = e -> search(false); + + /** + * 选项改变,需要重新刷新下拉列表里面的项 + */ + protected void search(boolean refresh) { + String selectedObj = selected.getValue(); + if(StringUtils.isBlank(selectedObj)){ + selectedObj = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); + } + + String[] types = ArrayUtils.EMPTY_STRING_ARRAY; + if (tableCheckBox != null) { + if (tableCheckBox.isSelected()) { + types = ArrayUtils.add(types, TableProcedure.TABLE); + } + if (viewCheckBox.isSelected()) { + types = ArrayUtils.add(types, TableProcedure.VIEW); + } + } else { + types = ArrayUtils.add(types, TableProcedure.PROCEDURE); + } + tableViewList.populate(selectedObj, searchField.getText().trim(), refresh, types); + } + + @Override + protected String title4PopupWindow() { + return "Connection"; + } + + /** + * @param l + */ + public void addDoubleClickListener(DoubleClickSelectedNodeOnTreeListener l) { + this.listeners.add(l); + } + + public void setSelectedDatabaseConnection(com.fr.data.impl.Connection db) { + connectionComboBox.populate(db); + } + + public String getSelectedDatabaseConnnectonName() { + return connectionComboBox.getSelectedItem(); + } + + public static interface DoubleClickSelectedNodeOnTreeListener { + /** + * 处理双击事件 + * + * @param target + */ + public void actionPerformed(TableProcedure target); + } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java index a430a13bd1..8b13789179 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java @@ -1,183 +1 @@ -package com.fr.design.data.datapane.connect; -import com.fr.base.BaseUtils; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.gui.icombobox.UIComboBox; -import com.fr.design.i18n.Toolkit; -import com.fr.design.layout.FRGUIPaneFactory; - -import com.fr.log.FineLoggerFactory; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.util.Iterator; -import java.util.concurrent.CancellationException; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JPanel; -import javax.swing.SwingWorker; - -public abstract class ItemEditableComboBoxPanel extends JPanel { - /** - * - */ - private static final long serialVersionUID = 1L; - - private static final String PENDING = Toolkit.i18nText("Fine-Design_Basic_Loading") + "..."; - - protected static final Object EMPTY = new Object() { - public String toString() { - return ""; - } - }; - - protected UIComboBox itemComboBox; - protected UIButton editButton; - protected UIButton refreshButton; - - private SwingWorker, Void> refreshWorker; - - public ItemEditableComboBoxPanel() { - super(); - - initComponents(); - } - - protected void initComponents() { - this.setLayout(FRGUIPaneFactory.createM_BorderLayout()); - Dimension buttonSize = new Dimension(26, 20); - itemComboBox = new UIComboBox(); - itemComboBox.setEnabled(true); - this.add(itemComboBox, BorderLayout.CENTER); - refreshButton = new UIButton(BaseUtils.readIcon("/com/fr/design/images/control/refresh.png")); - JPanel jPanel = FRGUIPaneFactory.createNColumnGridInnerContainer_Pane(2, 4 ,4); - editButton = initEditButton(editButton, buttonSize); - jPanel.add(editButton); - jPanel.add(refreshButton); - this.add(jPanel, BorderLayout.EAST); - refreshButton.setPreferredSize(buttonSize); - refreshButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - refreshItems(); - } - }); - } - - protected UIButton initEditButton(UIButton editButton, Dimension buttonSize) { - editButton = new UIButton(BaseUtils.readIcon("/com/fr/design/images/control/control-center2.png")); - editButton.setPreferredSize(buttonSize); - editButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - editItems(); - } - }); - return editButton; - } - - - /** - * 给itemComboBox添加ActionListener - */ - public void addComboBoxActionListener(ActionListener l) { - itemComboBox.addActionListener(l); - } - - /* - * 刷新itemComboBox的内容 - */ - protected void refreshItems() { - - if (refreshWorker != null && !refreshWorker.isDone()) { - refreshWorker.cancel(true); - } - - // 记录原来选中的Item,重新加载后需要再次选中 - Object lastSelectedItem = itemComboBox.getSelectedItem(); - - DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); - model.removeAllElements(); - - // 先加EMPTY,再加items - model.addElement(EMPTY); - model.addElement(PENDING); - - // 存在两种场景之前只考虑了填充场景 有populate会填充下 把这边的填充逻辑删了 所以没有问题 - // 如果是纯通过刷新按钮 没有populate 需要手动设置下上次选中的内容 - if (lastSelectedItem != null) { - model.setSelectedItem(lastSelectedItem); - } - - refreshWorker = new SwingWorker, Void>() { - @Override - protected Iterator doInBackground() throws Exception { - return items(); - } - - @Override - protected void done() { - try { - Iterator itemIt = get(); - model.removeElement(PENDING); - while(itemIt.hasNext()) { - model.addElement(itemIt.next()); - } - // 如果加载成功 但是下拉框是可见的 下拉框高度是会固定为原始高度 不会因为填充了更多下拉项而变化 - // 需要重新设置下拉框高度 但值一样时相关事件不会生效 所以先加再减下 - if (itemComboBox.isPopupVisible()) { - itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() + 1); - itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() - 1); - } - afterRefreshItems(); - } catch (Exception e) { - if (!(e instanceof CancellationException)) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - refreshItemsError(); - } - - } - }; - refreshWorker.execute(); - } - - /* - * 得到其中的itemComboBox所选中的Item - */ - public String getSelectedItem() { - Object selected = itemComboBox.getSelectedItem(); - - return selected instanceof String ? (String)selected : null; - } - - /* - * 选中name项 - */ - public void setSelectedItem(String name) { - DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); - model.setSelectedItem(name); - } - - /* - * 刷新ComboBox.items - */ - protected abstract java.util.Iterator items(); - - /** - * 刷新ComboBox.items之后 - */ - protected void afterRefreshItems() { - // 空实现,供子类重写 - } - - /** - * 刷新ComboBox.items时出现异常 - */ - protected void refreshItemsError() { - // 空实现,供子类重写 - } - - /* - * 弹出对话框编辑Items - */ - protected abstract void editItems(); -} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java index d0ffd7f22c..db0f03e72b 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java @@ -1,35 +1,24 @@ package com.fr.design.data.tabledata.tabledatapane; -import com.fr.base.Parameter; -import com.fr.base.ParameterHelper; -import com.fr.data.core.db.TableProcedure; +import com.fine.state.livedata.DocumentLiveData; import com.fr.data.impl.Connection; import com.fr.data.impl.DBTableData; import com.fr.data.impl.JDBCDatabaseConnection; import com.fr.data.impl.JNDIDatabaseConnection; -import com.fr.data.impl.NameDatabaseConnection; import com.fr.design.ExtraDesignClassManager; import com.fr.design.actions.UpdateAction; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.UIConstants; -import com.fr.design.data.StrategyConfigAttrUtils; -import com.fr.design.data.datapane.ESDStrategyConfigPane; import com.fr.design.data.datapane.connect.ConnectionTableProcedurePane; import com.fr.design.data.datapane.preview.PreviewTablePane; import com.fr.design.data.datapane.preview.sql.PreviewPerformedSqlPane; import com.fr.design.data.datapane.sqlpane.SQLEditPane; -import com.fr.design.data.tabledata.strategy.StrategyConfigHandler; -import com.fr.design.data.tabledata.tabledatapane.db.StrategyConfigFrom; import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; -import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.fun.DBTableDataMenuHandler; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.gui.icheckbox.UICheckBox; -import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itableeditorpane.ParameterTableModel; import com.fr.design.gui.itableeditorpane.UITableEditAction; @@ -42,25 +31,15 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.menu.SeparatorDef; import com.fr.design.menu.ToolBarDef; -import com.fr.design.utils.ParameterUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.esd.core.strategy.config.StrategyConfig; -import com.fr.esd.core.strategy.config.StrategyConfigHelper; -import com.fr.esd.core.strategy.config.service.StrategyConfigService; -import com.fr.esd.data.db.DBTableDataSavedHook; -import com.fr.esd.event.DSMapping; -import com.fr.esd.event.DsNameTarget; -import com.fr.esd.event.StrategyEventsNotifier; -import com.fr.esd.query.StrategicTableData; import com.fr.general.ComparatorUtils; import com.fr.general.IOUtils; -import com.fr.general.sql.SqlUtils; import com.fr.log.FineLoggerFactory; import com.fr.script.Calculator; import com.fr.stable.ArrayUtils; import com.fr.stable.ParameterProvider; import com.fr.stable.StringUtils; -import com.fr.workspace.WorkContext; import javax.swing.BorderFactory; import javax.swing.Box; @@ -69,20 +48,16 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JToolBar; -import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import java.awt.BorderLayout; import java.awt.CardLayout; -import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import java.util.ArrayList; import java.util.List; /** @@ -99,27 +74,22 @@ public class DBTableDataPane extends AbstractTableDataPane implemen private UITableEditorPane editorPane; private DBTableDataMenuHandler dbTableDataMenuHandler; private SQLEditPane sqlTextPane; - private String pageQuery; - private DBTableData dbTableData; - //ESD - private UILabel esdSettingsLabel; - private UIComboBox esdConfigOption; - private UICheckBox esdEnabled; - private UIButton esdSettingsBtn; - private UILabel barErrorTips; - //配置 - private StrategyConfig strategyConfig; - - private StrategyConfigHandler configHandler; private CardLayout card; - /** 数据库查询面板真正的内容面板 */ + /** + * 数据库查询面板真正的内容面板 + */ private JPanel contentPane; - /** 加载中面板 */ + /** + * 加载中面板 + */ private JPanel loadingPane; + private DBTableDataViewModel viewModel; + public DBTableDataPane() { + viewModel = new DBTableDataViewModel(); initCards(); initContentPane(); } @@ -144,7 +114,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen add(LOADING_PANE_NAME, loadingPane); add(CONTENT_PANE_NAME, contentPane); - switchTo(LOADING_PANE_NAME); + switchTo(CONTENT_PANE_NAME); } private void init() { @@ -162,7 +132,13 @@ public class DBTableDataPane extends AbstractTableDataPane implemen editorPane = new UITableEditorPane<>(model); - this.connectionTableProcedurePane = new ConnectionTableProcedurePane(this) { + this.connectionTableProcedurePane = new ConnectionTableProcedurePane( + new ConnectionTableProcedurePane.ConnectionTableState( + viewModel.getConnectionList(), + unused -> viewModel.fetchConnectionNameAction(), + viewModel.getTableProcedures(), + bean -> viewModel.fetchTableProceduresAction(bean) + )) { @Override protected void filter(Connection connection, String conName, List nameList) { connection.addConnection(nameList, conName, new Class[]{ @@ -195,35 +171,31 @@ public class DBTableDataPane extends AbstractTableDataPane implemen }); } }; - this.connectionTableProcedurePane.addDoubleClickListener(new ConnectionTableProcedurePane.DoubleClickSelectedNodeOnTreeListener() { - @Override - public void actionPerformed(TableProcedure target) { - Document document = DBTableDataPane.this.sqlTextPane.getDocument(); - try { - document.insertString(DBTableDataPane.this.sqlTextPane.getCaretPosition(), target.toString(), null); - } catch (BadLocationException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - - - DBTableDataPane.this.sqlTextPane.requestFocus(); + this.connectionTableProcedurePane.addDoubleClickListener(target -> { + Document document = DBTableDataPane.this.sqlTextPane.getDocument(); + try { + document.insertString(DBTableDataPane.this.sqlTextPane.getCaretPosition(), target.toString(), null); + } catch (BadLocationException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); } + DBTableDataPane.this.sqlTextPane.requestFocus(); }); this.sqlTextPane.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { - barErrorTips.setVisible(false); } @Override public void focusLost(FocusEvent e) { if (DBTableDataPane.this.isPreviewOrRefreshButton(e)) { - DBTableDataPane.this.checkParameter(); + viewModel.refreshParameters(); } } }); + DocumentLiveData.fromDocumentEventsOf(sqlTextPane.getDocument()) + .observeForever(documentEvent -> viewModel.updateQuery(sqlTextPane.getText())); } private void initMainSplitPane() { @@ -293,16 +265,6 @@ public class DBTableDataPane extends AbstractTableDataPane implemen return Toolkit.i18nText("Fine-Design_Basic_DS-Database_Query"); } - private void refreshParameters() { - String[] paramTexts = new String[2]; - paramTexts[0] = SqlUtils.tryPureSqlText(this.sqlTextPane.getText()); - paramTexts[1] = SqlUtils.tryPureSqlText(this.pageQuery); - List existParameterList = this.editorPane.update(); - Parameter[] ps = (existParameterList == null) ? new Parameter[0] : existParameterList.toArray(new Parameter[0]); - - this.editorPane.populate(ParameterUtils.analyzeAndUnionParameters(paramTexts, ps)); - } - private JToolBar createToolBar() { ToolBarDef toolBarDef = new ToolBarDef(); toolBarDef.addShortCut(new PreviewAction()); @@ -319,248 +281,105 @@ public class DBTableDataPane extends AbstractTableDataPane implemen toolBarDef.updateToolBar(editToolBar); //esd相关组件初始化 - createToolbarEsdComponents(editToolBar); +// createToolbarEsdComponents(editToolBar); return editToolBar; } - private void createToolbarEsdComponents(final UIToolbar editToolBar) { - this.esdSettingsLabel = new UILabel(Toolkit.i18nText("Fine-Design_ESD_Cache_Settings")); - this.esdConfigOption = new UIComboBox(StrategyConfigFrom.values()); - this.esdEnabled = new UICheckBox(Toolkit.i18nText("Fine-Design_ESD_Enable_Cache")); - this.barErrorTips = new UILabel(); - this.barErrorTips.setForeground(Color.RED); - this.barErrorTips.setVisible(false); - - esdSettingsBtn = new UIButton(Toolkit.i18nText("Fine-Design_ESD_Strategy_Config")); - esdSettingsBtn.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - final boolean global = globalOptionSelected(); - - final ESDStrategyConfigPane strategyConfigPane = new ESDStrategyConfigPane(global); - - StrategyConfig populateStrategyConfig; - if (global) { - populateStrategyConfig = StrategyConfigService.getGlobalConfig(); - } else { - populateStrategyConfig = strategyConfig; - } - - //显示对应的配置 - strategyConfigPane.populateBean(populateStrategyConfig); - - BasicDialog dlg = strategyConfigPane.showMediumWindow(SwingUtilities.getWindowAncestor(DBTableDataPane.this), new DialogActionAdapter() { - @Override - public void doOk() { - super.doOk(); - if (!global) { - //点击策略配置面板的确定,重新设置策略配置 - strategyConfig = strategyConfigPane.updateBean(); - // TODO: 2021/3/12 这个直接使用不太好 - } - } - }); - //dlg.setAlwaysOnTop(true); - dlg.setVisible(true); - } - }); - - this.esdConfigOption.setSelectedIndex(StrategyConfigFrom.GLOBAL.getIndex()); - this.esdConfigOption.addActionListener(e -> setEsdEnabled()); - - - //工具栏加上esd相关组件 - editToolBar.add(this.esdSettingsLabel); - editToolBar.add(this.esdConfigOption); - editToolBar.add(this.esdEnabled); - editToolBar.add(this.esdSettingsBtn); - editToolBar.add(this.barErrorTips); - } - - private boolean globalOptionSelected() { - return esdConfigOption.getSelectedIndex() == StrategyConfigFrom.GLOBAL.getIndex(); - } - - private void setEsdEnableStatus(boolean selected, boolean enabled) { - this.esdEnabled.setSelected(selected); - this.esdEnabled.setEnabled(enabled); - } - - private void setEsdEnabled() { - boolean useIndividualConfig = !this.globalOptionSelected(); - if (useIndividualConfig) { - if (this.strategyConfig == null) { - //新建的数据集,选择单独时,可用但是不勾选 - setEsdEnableStatus(false, true); - } else { - setEsdEnableStatus(!this.strategyConfig.isUseGlobal() && this.strategyConfig.enabled(), true); - } - } else { - //判断是不是模版数据集 - switch (this.dbTableData.getScope()) { - case TEMPLATE: - String tplPath = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getEditingFILE().getPath(); - setEsdEnableStatus(StrategyConfigService.isTemplateEnabled(tplPath), false); - break; - case SERVER: - //不会走到这里 - default: - break; - } - } - } public StrategyConfig updateStrategyConfig() { - return this.strategyConfig; - } - - private void checkParameter() { - String[] paramTexts = new String[2]; - paramTexts[0] = this.sqlTextPane.getText(); - paramTexts[1] = this.pageQuery; - Parameter[] parameters = ParameterHelper.analyze4Parameters(paramTexts, false); - - if (parameters.length < 1 && this.editorPane.update().size() < 1) { - return; - } - boolean isIn = true; - List list = this.editorPane.update(); - List name = new ArrayList<>(); - for (ParameterProvider parameter : list) { - name.add(parameter.getName()); - } - for (Parameter parameter : parameters) { - if (!name.contains(parameter.getName())) { - isIn = false; - break; - } - } - if (list.size() == parameters.length && isIn) { - return; - } - - refreshParameters(); + return null; } @Override - public void populateBean(DBTableData dbTableData) { - this.dbTableData = dbTableData; - if (this.dbTableDataMenuHandler != null) { - this.dbTableDataMenuHandler.populate(dbTableData); - } - - - Calculator c = Calculator.createCalculator(); - - ParameterProvider[] parameters = dbTableData.getParameters(c); - this.editorPane.populate(parameters); + public void populateBean(DBTableData tableData) { + this.viewModel.updateTableData(tableData); + this.viewModel.getDbTableData().observeForever(dbTableData -> { + if (this.dbTableDataMenuHandler != null) { + this.dbTableDataMenuHandler.populate(dbTableData); + } + editorPane.populate(dbTableData.getParameters(Calculator.createCalculator())); + connectionTableProcedurePane.setSelectedDatabaseConnection(dbTableData.getDatabase()); + connectionTableProcedurePane.addItemListener(event -> { + String dbName = connectionTableProcedurePane.getSelectedDatabaseConnnectonName(); +// if (StringUtils.isBlank(dbName) || StringUtils.isBlank(sqlTextPane.getText())) { +// try { +// throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Connect_SQL_Cannot_Null") + "."); +// } catch (Exception e) { +// FineLoggerFactory.getLogger().error(e.getMessage(), e); +// } +// } + viewModel.updateDBName(dbName); + }); + }); - Connection db = dbTableData.getDatabase(); - String query = dbTableData.getQuery(); - this.pageQuery = dbTableData.getPageQuerySql(); - this.connectionTableProcedurePane.setSelectedDatabaseConnection(db); - this.sqlTextPane.setText(query); - this.sqlTextPane.requestFocus(); + this.sqlTextPane.setText(tableData.getQuery()); this.sqlTextPane.moveCaretPosition(this.sqlTextPane.getCaretPosition()); + this.sqlTextPane.requestFocus(); - switch (dbTableData.getScope()) { - - case TEMPLATE: - this.configHandler = new TemplateStrategyConfigHandler(dbTableData); - break; - case SERVER: - //服务器数据集 - default: - //新建服务器数据集 - this.configHandler = new ServerStrategyConfigHandler(dbTableData); - break; - } //设置esd相关组件显示状态 - populateESDComponents(); +// populateESDComponents(); } - private void populateESDComponents() { - //查找映射的配置 - this.strategyConfig = configHandler.find(); - - boolean shouldEnable = false; - StrategyConfigFrom from = StrategyConfigFrom.GLOBAL; - - if (this.strategyConfig != null) { - if (this.strategyConfig.enabled()) { - shouldEnable = true; - } - if (!this.strategyConfig.isUseGlobal()) { - from = StrategyConfigFrom.INDIVIDUAL; - } - } - - //服务器数据集不允许设置来源,只能单独配置 - if (dbTableData.getScope() != StrategicTableData.Scope.TEMPLATE) { - from = StrategyConfigFrom.INDIVIDUAL; - this.esdConfigOption.setEnabled(false); - } - this.esdEnabled.setSelected(shouldEnable); - this.esdConfigOption.setSelectedIndex(from.getIndex()); - } +// private void populateESDComponents() { +// //查找映射的配置 +// this.strategyConfig = configHandler.find(); +// +// boolean shouldEnable = false; +// StrategyConfigFrom from = StrategyConfigFrom.GLOBAL; +// +// if (this.strategyConfig != null) { +// if (this.strategyConfig.enabled()) { +// shouldEnable = true; +// } +// if (!this.strategyConfig.isUseGlobal()) { +// from = StrategyConfigFrom.INDIVIDUAL; +// } +// } +// +// //服务器数据集不允许设置来源,只能单独配置 +// if (dbTableData.getScope() != StrategicTableData.Scope.TEMPLATE) { +// from = StrategyConfigFrom.INDIVIDUAL; +// this.esdConfigOption.setEnabled(false); +// } +// this.esdEnabled.setSelected(shouldEnable); +// this.esdConfigOption.setSelectedIndex(from.getIndex()); +// } @Override public DBTableData updateBean() { updateDBTableData(); - internalUpdateStrategyConfig(); +// internalUpdateStrategyConfig(); - return this.dbTableData; + return viewModel.getDbTableData().getValue(); } - private void internalUpdateStrategyConfig() { - //这边只修改enable和useGlobal - boolean global = globalOptionSelected(); - boolean enable = this.esdEnabled.isSelected(); - - - //未开启缓存的,如果选择了单独配置,需要创建配置 - if (this.strategyConfig == null && !global) { - this.strategyConfig = StrategyConfig.createDefault(); - } - - //设置配置来源和开启状态 - if (this.strategyConfig != null) { - this.strategyConfig.setEnable(enable); - this.strategyConfig.setUseGlobal(global); - } - - //保存 - this.configHandler.save(this.dbTableData, this.strategyConfig); - } +// private void internalUpdateStrategyConfig() { +// //这边只修改enable和useGlobal +// boolean global = globalOptionSelected(); +// boolean enable = this.esdEnabled.isSelected(); +// +// +// //未开启缓存的,如果选择了单独配置,需要创建配置 +// if (this.strategyConfig == null && !global) { +// this.strategyConfig = StrategyConfig.createDefault(); +// } +// +// //设置配置来源和开启状态 +// if (this.strategyConfig != null) { +// this.strategyConfig.setEnable(enable); +// this.strategyConfig.setUseGlobal(global); +// } +// +// //保存 +// this.configHandler.save(this.dbTableData, this.strategyConfig); +// } private void updateDBTableData() { - String dbName = this.connectionTableProcedurePane.getSelectedDatabaseConnnectonName(); - if (StringUtils.isBlank(dbName) || StringUtils.isBlank(this.sqlTextPane.getText())) { - try { - throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Connect_SQL_Cannot_Null") + "."); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - } - - - // 保存前 刷新下参数列表 保证获取到最新的参数 - refreshParameters(); - - List parameterList = this.editorPane.update(); - ParameterProvider[] parameters = parameterList.toArray(new ParameterProvider[0]); - - dbTableData.setDatabase(new NameDatabaseConnection(dbName)); - - dbTableData.setParameters(parameters); - dbTableData.setQuery(this.sqlTextPane.getText().trim()); - - dbTableData.setPageQuerySql(this.pageQuery); + viewModel.refreshParameters(); if (this.dbTableDataMenuHandler != null) { this.dbTableDataMenuHandler.update(); } @@ -575,7 +394,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent e) { - DBTableDataPane.this.refreshParameters(); + viewModel.refreshParameters(); } @@ -594,7 +413,6 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent evt) { - DBTableDataPane.this.checkParameter(); PreviewTablePane.previewTableData(DBTableDataPane.this.updateBean()); } } @@ -608,7 +426,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent e) { - checkParameter(); + viewModel.refreshParameters(); PreviewPerformedSqlPane.previewPerformedSql(DBTableDataPane.this.updateBean()); } } @@ -623,13 +441,13 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent e) { final QueryPane pane = new QueryPane(Toolkit.i18nText("Fine-Design_Basic_Layer_Page_Report_Define_Page_Query_SQL")); - pane.populate(pageQuery); + pane.populate(viewModel.getDbTableData().getValue().getPageQuerySql()); BasicDialog dialog = pane.showWindow(DesignerContext.getDesignerFrame()); dialog.addDialogActionListener(new DialogActionAdapter() { @Override public void doOk() { - pageQuery = pane.update(); - checkParameter(); + viewModel.updatePageQuery(pane.update()); + viewModel.refreshParameters(); } }); dialog.setVisible(true); @@ -673,117 +491,4 @@ public class DBTableDataPane extends AbstractTableDataPane implemen } } - /** - * 服务器数据集配置处理器 - */ - private static class ServerStrategyConfigHandler extends StrategyConfigHandler { - private final String origName; - - private final String origConnection; - - private final String origQuery; - - public ServerStrategyConfigHandler(DBTableData tableData) { - super(tableData); - this.origName = tableData.getDsName(); - this.origConnection = tableData.getDatabase().toString(); - this.origQuery = tableData.getQuery(); - } - - @Override - public StrategyConfig find() { - StrategyConfig strategyConfig = null; - if (getTableData() != null) { - strategyConfig = getTableData().getStrategyConfig(); - if (strategyConfig == null) { - //共享数据集 - if (getTableData().isShare()) { - strategyConfig = StrategyConfigHelper.createStrategyConfig(true, false, true); - } - } - } - - return strategyConfig; - } - - @Override - public void save(DBTableData saved, StrategyConfig strategyConfig) { - String conn = saved.getDatabase().toString(); - String query = saved.getQuery(); - - - //检查数据链接和sql是否修改,如果修改需要触发缓存监听事件 - if (!conn.equals(origConnection) || !query.equals(origQuery)) { - if (StringUtils.isNotEmpty(origName)) { - //新建数据集的origName为null,不用触发 - StrategyEventsNotifier.modifyDataSet(DSMapping.ofServerDS(new DsNameTarget(origName))); - } - } - - - //配置变动事件 - try { - final StrategyConfig orig = getTableData().getStrategyConfig(); - saved.setStrategyConfig(strategyConfig.clone()); - StrategyEventsNotifier.compareAndFireConfigEvents(orig, strategyConfig, DSMapping.ofServerDS(new DsNameTarget(saved.getDsName()))); - } catch (CloneNotSupportedException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - } - } - - - /** - * 模版数据集配置处理器 - */ - private static class TemplateStrategyConfigHandler extends StrategyConfigHandler { - public TemplateStrategyConfigHandler(DBTableData tableData) { - super(tableData); - } - - @Override - public StrategyConfig find() { - StrategyConfig strategyConfig = null; - String tplPath = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getEditingFILE().getPath(); - if (getTableData() != null && StringUtils.isNotEmpty(tplPath)) { - //设置保存数据集的事件检查钩子 - //新建模版此时不存在,不需要注册钩子 - if (getTableData().getXmlSavedHook() == null && WorkContext.getWorkResource().exist(tplPath)) { - getTableData().setXmlSavedHook(new DBTableDataSavedHook(tplPath, getTableData())); - } - - //获取当前的缓存配置,没有就创建一份 - String dsName = getTableData().getDsName(); - - //这里为了之前兼容插件创建的配置,缓存配置不在DBTableData,而是从模版attr读取 - strategyConfig = StrategyConfigAttrUtils.getStrategyConfig(dsName); - - - if (useGlobal(getTableData(), strategyConfig)) { - //使用全局配置 - strategyConfig = StrategyConfigHelper.createStrategyConfig(true); - } else if (strategyConfig == null && getTableData().isShare()) { - //没有配置时,使用共享数据集兼容配置 - strategyConfig = StrategyConfigHelper.createStrategyConfig(true, false, true); - } - } - - return strategyConfig; - } - - private boolean useGlobal(DBTableData dbTableData, StrategyConfig strategyConfig) { - //非共享且配置为空或者指定使用全局配置时,检查是否全局开启 - if (strategyConfig == null) { - return !dbTableData.isShare(); - } else { - return strategyConfig.isUseGlobal(); - } - } - - @Override - public void save(DBTableData saved, StrategyConfig config) { - - //DBTableDataSavedHook处理了 - } - } } diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java new file mode 100644 index 0000000000..6260e4960b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java @@ -0,0 +1,281 @@ +package com.fr.design.data.tabledata.tabledatapane; + +import com.fine.state.livedata.LiveData; +import com.fine.state.livedata.MutableLiveData; +import com.fr.base.Parameter; +import com.fr.base.ParameterHelper; +import com.fr.base.TableData; +import com.fr.data.core.DataCoreUtils; +import com.fr.data.core.db.TableProcedure; +import com.fr.data.core.db.dialect.base.key.check.DataBaseDetail; +import com.fr.data.core.db.dialect.base.key.check.DataBaseType; +import com.fr.data.impl.AbstractDatabaseConnection; +import com.fr.data.impl.Connection; +import com.fr.data.impl.DBTableData; +import com.fr.data.impl.NameDatabaseConnection; +import com.fr.data.operator.DataOperator; +import com.fr.design.DesignerEnvManager; +import com.fr.design.gui.ilist.TableViewList; +import com.fr.design.utils.ParameterUtils; +import com.fr.file.ConnectionConfig; +import com.fr.general.ComparatorUtils; +import com.fr.general.sql.SqlUtils; +import com.fr.stable.ArrayUtils; +import com.fr.stable.ParameterProvider; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.connection.DBConnectAuth; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static com.fr.data.core.db.TableProcedure.ERROR_TABLE_PROCEDURE; + +/** + * 数据集界面视图模型 + * + * @author vito + * @since 11.0 + * Created on 2023/11/7 + */ +public class DBTableDataViewModel { + + private MutableLiveData dbTableData = new MutableLiveData<>(); + private MutableLiveData> connectionList = new MutableLiveData<>(Collections.emptyList()); + private MutableLiveData> tableProcedures = new MutableLiveData<>(Collections.emptyList()); + + public DBTableDataViewModel() { + } + + public LiveData getDbTableData() { + return dbTableData; + } + + public LiveData> getConnectionList() { + return connectionList; + } + + public LiveData> getTableProcedures() { + return tableProcedures; + } + + /* ---------action--------- */ + public void updateTableData(TableData tableData) { + if (!(tableData instanceof DBTableData)) { + return; + } + dbTableData.postValue((DBTableData) tableData); + } + + + public void fetchConnectionNameAction() { + new Thread(() -> { + + ConnectionConfig mgr = ConnectionConfig.getInstance(); + Set connectionName = mgr.getConnections().keySet(); + + Collection noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections(); + + ArrayList nameList = new ArrayList<>(); + + if (noAuthConnections == null) { + connectionList.postValue(Collections.emptyList()); + return; + } + for (String conName : connectionName) { + if (noAuthConnections.contains(conName)) { + continue; + } + Connection connection = mgr.getConnection(conName); + connection.addConnection(nameList, conName, new Class[]{AbstractDatabaseConnection.class}); + } + connectionList.postValue(nameList); + }).start(); + } + + public void fetchTableProceduresAction(TableViewList.TableProcedureBean tableProcedureBean) { + new Thread(() -> { + List list; + try { + list = fetchTableProcedures(tableProcedureBean); + } catch (Exception e) { + list = new ArrayList<>(); + list.add(ERROR_TABLE_PROCEDURE); + } + tableProcedures.postValue(list); + }).start(); + } + + /** + * august:databaseName是数据库名字,searchFilter是输入的过滤条件,typesFilter是视图、表、 + * 存储过程中的一者或者几者 + * + * @param bean 数据 + */ + private List fetchTableProcedures(TableViewList.TableProcedureBean bean) throws Exception { + if (bean.refresh) { + clearCache(ConnectionConfig.getInstance().getConnection(bean.databaseName)); + } + Connection datasource = ConnectionConfig.getInstance().getConnection(bean.databaseName); + if (datasource == null) { + return Collections.emptyList(); + } + String[] schemas = DataCoreUtils.getDatabaseSchema(datasource); + + String searchFilter = bean.searchFilter.toLowerCase(); + boolean isOracleSystemSpace = DesignerEnvManager.getEnvManager().isOracleSystemSpace(); + // oracle不勾选显示所有表,则只显示用户下的(包括存储过程和table表) + DataBaseDetail detail = DataOperator.getInstance().getDataBaseDetail(datasource, isOracleSystemSpace); + if (ArrayUtils.isNotEmpty(detail.getSchemas())) { + schemas = detail.getSchemas(); + } + if (bean.typesFilter.length == 1 && ComparatorUtils.equals(bean.typesFilter[0], TableProcedure.PROCEDURE)) { + return processStoreProcedure(schemas, datasource, DataBaseType.ORACLE.equals(detail.getType()), searchFilter); + } else { + return processTableAndView(schemas, datasource, searchFilter, DataBaseType.ORACLE.equals(detail.getType()), bean.typesFilter); + } + } + + private void clearCache(Connection datasource) { + String[] schemas = DataCoreUtils.getDatabaseSchema(datasource); + schemas = (schemas == null || schemas.length == 0) ? new String[]{null} : schemas; + for (String schema : schemas) { + doClearCache(datasource, schema); + } + doClearCache(datasource, null); + } + + private void doClearCache(Connection datasource, String schema) { + DataCoreUtils.refreshTables(datasource, TableProcedure.TABLE, schema); + DataCoreUtils.refreshTables(datasource, TableProcedure.VIEW, schema); + DataCoreUtils.refreshTables(datasource, TableProcedure.PROCEDURE, schema); + } + + private List processStoreProcedure(String[] schemas, Connection datasource, boolean isOracle, String searchFilter) throws Exception { + List tableProcedures = new ArrayList<>(); + boolean isBlank = StringUtils.isBlank(searchFilter); + boolean isOracleSysSpace = DesignerEnvManager.getEnvManager().isOracleSystemSpace(); + List sqlTablees = DataCoreUtils.getProcedures(datasource, schemas, isOracle, isOracleSysSpace); + for (TableProcedure[] sqlTables : sqlTablees) { + if (sqlTables == null) { + continue; + } + for (TableProcedure sqlTable : sqlTables) { + String name = sqlTable.toString().toLowerCase(); + if (isBlank || name.contains(searchFilter)) { + tableProcedures.add(sqlTable); + } + } + } + return tableProcedures; + } + + private List processTableAndView(String[] schemas, Connection datasource, String searchFilter, boolean isOracle, String... typesFilter) + throws Exception { + List tableProcedures = new ArrayList<>(); + boolean isBlank = StringUtils.isBlank(searchFilter); + boolean isOracleSystemSpace = DesignerEnvManager.getEnvManager().isOracleSystemSpace(); + if (!isOracle) { + String schema = null; + for (String type : typesFilter) { + //非oracle数据库,默认都是显示所有表的,参数为true + TableProcedure[] sqlTables = DataCoreUtils.getTables(datasource, type, schema, true); + if (Objects.isNull(sqlTables)) { + return tableProcedures; + } + for (TableProcedure sqlTable : sqlTables) { + if (isBlank || sqlTable.getName().toLowerCase().contains(searchFilter)) { + tableProcedures.add(sqlTable); + } + } + } + } else { + for (String type : typesFilter) { + for (String schema : schemas) { + TableProcedure[] sqlTables = DataCoreUtils.getTables(datasource, type, schema, isOracleSystemSpace); + if (Objects.isNull(sqlTables)) { + return tableProcedures; + } + // oracle的表名加上模式 + for (TableProcedure ta : sqlTables) { + String name = ta.getSchema() + '.' + ta.getName(); + if (isBlank || name.toLowerCase().contains(searchFilter)) { + tableProcedures.add(ta); + } + } + } + } + } + return tableProcedures; + } + + public void updatePageQuery(String pageQuery) { + DBTableData tableData = dbTableData.getValue(); + if (ComparatorUtils.equals(pageQuery, tableData.getPageQuerySql())) { + return; + } + tableData.setPageQuerySql(pageQuery); + dbTableData.postValue(tableData); + } + + public void updateQuery(String query) { + DBTableData tableData = dbTableData.getValue(); + if (ComparatorUtils.equals(query, tableData.getQuery())) { + return; + } + tableData.setQuery(query); + dbTableData.postValue(tableData); + } + + public void refreshParameters() { + DBTableData tableData = dbTableData.getValue(); + if (needRefreshParameter(tableData)) { + tableData.setParameters(calParameter(tableData)); + } + dbTableData.postValue(tableData); + } + + private boolean needRefreshParameter(DBTableData tableData) { + String[] paramTexts = new String[2]; + paramTexts[0] = tableData.getQuery(); + paramTexts[1] = tableData.getPageQuerySql(); + Parameter[] parameters = ParameterHelper.analyze4Parameters(paramTexts, false); + + if (parameters.length < 1 && tableData.getParameters().length < 1) { + return false; + } + boolean isIn = true; + ParameterProvider[] list = tableData.getParameters(); + List name = new ArrayList<>(); + for (ParameterProvider parameter : list) { + name.add(parameter.getName()); + } + for (Parameter parameter : parameters) { + if (!name.contains(parameter.getName())) { + isIn = false; + break; + } + } + return list.length != parameters.length || !isIn; + } + + private Parameter[] calParameter(DBTableData tableData) { + + String[] paramTexts = new String[2]; + paramTexts[0] = SqlUtils.tryPureSqlText(tableData.getQuery()); + paramTexts[1] = SqlUtils.tryPureSqlText(tableData.getPageQuerySql()); + Parameter[] oldParameters = Arrays.asList(tableData.getParameters()).toArray(new Parameter[0]); + return ParameterUtils.analyzeAndUnionParameters(paramTexts, oldParameters); + } + + public void updateDBName(String dbName) { + DBTableData tableData = dbTableData.getValue(); + tableData.setDatabase(new NameDatabaseConnection(dbName)); + dbTableData.postValue(tableData); + } +} From a64aa24b528786375fbaa25fa478637b03668753 Mon Sep 17 00:00:00 2001 From: vito Date: Tue, 28 Nov 2023 12:03:01 +0800 Subject: [PATCH 2/3] =?UTF-8?q?REPORT-99485=20UI=20demo=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E6=95=85=E4=BA=8B=E4=B9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fine/theme/icon/IconResource.java | 4 +- .../com/fine/theme/icon/UrlIconResource.java | 8 +- .../fine/theme/light/ui/laf/FineDarkLaf.java | 37 ++++++++ .../fine/theme/light/ui/laf/FineLightLaf.java | 19 ++++- .../com/fr/design/gui/ibutton/UIHead.java | 2 +- .../fr/design/gui/ibutton/UIHeadGroup.java | 2 +- .../gui/storybook/ButtonStoryBoard.java | 36 ++++++++ .../fr/design/gui/storybook/StoryBoard.java | 30 +++++++ .../gui/storybook/StoryBookComponent.java | 18 ++++ .../fr/design/gui/storybook/Storybook.java | 85 +++++++++++++++++++ .../gui/storybook/ToggleButtonStoryBoard.java | 31 +++++++ .../gui/storybook/UIHeadGroupStoryBoard.java | 65 ++++++++++++++ 12 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java create mode 100644 designer-base/src/test/java/com/fr/design/gui/storybook/ButtonStoryBoard.java create mode 100644 designer-base/src/test/java/com/fr/design/gui/storybook/StoryBoard.java create mode 100644 designer-base/src/test/java/com/fr/design/gui/storybook/StoryBookComponent.java create mode 100644 designer-base/src/test/java/com/fr/design/gui/storybook/Storybook.java create mode 100644 designer-base/src/test/java/com/fr/design/gui/storybook/ToggleButtonStoryBoard.java create mode 100644 designer-base/src/test/java/com/fr/design/gui/storybook/UIHeadGroupStoryBoard.java diff --git a/designer-base/src/main/java/com/fine/theme/icon/IconResource.java b/designer-base/src/main/java/com/fine/theme/icon/IconResource.java index f654a6cf8c..d519601391 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/IconResource.java +++ b/designer-base/src/main/java/com/fine/theme/icon/IconResource.java @@ -1,6 +1,6 @@ package com.fine.theme.icon; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import java.io.InputStream; @@ -18,6 +18,6 @@ public interface IconResource { * * @return 资源流 */ - @Nullable + @NotNull InputStream getInputStream(); } diff --git a/designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java b/designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java index 58e53646e2..1684a5464c 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java +++ b/designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java @@ -3,6 +3,7 @@ package com.fine.theme.icon; import com.fr.general.IOUtils; import com.fr.io.utils.ResourceIOUtils; import com.fr.third.errorprone.annotations.Immutable; +import org.jetbrains.annotations.NotNull; import java.io.InputStream; @@ -27,8 +28,13 @@ public class UrlIconResource implements IconResource { } @Override + @NotNull public InputStream getInputStream() { - return getInputStream(path); + InputStream inputStream = getInputStream(path); + if (inputStream == null) { + throw new IconException("Icon load failed: " + path); + } + return inputStream; } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java new file mode 100644 index 0000000000..062e818a74 --- /dev/null +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java @@ -0,0 +1,37 @@ +package com.fine.theme.light.ui.laf; + +import com.fine.swing.ui.layout.Layouts; +import com.fine.theme.icon.IconManager; +import com.fine.theme.light.ui.FineLightIconSet; +import com.formdev.flatlaf.FlatDarkLaf; +import com.formdev.flatlaf.util.UIScale; +import com.fr.stable.StringUtils; + +/** + * FineReport designer new look and feel + * + * @author vito + * @since 11.0 + * Created on 2023/9/12 + */ +public class FineDarkLaf extends FlatDarkLaf { + + private static final String USER_SCALE_FACTOR = "userScaleFactor"; + + public static boolean setup() { + IconManager.addSet(new FineLightIconSet("fine-light")); + Layouts.setScaleFactor(UIScale.getUserScaleFactor()); + UIScale.addPropertyChangeListener(evt -> { + if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { + Layouts.setScaleFactor((float) evt.getNewValue()); + } + }); + return setup(new FineDarkLaf()); + } + + @Override + public String getName() { + return "FineDarkLaf"; + } + +} diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java index 58442eca58..f18bbcd69b 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java @@ -1,8 +1,11 @@ package com.fine.theme.light.ui.laf; -import com.fine.theme.light.ui.FineLightIconSet; +import com.fine.swing.ui.layout.Layouts; import com.fine.theme.icon.IconManager; +import com.fine.theme.light.ui.FineLightIconSet; import com.formdev.flatlaf.FlatLightLaf; +import com.formdev.flatlaf.util.UIScale; +import com.fr.stable.StringUtils; /** * FineReport designer new look and feel @@ -12,8 +15,22 @@ import com.formdev.flatlaf.FlatLightLaf; * Created on 2023/9/12 */ public class FineLightLaf extends FlatLightLaf { + + public static final String USER_SCALE_FACTOR = "userScaleFactor"; + + /** + * 安装外观 + * + * @return 是否安装成功 + */ public static boolean setup() { IconManager.addSet(new FineLightIconSet("fine-light")); + Layouts.setScaleFactor(UIScale.getUserScaleFactor()); + UIScale.addPropertyChangeListener(evt -> { + if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { + Layouts.setScaleFactor((float) evt.getNewValue()); + } + }); return setup(new FineLightLaf()); } diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java index e1f91b15a7..9d52c61870 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java @@ -22,7 +22,7 @@ public class UIHead { this.icon = icon; } - public UIHead(Icon icon, int index, boolean enable) { + public UIHead(Icon icon,boolean enable) { this(icon); this.enable = enable; } diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java index 1eeb0bb913..f5560810ec 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java @@ -61,7 +61,7 @@ public class UIHeadGroup extends Row { } private void intiContent() { - setSpacing(4); + setSpacing(2); setOpaque(false); add(buttonGroup()); setUI(new UIHeadGroupUI()); diff --git a/designer-base/src/test/java/com/fr/design/gui/storybook/ButtonStoryBoard.java b/designer-base/src/test/java/com/fr/design/gui/storybook/ButtonStoryBoard.java new file mode 100644 index 0000000000..17646a18dc --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/gui/storybook/ButtonStoryBoard.java @@ -0,0 +1,36 @@ +package com.fr.design.gui.storybook; + +import com.fine.theme.icon.LazyIcon; +import com.fr.design.gui.ibutton.UIButton; + +import javax.swing.JButton; + +import static com.fine.swing.ui.layout.Layouts.cell; +import static com.fine.swing.ui.layout.Layouts.flex; +import static com.fine.swing.ui.layout.Layouts.row; + +/** + * 按钮 + * + * @author vito + * @since 11.0 + * Created on 2023/11/27 + */ +public class ButtonStoryBoard extends StoryBoard { + + public ButtonStoryBoard() { + super("按钮"); + add( + row(10, + cell(new UIButton("按钮")), + cell(new UIButton("保存", new LazyIcon("save"))), + cell(new UIButton(new LazyIcon("multi"))) + ), + row(10, + cell(new JButton("按钮")), + cell(new JButton(new LazyIcon("multi"))) + ), + flex() + ); + } +} diff --git a/designer-base/src/test/java/com/fr/design/gui/storybook/StoryBoard.java b/designer-base/src/test/java/com/fr/design/gui/storybook/StoryBoard.java new file mode 100644 index 0000000000..ad7f04aa32 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/gui/storybook/StoryBoard.java @@ -0,0 +1,30 @@ +package com.fr.design.gui.storybook; + +import com.fine.swing.ui.layout.Column; +import com.fr.design.gui.ilable.UILabel; + +import javax.swing.UIManager; +import java.awt.Font; + +import static com.fine.swing.ui.layout.Layouts.cell; + +/** + * UI 故事板,用于demo + * 展示每个UI组件的能力 + * + * @author vito + * @since 11.0 + * Created on 2023/11/27 + */ +public class StoryBoard extends Column { + + protected static final Font labelFont = UIManager.getFont("Label.font"); + + protected String title; + + public StoryBoard(String title) { + this.title = title; + setSpacing(4); + add(cell(new UILabel(title)).with(it -> it.setFont(labelFont.deriveFont(16f).deriveFont(Font.BOLD)))); + } +} diff --git a/designer-base/src/test/java/com/fr/design/gui/storybook/StoryBookComponent.java b/designer-base/src/test/java/com/fr/design/gui/storybook/StoryBookComponent.java new file mode 100644 index 0000000000..8926899aea --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/gui/storybook/StoryBookComponent.java @@ -0,0 +1,18 @@ +package com.fr.design.gui.storybook; + +import javax.swing.JComponent; + +/** + * @author vito + * @since 11.0 + * Created on 2023/11/27 + */ +public class StoryBookComponent { + public String name; + public JComponent component; + + public StoryBookComponent(String name, JComponent component) { + this.name = name; + this.component = component; + } +} diff --git a/designer-base/src/test/java/com/fr/design/gui/storybook/Storybook.java b/designer-base/src/test/java/com/fr/design/gui/storybook/Storybook.java new file mode 100644 index 0000000000..e6621cddca --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/gui/storybook/Storybook.java @@ -0,0 +1,85 @@ +package com.fr.design.gui.storybook; + +import com.fanruan.gui.UiInspector; +import com.fine.theme.light.ui.laf.FineLightLaf; +import com.formdev.flatlaf.util.ScaledEmptyBorder; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Component; +import java.util.ArrayList; + +import static com.fine.swing.ui.layout.Layouts.cell; +import static com.fine.swing.ui.layout.Layouts.row; +import static com.fine.theme.utils.FineUIScale.scale; + +/** + * UI 故事书,用于demo + * 展示每个UI组件的能力 + * + * @author vito + * @since 11.0 + * Created on 2023/11/27 + */ +public class Storybook { + + CardLayout cardLayout; + JPanel cards; + + public void start() { + FineLightLaf.setup(); + JFrame jf = new JFrame("Story Book"); + jf.add(row( + cell(new JList<>(components())).with(it -> { + it.setBorder(new ScaledEmptyBorder(10, 10, 10, 10)); + it.setCellRenderer(new MyListCellRenderer()); + it.addListSelectionListener(e -> { + StoryBookComponent[] cs = components(); + cards.removeAll(); + cards.add(cs[it.getSelectedIndex()].component); + cards.revalidate(); + }); + }), + cell(new JScrollPane()).weight(1).with(it -> { + cards = new JPanel(new BorderLayout()); + it.setViewportView(cards); + cards.setBorder(new ScaledEmptyBorder(10, 10, 10, 10)); + cards.add(components()[0].component); + }) + ).getComponent()); + jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + jf.setSize(scale(600), scale(400)); + new UiInspector(); + jf.setVisible(true); + } + + + static class MyListCellRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setText(((StoryBookComponent) value).name); + return this; + } + } + + private StoryBookComponent[] components() { + ArrayList components = new ArrayList<>(); + components.add(new StoryBookComponent("Button", new ButtonStoryBoard())); + components.add(new StoryBookComponent("HeadGroup", new UIHeadGroupStoryBoard())); + components.add(new StoryBookComponent("ToggleButton", new ToggleButtonStoryBoard())); + return components.toArray(new StoryBookComponent[0]); + } + + + public static void main(String... args) { + SwingUtilities.invokeLater(() -> new Storybook().start()); + } + +} diff --git a/designer-base/src/test/java/com/fr/design/gui/storybook/ToggleButtonStoryBoard.java b/designer-base/src/test/java/com/fr/design/gui/storybook/ToggleButtonStoryBoard.java new file mode 100644 index 0000000000..8ef89bc40a --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/gui/storybook/ToggleButtonStoryBoard.java @@ -0,0 +1,31 @@ +package com.fr.design.gui.storybook; + +import com.fine.theme.icon.LazyIcon; + +import javax.swing.JToggleButton; + +import static com.fine.swing.ui.layout.Layouts.cell; +import static com.fine.swing.ui.layout.Layouts.flex; +import static com.fine.swing.ui.layout.Layouts.row; + +/** + * 切换状态按钮 + * + * @author vito + * @since 11.0 + * Created on 2023/11/27 + */ +public class ToggleButtonStoryBoard extends StoryBoard { + + public ToggleButtonStoryBoard() { + super("切换按钮"); + add( + row(10, + cell(new JToggleButton("切换按钮")), + cell(new JToggleButton("长文字保存保存保存保存", new LazyIcon("save"))), + cell(new JToggleButton(new LazyIcon("multi"))) + ), + flex() + ); + } +} diff --git a/designer-base/src/test/java/com/fr/design/gui/storybook/UIHeadGroupStoryBoard.java b/designer-base/src/test/java/com/fr/design/gui/storybook/UIHeadGroupStoryBoard.java new file mode 100644 index 0000000000..887c59e9e4 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/gui/storybook/UIHeadGroupStoryBoard.java @@ -0,0 +1,65 @@ +package com.fr.design.gui.storybook; + +import com.fine.theme.icon.LazyIcon; +import com.fr.design.gui.ibutton.UIHead; +import com.fr.design.gui.ibutton.UIHeadGroup; +import com.fr.design.gui.ilable.UILabel; + +import java.util.ArrayList; +import java.util.List; + +import static com.fine.swing.ui.layout.Layouts.cell; +import static com.fine.swing.ui.layout.Layouts.flex; + +/** + * 属性面板tab + * + * @author vito + * @since 11.0 + * Created on 2023/11/27 + */ +class UIHeadGroupStoryBoard extends StoryBoard { + + public UIHeadGroupStoryBoard() { + super("属性面板&导入数据集tab"); + add( + cell(new UILabel("文字Tab")).with(it -> it.setFont(labelFont.deriveFont(14f))), + cell(new UIHeadGroup(new String[]{"左按钮", "右按钮"})), + cell(new UILabel("图标Tab")).with(it -> it.setFont(labelFont.deriveFont(14f))), + cell(new UIHeadGroup(iconList())), + cell(new UILabel("文字Tab带禁用")).with(it -> it.setFont(labelFont.deriveFont(14f))), + cell(new UIHeadGroup(iconList2())), + cell(new UILabel("文字图标Tab带禁用")).with(it -> it.setFont(labelFont.deriveFont(14f))), + cell(new UIHeadGroup(iconList3())), + flex() + ); + } + + public static List iconList() { + List uiHeads = new ArrayList<>(); + uiHeads.add(new UIHead(new LazyIcon("cut"))); + uiHeads.add(new UIHead(new LazyIcon("save"))); + return uiHeads; + } + + public static List iconList2() { + List uiHeads = new ArrayList<>(); + uiHeads.add(new UIHead(new LazyIcon("cut"))); + uiHeads.add(new UIHead(new LazyIcon("save"), false)); + return uiHeads; + } + + public static List iconList3() { + List uiHeads = new ArrayList<>(); + uiHeads.add(new UIHead("剪切", new LazyIcon("cut"))); + uiHeads.add(new UIHead("保存", new LazyIcon("save"), false)); + return uiHeads; + } + + public static List iconList4() { + List uiHeads = new ArrayList<>(); + uiHeads.add(new UIHead("剪切剪切剪切剪切剪切剪切剪切剪切剪切", new LazyIcon("cut"))); + uiHeads.add(new UIHead("保存", new LazyIcon("save"), false)); + return uiHeads; + } +} From 9194c8cd70b8efb4642d5edec03dcdf2c823346a Mon Sep 17 00:00:00 2001 From: vito Date: Tue, 28 Nov 2023 20:44:32 +0800 Subject: [PATCH 3/3] =?UTF-8?q?Revert=20"REPORT-99485=20UI=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=88=86=E7=A6=BBDemo"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b75652dc438f16b7e0bee2d5266b4a35f756fe91. --- .../connect/ConnectionComboBoxPanel.java | 200 +++---- .../connect/ConnectionTableProcedurePane.java | 548 +++++++++--------- .../connect/ItemEditableComboBoxPanel.java | 182 ++++++ .../tabledatapane/DBTableDataPane.java | 505 ++++++++++++---- .../tabledatapane/DBTableDataViewModel.java | 281 --------- 5 files changed, 929 insertions(+), 787 deletions(-) delete mode 100644 designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java index d3b1a720d7..76f32d6f0c 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java @@ -1,9 +1,7 @@ package com.fr.design.data.datapane.connect; -import com.fine.state.livedata.LiveData; -import com.fine.swing.ui.layout.Row; -import com.fr.base.BaseUtils; import com.fr.base.svg.IconUtils; +import com.fr.data.impl.AbstractDatabaseConnection; import com.fr.data.impl.Connection; import com.fr.data.impl.NameDatabaseConnection; import com.fr.design.DesignerEnvManager; @@ -11,23 +9,22 @@ import com.fr.design.editlock.ConnectionLockChangeChecker; import com.fr.design.editlock.EditLockUtils; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UILockButton; -import com.fr.design.gui.icombobox.UIComboBox; -import com.fr.design.i18n.Toolkit; -import com.fr.log.FineLoggerFactory; +import com.fr.file.ConnectionConfig; import com.fr.report.LockItem; import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; -import org.jetbrains.annotations.Nullable; +import com.fr.workspace.server.connection.DBConnectAuth; -import javax.swing.DefaultComboBoxModel; import javax.swing.SwingUtilities; +import java.awt.Dimension; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; import java.util.List; -import java.util.Objects; -import java.util.concurrent.CancellationException; -import java.util.function.Consumer; - -import static com.fine.swing.ui.layout.Layouts.cell; /** * 选择数据连接的下拉框 @@ -35,150 +32,86 @@ import static com.fine.swing.ui.layout.Layouts.cell; * @editor zhou * @since 2012-3-28下午3:02:30 */ -public class ConnectionComboBoxPanel extends Row { +public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { + /** + * + */ private static final long serialVersionUID = 1L; + private Class cls; // 所取的Connection都是cls及其子类 + private List nameList = new ArrayList(); - private static final String PENDING = Toolkit.i18nText("Fine-Design_Basic_Loading") + "..."; - - protected static final Object EMPTY = new Object() { - public String toString() { - return ""; - } - }; - - protected UIComboBox itemComboBox; - protected UIButton editButton; - - // 记录原来选中的Item,重新加载后需要再次选中 - private Object lastSelectedItem; - - private final LiveData> names; - private final Consumer fetchNames; - - public ConnectionComboBoxPanel( - LiveData> names, - LiveData selectedItem, - @Nullable Consumer fetchNames, - @Nullable Consumer selecteChangeConsumer - ) { + public ConnectionComboBoxPanel(Class cls) { super(); - this.names = names; - this.fetchNames = fetchNames; - initComponents(); + + this.cls = cls; // alex:添加item change监听,当改变时改变DesignerEnvManager中的最近选中的数据连接 - this.itemComboBox.addItemListener(e -> { - String selected = ConnectionComboBoxPanel.this.getSelectedItem(); - if(PENDING.equals(selected)){ - return; - } - if (StringUtils.isNotBlank(selected)) { - DesignerEnvManager.getEnvManager().setRecentSelectedConnection(selected); - } - if(!Objects.isNull(selecteChangeConsumer)){ - selecteChangeConsumer.accept(selected); - } - }); - names.observeForever(strings -> { - try { - itemComboBox.setModel(new DefaultComboBoxModel<>(strings.toArray(new String[0]))); -// // 如果加载成功 但是下拉框是可见的 下拉框高度是会固定为原始高度 不会因为填充了更多下拉项而变化 -// // 需要重新设置下拉框高度 但值一样时相关事件不会生效 所以先加再减下 -// if (itemComboBox.isPopupVisible()) { -// itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() + 1); -// itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() - 1); -// } -// // 存在两种场景之前只考虑了填充场景 有populate会填充下 把这边的填充逻辑删了 所以没有问题 -// // 如果是纯通过刷新按钮 没有populate 需要手动设置下上次选中的内容 - if (lastSelectedItem != null) { - itemComboBox.setSelectedItem(lastSelectedItem); - } - } catch (Exception e) { - if (!(e instanceof CancellationException)) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + this.itemComboBox.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + String selected = ConnectionComboBoxPanel.this.getSelectedItem(); + if (StringUtils.isNotBlank(selected)) { + DesignerEnvManager.getEnvManager().setRecentSelectedConnection(selected); } } }); - - - lastSelectedItem = selectedItem.getValue(); refreshItems(); } - private void initComponents() { - setSpacing(5); - add( - cell(new UIComboBox()).weight(1.0).with(uiComboBox -> { - this.itemComboBox= uiComboBox; - uiComboBox.setEnabled(true); - - }), - cell(new UIButton(BaseUtils.readIcon("/com/fr/design/images/control/refresh.png"))) - .with(btn -> btn.addActionListener(e -> refreshItems())), - cell(initEditButton()).with(uiButton -> editButton = uiButton) - ); - } - - - /** - * 给itemComboBox添加ActionListener - */ - public void addComboBoxActionListener(ActionListener l) { - itemComboBox.addActionListener(l); - } - - /* - * 刷新itemComboBox的内容 - */ - protected void refreshItems() { - lastSelectedItem = itemComboBox.getSelectedItem(); - DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); - - model.removeAllElements(); - - // 先加EMPTY,再加items - model.addElement(PENDING); - if(!Objects.isNull(fetchNames)){ - fetchNames.accept(null); - } - } - - protected UIButton initEditButton() { - UIButton editButton = new UILockButton( + @Override + protected UIButton initEditButton(UIButton editButton, Dimension buttonSize) { + editButton = new UILockButton( EditLockUtils.CONNECTION_LOCKED_ICON, IconUtils.readIcon("/com/fr/design/images/m_web/connection"), EditLockUtils.CONNECTION_LOCKED_TOOLTIPS, null ); -// editButton.setPreferredSize(buttonSize); - editButton.addActionListener(evt -> editItems()); + editButton.setPreferredSize(buttonSize); + editButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + editItems(); + } + }); ConnectionLockChangeChecker.getInstance().addEditLockChangeListener((UILockButton) editButton); return editButton; } /* - * 得到其中的itemComboBox所选中的Item + * 刷新ComboBox.items */ - public String getSelectedItem() { - Object selected = itemComboBox.getSelectedItem(); + protected Iterator items() { + ConnectionConfig mgr = ConnectionConfig.getInstance(); + Iterator nameIt = mgr.getConnections().keySet().iterator(); + + Collection noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections(); - return selected instanceof String ? (String)selected : null; + nameList = new ArrayList<>(); + + if (noAuthConnections == null) { + return nameList.iterator(); + } + while (nameIt.hasNext()) { + String conName = nameIt.next(); + if (noAuthConnections.contains(conName)) { + continue; + } + Connection connection = mgr.getConnection(conName); + // nameList依赖items方法初始化,父类ItemEditableComboBoxPanel里异步执行item方法 + filterConnection(connection, conName, nameList); + } + + return nameList.iterator(); } - /* - * 选中name项 - */ - public void setSelectedItem(String name) { - DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); - model.setSelectedItem(name); + protected void filterConnection(Connection connection, String conName, List nameList) { + connection.addConnection(nameList, conName, new Class[]{AbstractDatabaseConnection.class}); } public int getConnectionSize() { - return names.getValue().size(); + return nameList.size(); } public String getConnection(int i) { - return names.getValue().get(i); + return nameList.get(i); } /* @@ -215,7 +148,9 @@ public class ConnectionComboBoxPanel extends Row { protected void setRecentConnection() { String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); if (StringUtils.isNotBlank(s)) { - if (names.getValue().contains(s)) { + // 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白 + // 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置 + if (nameList.contains(s)) { this.setSelectedItem(s); } } @@ -225,5 +160,12 @@ public class ConnectionComboBoxPanel extends Row { } } - -} \ No newline at end of file + /** + * 是否无选中状态(空白item也视为无选中) + * @return + */ + protected boolean isSelectedItemEmpty() { + String selectedItem = this.getSelectedItem(); + return selectedItem == null || StringUtils.equals(selectedItem, EMPTY.toString()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java index de5d1ed8a7..41556dae83 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java @@ -1,14 +1,13 @@ package com.fr.design.data.datapane.connect; -import com.fine.state.livedata.LiveData; -import com.fine.state.livedata.MutableLiveData; import com.fr.base.BaseUtils; import com.fr.base.svg.IconUtils; import com.fr.data.core.db.TableProcedure; +import com.fr.data.impl.AbstractDatabaseConnection; import com.fr.data.impl.Connection; -import com.fr.design.DesignerEnvManager; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.UIConstants; +import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icontainer.UIScrollPane; @@ -19,24 +18,21 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.general.GeneralContext; import com.fr.stable.ArrayUtils; -import com.fr.stable.StringUtils; import javax.swing.BorderFactory; +import javax.swing.DefaultComboBoxModel; import javax.swing.JPanel; import javax.swing.ToolTipManager; -import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.function.Consumer; /** * 数据集编辑面板左边的部分 @@ -45,269 +41,277 @@ import java.util.function.Consumer; * @since 2012-3-28下午10:14:59 */ public class ConnectionTableProcedurePane extends BasicPane { - private static int WIDTH = 155; - private ConnectionComboBoxPanel connectionComboBox; - private UICheckBox tableCheckBox; - private UICheckBox viewCheckBox; - protected UITextField searchField; - private TableViewList tableViewList; - private List listeners = new ArrayList(); - - private ConnectionTableState state; - - public MutableLiveData selected = new MutableLiveData<>(); - public Consumer selecteChangeConsumer; - - public static class ConnectionTableState { - public LiveData> names; - public Consumer namesConsumer; - public LiveData> tableProcedures; - public Consumer tableProcedureBeanConsumer; - - public ConnectionTableState(LiveData> names, Consumer namesConsumer, LiveData> tableProcedures, Consumer tableProcedureBeanConsumer) { - this.names = names; - this.namesConsumer = namesConsumer; - this.tableProcedures = tableProcedures; - this.tableProcedureBeanConsumer = tableProcedureBeanConsumer; - } - } - - public ConnectionTableProcedurePane() { - init(); - } - - public ConnectionTableProcedurePane(ConnectionTableState state) { - this.state = state; - init(); - } - - - private void init() { - selecteChangeConsumer = selectedName -> { - selected.setValue(selectedName); - }; - this.setLayout(new BorderLayout(4, 4)); - - // 初始化中间的面板 - JPanel centerPane = initCenterPane(); - this.add(centerPane, BorderLayout.CENTER); - // 初始化数据连接下拉框 - initConnectionComboBox(); - this.add(connectionComboBox, BorderLayout.NORTH); - setBorder(new EmptyBorder( - 10, 10, 10, 10 - )); - this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); - addKeyMonitor(); - state.names.observeForever(strings -> { - search(true); - }); - } - - - protected void filter(Connection connection, String conName, List nameList) { - - } - - private JPanel initCenterPane() { - JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - // 搜索面板 - centerPane.add(createSearchPane(), BorderLayout.NORTH); - // 数据库表视图面板 - centerPane.add(createTableViewBorderPane(), BorderLayout.CENTER); - return centerPane; - } - - private void initConnectionComboBox() { - connectionComboBox = new ConnectionComboBoxPanel(state.names, selected,state.namesConsumer, selecteChangeConsumer); - connectionComboBox.addComboBoxActionListener(filter); - } - - - - private JPanel createTableViewBorderPane() { - tableViewList = new TableViewList(state.tableProcedures, state.tableProcedureBeanConsumer); - ToolTipManager.sharedInstance().registerComponent(tableViewList); - - tableViewList.addMouseListener(new MouseAdapter() { - public void mouseClicked(MouseEvent evt) { - if (evt.getClickCount() >= 2) { - Object obj = tableViewList.getSelectedValue(); - TableProcedure tableProcedure = null; - if (obj instanceof TableProcedure) { - tableProcedure = (TableProcedure) obj; - } else { - return; - } - for (DoubleClickSelectedNodeOnTreeListener listener : ConnectionTableProcedurePane.this.listeners) { - listener.actionPerformed(tableProcedure); - } - } - } - }); - UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); - tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); - JPanel tableViewBorderPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - tableViewBorderPane.add(tableViewListPane, BorderLayout.CENTER); - JPanel checkBoxgroupPane = createCheckBoxgroupPane(); - if (checkBoxgroupPane != null) { - tableViewBorderPane.add(createCheckBoxgroupPane(), BorderLayout.SOUTH); - } - return tableViewBorderPane; - } - - /** - * 创建搜索Panel,用于搜索表或视图 - * - * @return - */ - private JPanel createSearchPane() { - JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel searchPane = new JPanel(new BorderLayout(10, 0)); - searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + private static int WIDTH = 155; + private ConnectionComboBoxPanel connectionComboBox; + private UICheckBox tableCheckBox; + private UICheckBox viewCheckBox; + protected UITextField searchField; + private TableViewList tableViewList; + private java.util.List listeners = new java.util.ArrayList(); + + public ConnectionTableProcedurePane() { + init(null); + } + + /** + * 传入父容器 + * @param parent + */ + public ConnectionTableProcedurePane(SwitchableTableDataPane parent) { + init(parent); + } + + private void init(SwitchableTableDataPane parent) { + this.setLayout(new BorderLayout(4, 4)); + // 初始化数据连接下拉框 + initConnectionComboBox(parent); + // 初始化中间的面板 + JPanel centerPane = initCenterPane(); + this.add(connectionComboBox, BorderLayout.NORTH); + this.add(centerPane, BorderLayout.CENTER); + this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); + addKeyMonitor(); + } + + private JPanel initCenterPane() { + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // 搜索面板 + centerPane.add(createSearchPane(), BorderLayout.NORTH); + // 数据库表视图面板 + centerPane.add(createTableViewBorderPane(), BorderLayout.CENTER); + return centerPane; + } + + private void initConnectionComboBox(SwitchableTableDataPane parent) { + connectionComboBox = new ConnectionComboBoxPanel(com.fr.data.impl.Connection.class) { + + @Override + protected void filterConnection(Connection connection, String conName, List nameList) { + filter(connection, conName, nameList); + } + + @Override + protected void refreshItems() { + super.refreshItems(); + if (tableViewList != null) { + search(true); + } + } + + @Override + protected void afterRefreshItems() { + // 刷新完成后,如果未选中(在nameList初始化完成之前可能会出现),则尝试再次设置 + if (isSelectedItemEmpty()) { + setRecentConnection(); + } + // 获取数据连接之后,让父容器切换面板 + if (parent != null) { + parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); + } + DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); + model.removeElement(EMPTY); + } + + @Override + protected void refreshItemsError() { + // 获取数据连接出现错误时,也让父容器从Loading面板切换至内容面板 + if (parent != null) { + parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); + } + } + }; + connectionComboBox.addComboBoxActionListener(filter); + } + + private JPanel createTableViewBorderPane() { + tableViewList = new TableViewList(); + ToolTipManager.sharedInstance().registerComponent(tableViewList); + + tableViewList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() >= 2) { + Object obj = tableViewList.getSelectedValue(); + TableProcedure tableProcedure = null; + if (obj instanceof TableProcedure) { + tableProcedure = (TableProcedure) obj; + } else { + return; + } + for (int i = 0; i < ConnectionTableProcedurePane.this.listeners.size(); i++) { + ConnectionTableProcedurePane.this.listeners.get(i).actionPerformed(tableProcedure); + } + } + } + }); + UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); + tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + JPanel tableViewBorderPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tableViewBorderPane.add(tableViewListPane, BorderLayout.CENTER); + JPanel checkBoxgroupPane = createCheckBoxgroupPane(); + if (checkBoxgroupPane != null) { + tableViewBorderPane.add(createCheckBoxgroupPane(), BorderLayout.SOUTH); + } + return tableViewBorderPane; + } + + /** + * 创建搜索Panel,用于搜索表或视图 + * @return + */ + private JPanel createSearchPane() { + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + JPanel searchPane = new JPanel(new BorderLayout(10, 0)); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); // searchPane.setBackground(Color.WHITE); - searchField = new UITextField(); - searchField.setBorderPainted(false); - searchField.setPlaceholder(Toolkit.i18nText("Fine-Design_Basic_Table_Search")); - searchField.getDocument().addDocumentListener(searchListener); - searchField.addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - super.mouseEntered(e); - searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.CHECKBOX_HOVER_SELECTED)); - } - - @Override - public void mouseExited(MouseEvent e) { - super.mouseExited(e); - searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); - } - }); - // 搜索图标 - UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); - searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); - searchPane.add(searchField, BorderLayout.CENTER); - searchPane.add(searchLabel, BorderLayout.EAST); - panel.add(searchPane, BorderLayout.CENTER); - return panel; - } - - protected void addKeyMonitor() { - //do nothing - } - - protected JPanel createCheckBoxgroupPane() { - JPanel checkBoxgroupPane = FRGUIPaneFactory.createNColumnGridInnerContainer_S_Pane(2); - JPanel first = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - tableCheckBox = new UICheckBox(); - tableCheckBox.setSelected(true); - tableCheckBox.addActionListener(filter); - first.add(tableCheckBox); - - JPanel second = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - viewCheckBox = new UICheckBox(); - viewCheckBox.setSelected(true); - viewCheckBox.addActionListener(filter); - second.add(viewCheckBox); - - // 根据环境是否为中文设置不同的显示 - if (GeneralContext.isChineseEnv()) { - first.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table"), - BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING)); - second.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View"), - BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING)); - } else { - UILabel ui1 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING); - UILabel ui2 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING); - ui1.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); - ui2.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); - first.add(ui1); - second.add(ui2); - } - checkBoxgroupPane.add(first); - checkBoxgroupPane.add(second); - - return checkBoxgroupPane; - } - - /** - * 给 itemComboBox 加上 itemListener - * - * @param itemListener - */ - public void addItemListener(ItemListener itemListener) { - connectionComboBox.itemComboBox.addItemListener(itemListener); - } - - private final DocumentListener searchListener = new DocumentListener() { - - @Override - public void removeUpdate(DocumentEvent e) { - search(false); - } - - @Override - public void insertUpdate(DocumentEvent e) { - search(false); - } - - @Override - public void changedUpdate(DocumentEvent e) { - search(false); - } - }; - - private final ActionListener filter = e -> search(false); - - /** - * 选项改变,需要重新刷新下拉列表里面的项 - */ - protected void search(boolean refresh) { - String selectedObj = selected.getValue(); - if(StringUtils.isBlank(selectedObj)){ - selectedObj = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); - } - - String[] types = ArrayUtils.EMPTY_STRING_ARRAY; - if (tableCheckBox != null) { - if (tableCheckBox.isSelected()) { - types = ArrayUtils.add(types, TableProcedure.TABLE); - } - if (viewCheckBox.isSelected()) { - types = ArrayUtils.add(types, TableProcedure.VIEW); - } - } else { - types = ArrayUtils.add(types, TableProcedure.PROCEDURE); - } - tableViewList.populate(selectedObj, searchField.getText().trim(), refresh, types); - } - - @Override - protected String title4PopupWindow() { - return "Connection"; - } - - /** - * @param l - */ - public void addDoubleClickListener(DoubleClickSelectedNodeOnTreeListener l) { - this.listeners.add(l); - } - - public void setSelectedDatabaseConnection(com.fr.data.impl.Connection db) { - connectionComboBox.populate(db); - } - - public String getSelectedDatabaseConnnectonName() { - return connectionComboBox.getSelectedItem(); - } - - public static interface DoubleClickSelectedNodeOnTreeListener { - /** - * 处理双击事件 - * - * @param target - */ - public void actionPerformed(TableProcedure target); - } + searchField = new UITextField(); + searchField.setBorderPainted(false); + searchField.setPlaceholder(Toolkit.i18nText("Fine-Design_Basic_Table_Search")); + searchField.getDocument().addDocumentListener(searchListener); + searchField.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.CHECKBOX_HOVER_SELECTED)); + } + + @Override + public void mouseExited(MouseEvent e) { + super.mouseExited(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + } + }); + // 搜索图标 + UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); + searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + searchPane.add(searchField, BorderLayout.CENTER); + searchPane.add(searchLabel, BorderLayout.EAST); + panel.add(searchPane, BorderLayout.CENTER); + return panel; + } + + protected void filter(Connection connection, String conName, List nameList) { + connection.addConnection(nameList, conName, new Class[]{AbstractDatabaseConnection.class}); + } + + protected void addKeyMonitor() { + //do nothing + } + + protected JPanel createCheckBoxgroupPane() { + JPanel checkBoxgroupPane = FRGUIPaneFactory.createNColumnGridInnerContainer_S_Pane(2); + JPanel first = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + tableCheckBox = new UICheckBox(); + tableCheckBox.setSelected(true); + tableCheckBox.addActionListener(filter); + first.add(tableCheckBox); + + JPanel second = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + viewCheckBox = new UICheckBox(); + viewCheckBox.setSelected(true); + viewCheckBox.addActionListener(filter); + second.add(viewCheckBox); + + // 根据环境是否为中文设置不同的显示 + if (GeneralContext.isChineseEnv()) { + first.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table"), + BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING)); + second.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View"), + BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING)); + } else { + UILabel ui1 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/tables.png"), UILabel.LEADING); + UILabel ui2 = new UILabel(BaseUtils.readIcon("/com/fr/design/images/data/views.png"), UILabel.LEADING); + ui1.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); + ui2.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); + first.add(ui1); + second.add(ui2); + } + checkBoxgroupPane.add(first); + checkBoxgroupPane.add(second); + + return checkBoxgroupPane; + } + + /** + * 给 itemComboBox 加上 itemListener + * + * @param itemListener + */ + public void addItemListener(ItemListener itemListener) { + connectionComboBox.itemComboBox.addItemListener(itemListener); + } + + private DocumentListener searchListener = new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + search(false); + } + + @Override + public void insertUpdate(DocumentEvent e) { + search(false); + } + + @Override + public void changedUpdate(DocumentEvent e) { + search(false); + } + }; + + private ActionListener filter = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + search(false); + } + }; + + /** + * 选项改变,需要重新刷新下拉列表里面的项 + */ + protected void search(boolean refresh) { + String selectedObj = connectionComboBox.getSelectedItem(); + + String[] types = ArrayUtils.EMPTY_STRING_ARRAY; + if (tableCheckBox != null) { + if (tableCheckBox.isSelected()) { + types = (String[]) ArrayUtils.add(types, TableProcedure.TABLE); + } + if (viewCheckBox.isSelected()) { + types = (String[]) ArrayUtils.add(types, TableProcedure.VIEW); + } + } else { + types = (String[]) ArrayUtils.add(types, TableProcedure.PROCEDURE); + } + tableViewList.populate(selectedObj, searchField.getText().trim(), refresh, types); + } + + @Override + protected String title4PopupWindow() { + return "Connection"; + } + + /** + * @param l + */ + public void addDoubleClickListener(DoubleClickSelectedNodeOnTreeListener l) { + this.listeners.add(l); + } + + public void setSelectedDatabaseConnection(com.fr.data.impl.Connection db) { + connectionComboBox.populate(db); + } + + public String getSelectedDatabaseConnnectonName() { + return connectionComboBox.getSelectedItem(); + } + + public static interface DoubleClickSelectedNodeOnTreeListener { + /** + * 处理双击事件 + * + * @param target + */ + public void actionPerformed(TableProcedure target); + } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java index 8b13789179..a430a13bd1 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java @@ -1 +1,183 @@ +package com.fr.design.data.datapane.connect; +import com.fr.base.BaseUtils; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; + +import com.fr.log.FineLoggerFactory; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.util.Iterator; +import java.util.concurrent.CancellationException; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JPanel; +import javax.swing.SwingWorker; + +public abstract class ItemEditableComboBoxPanel extends JPanel { + /** + * + */ + private static final long serialVersionUID = 1L; + + private static final String PENDING = Toolkit.i18nText("Fine-Design_Basic_Loading") + "..."; + + protected static final Object EMPTY = new Object() { + public String toString() { + return ""; + } + }; + + protected UIComboBox itemComboBox; + protected UIButton editButton; + protected UIButton refreshButton; + + private SwingWorker, Void> refreshWorker; + + public ItemEditableComboBoxPanel() { + super(); + + initComponents(); + } + + protected void initComponents() { + this.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + Dimension buttonSize = new Dimension(26, 20); + itemComboBox = new UIComboBox(); + itemComboBox.setEnabled(true); + this.add(itemComboBox, BorderLayout.CENTER); + refreshButton = new UIButton(BaseUtils.readIcon("/com/fr/design/images/control/refresh.png")); + JPanel jPanel = FRGUIPaneFactory.createNColumnGridInnerContainer_Pane(2, 4 ,4); + editButton = initEditButton(editButton, buttonSize); + jPanel.add(editButton); + jPanel.add(refreshButton); + this.add(jPanel, BorderLayout.EAST); + refreshButton.setPreferredSize(buttonSize); + refreshButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + refreshItems(); + } + }); + } + + protected UIButton initEditButton(UIButton editButton, Dimension buttonSize) { + editButton = new UIButton(BaseUtils.readIcon("/com/fr/design/images/control/control-center2.png")); + editButton.setPreferredSize(buttonSize); + editButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + editItems(); + } + }); + return editButton; + } + + + /** + * 给itemComboBox添加ActionListener + */ + public void addComboBoxActionListener(ActionListener l) { + itemComboBox.addActionListener(l); + } + + /* + * 刷新itemComboBox的内容 + */ + protected void refreshItems() { + + if (refreshWorker != null && !refreshWorker.isDone()) { + refreshWorker.cancel(true); + } + + // 记录原来选中的Item,重新加载后需要再次选中 + Object lastSelectedItem = itemComboBox.getSelectedItem(); + + DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); + model.removeAllElements(); + + // 先加EMPTY,再加items + model.addElement(EMPTY); + model.addElement(PENDING); + + // 存在两种场景之前只考虑了填充场景 有populate会填充下 把这边的填充逻辑删了 所以没有问题 + // 如果是纯通过刷新按钮 没有populate 需要手动设置下上次选中的内容 + if (lastSelectedItem != null) { + model.setSelectedItem(lastSelectedItem); + } + + refreshWorker = new SwingWorker, Void>() { + @Override + protected Iterator doInBackground() throws Exception { + return items(); + } + + @Override + protected void done() { + try { + Iterator itemIt = get(); + model.removeElement(PENDING); + while(itemIt.hasNext()) { + model.addElement(itemIt.next()); + } + // 如果加载成功 但是下拉框是可见的 下拉框高度是会固定为原始高度 不会因为填充了更多下拉项而变化 + // 需要重新设置下拉框高度 但值一样时相关事件不会生效 所以先加再减下 + if (itemComboBox.isPopupVisible()) { + itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() + 1); + itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() - 1); + } + afterRefreshItems(); + } catch (Exception e) { + if (!(e instanceof CancellationException)) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + refreshItemsError(); + } + + } + }; + refreshWorker.execute(); + } + + /* + * 得到其中的itemComboBox所选中的Item + */ + public String getSelectedItem() { + Object selected = itemComboBox.getSelectedItem(); + + return selected instanceof String ? (String)selected : null; + } + + /* + * 选中name项 + */ + public void setSelectedItem(String name) { + DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); + model.setSelectedItem(name); + } + + /* + * 刷新ComboBox.items + */ + protected abstract java.util.Iterator items(); + + /** + * 刷新ComboBox.items之后 + */ + protected void afterRefreshItems() { + // 空实现,供子类重写 + } + + /** + * 刷新ComboBox.items时出现异常 + */ + protected void refreshItemsError() { + // 空实现,供子类重写 + } + + /* + * 弹出对话框编辑Items + */ + protected abstract void editItems(); +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java index db0f03e72b..d0ffd7f22c 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java @@ -1,24 +1,35 @@ package com.fr.design.data.tabledata.tabledatapane; -import com.fine.state.livedata.DocumentLiveData; +import com.fr.base.Parameter; +import com.fr.base.ParameterHelper; +import com.fr.data.core.db.TableProcedure; import com.fr.data.impl.Connection; import com.fr.data.impl.DBTableData; import com.fr.data.impl.JDBCDatabaseConnection; import com.fr.data.impl.JNDIDatabaseConnection; +import com.fr.data.impl.NameDatabaseConnection; import com.fr.design.ExtraDesignClassManager; import com.fr.design.actions.UpdateAction; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.UIConstants; +import com.fr.design.data.StrategyConfigAttrUtils; +import com.fr.design.data.datapane.ESDStrategyConfigPane; import com.fr.design.data.datapane.connect.ConnectionTableProcedurePane; import com.fr.design.data.datapane.preview.PreviewTablePane; import com.fr.design.data.datapane.preview.sql.PreviewPerformedSqlPane; import com.fr.design.data.datapane.sqlpane.SQLEditPane; +import com.fr.design.data.tabledata.strategy.StrategyConfigHandler; +import com.fr.design.data.tabledata.tabledatapane.db.StrategyConfigFrom; import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.fun.DBTableDataMenuHandler; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itableeditorpane.ParameterTableModel; import com.fr.design.gui.itableeditorpane.UITableEditAction; @@ -31,15 +42,25 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.menu.SeparatorDef; import com.fr.design.menu.ToolBarDef; +import com.fr.design.utils.ParameterUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.esd.core.strategy.config.StrategyConfig; +import com.fr.esd.core.strategy.config.StrategyConfigHelper; +import com.fr.esd.core.strategy.config.service.StrategyConfigService; +import com.fr.esd.data.db.DBTableDataSavedHook; +import com.fr.esd.event.DSMapping; +import com.fr.esd.event.DsNameTarget; +import com.fr.esd.event.StrategyEventsNotifier; +import com.fr.esd.query.StrategicTableData; import com.fr.general.ComparatorUtils; import com.fr.general.IOUtils; +import com.fr.general.sql.SqlUtils; import com.fr.log.FineLoggerFactory; import com.fr.script.Calculator; import com.fr.stable.ArrayUtils; import com.fr.stable.ParameterProvider; import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; import javax.swing.BorderFactory; import javax.swing.Box; @@ -48,16 +69,20 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JToolBar; +import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import java.awt.BorderLayout; import java.awt.CardLayout; +import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; +import java.util.ArrayList; import java.util.List; /** @@ -74,22 +99,27 @@ public class DBTableDataPane extends AbstractTableDataPane implemen private UITableEditorPane editorPane; private DBTableDataMenuHandler dbTableDataMenuHandler; private SQLEditPane sqlTextPane; + private String pageQuery; + private DBTableData dbTableData; + //ESD + private UILabel esdSettingsLabel; + private UIComboBox esdConfigOption; + private UICheckBox esdEnabled; + private UIButton esdSettingsBtn; + private UILabel barErrorTips; + //配置 + private StrategyConfig strategyConfig; + + private StrategyConfigHandler configHandler; private CardLayout card; - /** - * 数据库查询面板真正的内容面板 - */ + /** 数据库查询面板真正的内容面板 */ private JPanel contentPane; - /** - * 加载中面板 - */ + /** 加载中面板 */ private JPanel loadingPane; - private DBTableDataViewModel viewModel; - public DBTableDataPane() { - viewModel = new DBTableDataViewModel(); initCards(); initContentPane(); } @@ -114,7 +144,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen add(LOADING_PANE_NAME, loadingPane); add(CONTENT_PANE_NAME, contentPane); - switchTo(CONTENT_PANE_NAME); + switchTo(LOADING_PANE_NAME); } private void init() { @@ -132,13 +162,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen editorPane = new UITableEditorPane<>(model); - this.connectionTableProcedurePane = new ConnectionTableProcedurePane( - new ConnectionTableProcedurePane.ConnectionTableState( - viewModel.getConnectionList(), - unused -> viewModel.fetchConnectionNameAction(), - viewModel.getTableProcedures(), - bean -> viewModel.fetchTableProceduresAction(bean) - )) { + this.connectionTableProcedurePane = new ConnectionTableProcedurePane(this) { @Override protected void filter(Connection connection, String conName, List nameList) { connection.addConnection(nameList, conName, new Class[]{ @@ -171,31 +195,35 @@ public class DBTableDataPane extends AbstractTableDataPane implemen }); } }; - this.connectionTableProcedurePane.addDoubleClickListener(target -> { - Document document = DBTableDataPane.this.sqlTextPane.getDocument(); - try { - document.insertString(DBTableDataPane.this.sqlTextPane.getCaretPosition(), target.toString(), null); - } catch (BadLocationException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + this.connectionTableProcedurePane.addDoubleClickListener(new ConnectionTableProcedurePane.DoubleClickSelectedNodeOnTreeListener() { + @Override + public void actionPerformed(TableProcedure target) { + Document document = DBTableDataPane.this.sqlTextPane.getDocument(); + try { + document.insertString(DBTableDataPane.this.sqlTextPane.getCaretPosition(), target.toString(), null); + } catch (BadLocationException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + + DBTableDataPane.this.sqlTextPane.requestFocus(); } - DBTableDataPane.this.sqlTextPane.requestFocus(); }); this.sqlTextPane.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { + barErrorTips.setVisible(false); } @Override public void focusLost(FocusEvent e) { if (DBTableDataPane.this.isPreviewOrRefreshButton(e)) { - viewModel.refreshParameters(); + DBTableDataPane.this.checkParameter(); } } }); - DocumentLiveData.fromDocumentEventsOf(sqlTextPane.getDocument()) - .observeForever(documentEvent -> viewModel.updateQuery(sqlTextPane.getText())); } private void initMainSplitPane() { @@ -265,6 +293,16 @@ public class DBTableDataPane extends AbstractTableDataPane implemen return Toolkit.i18nText("Fine-Design_Basic_DS-Database_Query"); } + private void refreshParameters() { + String[] paramTexts = new String[2]; + paramTexts[0] = SqlUtils.tryPureSqlText(this.sqlTextPane.getText()); + paramTexts[1] = SqlUtils.tryPureSqlText(this.pageQuery); + List existParameterList = this.editorPane.update(); + Parameter[] ps = (existParameterList == null) ? new Parameter[0] : existParameterList.toArray(new Parameter[0]); + + this.editorPane.populate(ParameterUtils.analyzeAndUnionParameters(paramTexts, ps)); + } + private JToolBar createToolBar() { ToolBarDef toolBarDef = new ToolBarDef(); toolBarDef.addShortCut(new PreviewAction()); @@ -281,105 +319,248 @@ public class DBTableDataPane extends AbstractTableDataPane implemen toolBarDef.updateToolBar(editToolBar); //esd相关组件初始化 -// createToolbarEsdComponents(editToolBar); + createToolbarEsdComponents(editToolBar); return editToolBar; } + private void createToolbarEsdComponents(final UIToolbar editToolBar) { + this.esdSettingsLabel = new UILabel(Toolkit.i18nText("Fine-Design_ESD_Cache_Settings")); + this.esdConfigOption = new UIComboBox(StrategyConfigFrom.values()); + this.esdEnabled = new UICheckBox(Toolkit.i18nText("Fine-Design_ESD_Enable_Cache")); + this.barErrorTips = new UILabel(); + this.barErrorTips.setForeground(Color.RED); + this.barErrorTips.setVisible(false); + + esdSettingsBtn = new UIButton(Toolkit.i18nText("Fine-Design_ESD_Strategy_Config")); + esdSettingsBtn.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + final boolean global = globalOptionSelected(); + + final ESDStrategyConfigPane strategyConfigPane = new ESDStrategyConfigPane(global); + + StrategyConfig populateStrategyConfig; + if (global) { + populateStrategyConfig = StrategyConfigService.getGlobalConfig(); + } else { + populateStrategyConfig = strategyConfig; + } + + //显示对应的配置 + strategyConfigPane.populateBean(populateStrategyConfig); + + BasicDialog dlg = strategyConfigPane.showMediumWindow(SwingUtilities.getWindowAncestor(DBTableDataPane.this), new DialogActionAdapter() { + @Override + public void doOk() { + super.doOk(); + if (!global) { + //点击策略配置面板的确定,重新设置策略配置 + strategyConfig = strategyConfigPane.updateBean(); + // TODO: 2021/3/12 这个直接使用不太好 + } + } + }); + //dlg.setAlwaysOnTop(true); + dlg.setVisible(true); + } + }); + + this.esdConfigOption.setSelectedIndex(StrategyConfigFrom.GLOBAL.getIndex()); + this.esdConfigOption.addActionListener(e -> setEsdEnabled()); + + + //工具栏加上esd相关组件 + editToolBar.add(this.esdSettingsLabel); + editToolBar.add(this.esdConfigOption); + editToolBar.add(this.esdEnabled); + editToolBar.add(this.esdSettingsBtn); + editToolBar.add(this.barErrorTips); + } + + private boolean globalOptionSelected() { + return esdConfigOption.getSelectedIndex() == StrategyConfigFrom.GLOBAL.getIndex(); + } + + private void setEsdEnableStatus(boolean selected, boolean enabled) { + this.esdEnabled.setSelected(selected); + this.esdEnabled.setEnabled(enabled); + } + + private void setEsdEnabled() { + boolean useIndividualConfig = !this.globalOptionSelected(); + if (useIndividualConfig) { + if (this.strategyConfig == null) { + //新建的数据集,选择单独时,可用但是不勾选 + setEsdEnableStatus(false, true); + } else { + setEsdEnableStatus(!this.strategyConfig.isUseGlobal() && this.strategyConfig.enabled(), true); + } + } else { + //判断是不是模版数据集 + switch (this.dbTableData.getScope()) { + case TEMPLATE: + String tplPath = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getEditingFILE().getPath(); + setEsdEnableStatus(StrategyConfigService.isTemplateEnabled(tplPath), false); + break; + case SERVER: + //不会走到这里 + default: + break; + } + } + } public StrategyConfig updateStrategyConfig() { - return null; + return this.strategyConfig; } - @Override - public void populateBean(DBTableData tableData) { - this.viewModel.updateTableData(tableData); - this.viewModel.getDbTableData().observeForever(dbTableData -> { - if (this.dbTableDataMenuHandler != null) { - this.dbTableDataMenuHandler.populate(dbTableData); + private void checkParameter() { + String[] paramTexts = new String[2]; + paramTexts[0] = this.sqlTextPane.getText(); + paramTexts[1] = this.pageQuery; + Parameter[] parameters = ParameterHelper.analyze4Parameters(paramTexts, false); + + if (parameters.length < 1 && this.editorPane.update().size() < 1) { + return; + } + boolean isIn = true; + List list = this.editorPane.update(); + List name = new ArrayList<>(); + for (ParameterProvider parameter : list) { + name.add(parameter.getName()); + } + for (Parameter parameter : parameters) { + if (!name.contains(parameter.getName())) { + isIn = false; + break; } - editorPane.populate(dbTableData.getParameters(Calculator.createCalculator())); - connectionTableProcedurePane.setSelectedDatabaseConnection(dbTableData.getDatabase()); - connectionTableProcedurePane.addItemListener(event -> { - String dbName = connectionTableProcedurePane.getSelectedDatabaseConnnectonName(); -// if (StringUtils.isBlank(dbName) || StringUtils.isBlank(sqlTextPane.getText())) { -// try { -// throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Connect_SQL_Cannot_Null") + "."); -// } catch (Exception e) { -// FineLoggerFactory.getLogger().error(e.getMessage(), e); -// } -// } - viewModel.updateDBName(dbName); - }); + } + if (list.size() == parameters.length && isIn) { + return; + } - }); + refreshParameters(); + } - this.sqlTextPane.setText(tableData.getQuery()); - this.sqlTextPane.moveCaretPosition(this.sqlTextPane.getCaretPosition()); + @Override + public void populateBean(DBTableData dbTableData) { + this.dbTableData = dbTableData; + if (this.dbTableDataMenuHandler != null) { + this.dbTableDataMenuHandler.populate(dbTableData); + } + + + Calculator c = Calculator.createCalculator(); + + ParameterProvider[] parameters = dbTableData.getParameters(c); + this.editorPane.populate(parameters); + + + Connection db = dbTableData.getDatabase(); + String query = dbTableData.getQuery(); + this.pageQuery = dbTableData.getPageQuerySql(); + this.connectionTableProcedurePane.setSelectedDatabaseConnection(db); + this.sqlTextPane.setText(query); this.sqlTextPane.requestFocus(); + this.sqlTextPane.moveCaretPosition(this.sqlTextPane.getCaretPosition()); + switch (dbTableData.getScope()) { + + case TEMPLATE: + this.configHandler = new TemplateStrategyConfigHandler(dbTableData); + break; + case SERVER: + //服务器数据集 + default: + //新建服务器数据集 + this.configHandler = new ServerStrategyConfigHandler(dbTableData); + break; + } //设置esd相关组件显示状态 -// populateESDComponents(); + populateESDComponents(); } -// private void populateESDComponents() { -// //查找映射的配置 -// this.strategyConfig = configHandler.find(); -// -// boolean shouldEnable = false; -// StrategyConfigFrom from = StrategyConfigFrom.GLOBAL; -// -// if (this.strategyConfig != null) { -// if (this.strategyConfig.enabled()) { -// shouldEnable = true; -// } -// if (!this.strategyConfig.isUseGlobal()) { -// from = StrategyConfigFrom.INDIVIDUAL; -// } -// } -// -// //服务器数据集不允许设置来源,只能单独配置 -// if (dbTableData.getScope() != StrategicTableData.Scope.TEMPLATE) { -// from = StrategyConfigFrom.INDIVIDUAL; -// this.esdConfigOption.setEnabled(false); -// } -// this.esdEnabled.setSelected(shouldEnable); -// this.esdConfigOption.setSelectedIndex(from.getIndex()); -// } + private void populateESDComponents() { + //查找映射的配置 + this.strategyConfig = configHandler.find(); + + boolean shouldEnable = false; + StrategyConfigFrom from = StrategyConfigFrom.GLOBAL; + + if (this.strategyConfig != null) { + if (this.strategyConfig.enabled()) { + shouldEnable = true; + } + if (!this.strategyConfig.isUseGlobal()) { + from = StrategyConfigFrom.INDIVIDUAL; + } + } + + //服务器数据集不允许设置来源,只能单独配置 + if (dbTableData.getScope() != StrategicTableData.Scope.TEMPLATE) { + from = StrategyConfigFrom.INDIVIDUAL; + this.esdConfigOption.setEnabled(false); + } + this.esdEnabled.setSelected(shouldEnable); + this.esdConfigOption.setSelectedIndex(from.getIndex()); + } @Override public DBTableData updateBean() { updateDBTableData(); -// internalUpdateStrategyConfig(); + internalUpdateStrategyConfig(); - return viewModel.getDbTableData().getValue(); + return this.dbTableData; } -// private void internalUpdateStrategyConfig() { -// //这边只修改enable和useGlobal -// boolean global = globalOptionSelected(); -// boolean enable = this.esdEnabled.isSelected(); -// -// -// //未开启缓存的,如果选择了单独配置,需要创建配置 -// if (this.strategyConfig == null && !global) { -// this.strategyConfig = StrategyConfig.createDefault(); -// } -// -// //设置配置来源和开启状态 -// if (this.strategyConfig != null) { -// this.strategyConfig.setEnable(enable); -// this.strategyConfig.setUseGlobal(global); -// } -// -// //保存 -// this.configHandler.save(this.dbTableData, this.strategyConfig); -// } + private void internalUpdateStrategyConfig() { + //这边只修改enable和useGlobal + boolean global = globalOptionSelected(); + boolean enable = this.esdEnabled.isSelected(); + + + //未开启缓存的,如果选择了单独配置,需要创建配置 + if (this.strategyConfig == null && !global) { + this.strategyConfig = StrategyConfig.createDefault(); + } + + //设置配置来源和开启状态 + if (this.strategyConfig != null) { + this.strategyConfig.setEnable(enable); + this.strategyConfig.setUseGlobal(global); + } + + //保存 + this.configHandler.save(this.dbTableData, this.strategyConfig); + } private void updateDBTableData() { + String dbName = this.connectionTableProcedurePane.getSelectedDatabaseConnnectonName(); + if (StringUtils.isBlank(dbName) || StringUtils.isBlank(this.sqlTextPane.getText())) { + try { + throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Connect_SQL_Cannot_Null") + "."); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + + // 保存前 刷新下参数列表 保证获取到最新的参数 + refreshParameters(); + + List parameterList = this.editorPane.update(); + ParameterProvider[] parameters = parameterList.toArray(new ParameterProvider[0]); + + dbTableData.setDatabase(new NameDatabaseConnection(dbName)); + - viewModel.refreshParameters(); + dbTableData.setParameters(parameters); + dbTableData.setQuery(this.sqlTextPane.getText().trim()); + + dbTableData.setPageQuerySql(this.pageQuery); if (this.dbTableDataMenuHandler != null) { this.dbTableDataMenuHandler.update(); } @@ -394,7 +575,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent e) { - viewModel.refreshParameters(); + DBTableDataPane.this.refreshParameters(); } @@ -413,6 +594,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent evt) { + DBTableDataPane.this.checkParameter(); PreviewTablePane.previewTableData(DBTableDataPane.this.updateBean()); } } @@ -426,7 +608,7 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent e) { - viewModel.refreshParameters(); + checkParameter(); PreviewPerformedSqlPane.previewPerformedSql(DBTableDataPane.this.updateBean()); } } @@ -441,13 +623,13 @@ public class DBTableDataPane extends AbstractTableDataPane implemen @Override public void actionPerformed(ActionEvent e) { final QueryPane pane = new QueryPane(Toolkit.i18nText("Fine-Design_Basic_Layer_Page_Report_Define_Page_Query_SQL")); - pane.populate(viewModel.getDbTableData().getValue().getPageQuerySql()); + pane.populate(pageQuery); BasicDialog dialog = pane.showWindow(DesignerContext.getDesignerFrame()); dialog.addDialogActionListener(new DialogActionAdapter() { @Override public void doOk() { - viewModel.updatePageQuery(pane.update()); - viewModel.refreshParameters(); + pageQuery = pane.update(); + checkParameter(); } }); dialog.setVisible(true); @@ -491,4 +673,117 @@ public class DBTableDataPane extends AbstractTableDataPane implemen } } + /** + * 服务器数据集配置处理器 + */ + private static class ServerStrategyConfigHandler extends StrategyConfigHandler { + private final String origName; + + private final String origConnection; + + private final String origQuery; + + public ServerStrategyConfigHandler(DBTableData tableData) { + super(tableData); + this.origName = tableData.getDsName(); + this.origConnection = tableData.getDatabase().toString(); + this.origQuery = tableData.getQuery(); + } + + @Override + public StrategyConfig find() { + StrategyConfig strategyConfig = null; + if (getTableData() != null) { + strategyConfig = getTableData().getStrategyConfig(); + if (strategyConfig == null) { + //共享数据集 + if (getTableData().isShare()) { + strategyConfig = StrategyConfigHelper.createStrategyConfig(true, false, true); + } + } + } + + return strategyConfig; + } + + @Override + public void save(DBTableData saved, StrategyConfig strategyConfig) { + String conn = saved.getDatabase().toString(); + String query = saved.getQuery(); + + + //检查数据链接和sql是否修改,如果修改需要触发缓存监听事件 + if (!conn.equals(origConnection) || !query.equals(origQuery)) { + if (StringUtils.isNotEmpty(origName)) { + //新建数据集的origName为null,不用触发 + StrategyEventsNotifier.modifyDataSet(DSMapping.ofServerDS(new DsNameTarget(origName))); + } + } + + + //配置变动事件 + try { + final StrategyConfig orig = getTableData().getStrategyConfig(); + saved.setStrategyConfig(strategyConfig.clone()); + StrategyEventsNotifier.compareAndFireConfigEvents(orig, strategyConfig, DSMapping.ofServerDS(new DsNameTarget(saved.getDsName()))); + } catch (CloneNotSupportedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } + + + /** + * 模版数据集配置处理器 + */ + private static class TemplateStrategyConfigHandler extends StrategyConfigHandler { + public TemplateStrategyConfigHandler(DBTableData tableData) { + super(tableData); + } + + @Override + public StrategyConfig find() { + StrategyConfig strategyConfig = null; + String tplPath = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getEditingFILE().getPath(); + if (getTableData() != null && StringUtils.isNotEmpty(tplPath)) { + //设置保存数据集的事件检查钩子 + //新建模版此时不存在,不需要注册钩子 + if (getTableData().getXmlSavedHook() == null && WorkContext.getWorkResource().exist(tplPath)) { + getTableData().setXmlSavedHook(new DBTableDataSavedHook(tplPath, getTableData())); + } + + //获取当前的缓存配置,没有就创建一份 + String dsName = getTableData().getDsName(); + + //这里为了之前兼容插件创建的配置,缓存配置不在DBTableData,而是从模版attr读取 + strategyConfig = StrategyConfigAttrUtils.getStrategyConfig(dsName); + + + if (useGlobal(getTableData(), strategyConfig)) { + //使用全局配置 + strategyConfig = StrategyConfigHelper.createStrategyConfig(true); + } else if (strategyConfig == null && getTableData().isShare()) { + //没有配置时,使用共享数据集兼容配置 + strategyConfig = StrategyConfigHelper.createStrategyConfig(true, false, true); + } + } + + return strategyConfig; + } + + private boolean useGlobal(DBTableData dbTableData, StrategyConfig strategyConfig) { + //非共享且配置为空或者指定使用全局配置时,检查是否全局开启 + if (strategyConfig == null) { + return !dbTableData.isShare(); + } else { + return strategyConfig.isUseGlobal(); + } + } + + @Override + public void save(DBTableData saved, StrategyConfig config) { + + //DBTableDataSavedHook处理了 + } + } } diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java deleted file mode 100644 index 6260e4960b..0000000000 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataViewModel.java +++ /dev/null @@ -1,281 +0,0 @@ -package com.fr.design.data.tabledata.tabledatapane; - -import com.fine.state.livedata.LiveData; -import com.fine.state.livedata.MutableLiveData; -import com.fr.base.Parameter; -import com.fr.base.ParameterHelper; -import com.fr.base.TableData; -import com.fr.data.core.DataCoreUtils; -import com.fr.data.core.db.TableProcedure; -import com.fr.data.core.db.dialect.base.key.check.DataBaseDetail; -import com.fr.data.core.db.dialect.base.key.check.DataBaseType; -import com.fr.data.impl.AbstractDatabaseConnection; -import com.fr.data.impl.Connection; -import com.fr.data.impl.DBTableData; -import com.fr.data.impl.NameDatabaseConnection; -import com.fr.data.operator.DataOperator; -import com.fr.design.DesignerEnvManager; -import com.fr.design.gui.ilist.TableViewList; -import com.fr.design.utils.ParameterUtils; -import com.fr.file.ConnectionConfig; -import com.fr.general.ComparatorUtils; -import com.fr.general.sql.SqlUtils; -import com.fr.stable.ArrayUtils; -import com.fr.stable.ParameterProvider; -import com.fr.stable.StringUtils; -import com.fr.workspace.WorkContext; -import com.fr.workspace.server.connection.DBConnectAuth; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static com.fr.data.core.db.TableProcedure.ERROR_TABLE_PROCEDURE; - -/** - * 数据集界面视图模型 - * - * @author vito - * @since 11.0 - * Created on 2023/11/7 - */ -public class DBTableDataViewModel { - - private MutableLiveData dbTableData = new MutableLiveData<>(); - private MutableLiveData> connectionList = new MutableLiveData<>(Collections.emptyList()); - private MutableLiveData> tableProcedures = new MutableLiveData<>(Collections.emptyList()); - - public DBTableDataViewModel() { - } - - public LiveData getDbTableData() { - return dbTableData; - } - - public LiveData> getConnectionList() { - return connectionList; - } - - public LiveData> getTableProcedures() { - return tableProcedures; - } - - /* ---------action--------- */ - public void updateTableData(TableData tableData) { - if (!(tableData instanceof DBTableData)) { - return; - } - dbTableData.postValue((DBTableData) tableData); - } - - - public void fetchConnectionNameAction() { - new Thread(() -> { - - ConnectionConfig mgr = ConnectionConfig.getInstance(); - Set connectionName = mgr.getConnections().keySet(); - - Collection noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections(); - - ArrayList nameList = new ArrayList<>(); - - if (noAuthConnections == null) { - connectionList.postValue(Collections.emptyList()); - return; - } - for (String conName : connectionName) { - if (noAuthConnections.contains(conName)) { - continue; - } - Connection connection = mgr.getConnection(conName); - connection.addConnection(nameList, conName, new Class[]{AbstractDatabaseConnection.class}); - } - connectionList.postValue(nameList); - }).start(); - } - - public void fetchTableProceduresAction(TableViewList.TableProcedureBean tableProcedureBean) { - new Thread(() -> { - List list; - try { - list = fetchTableProcedures(tableProcedureBean); - } catch (Exception e) { - list = new ArrayList<>(); - list.add(ERROR_TABLE_PROCEDURE); - } - tableProcedures.postValue(list); - }).start(); - } - - /** - * august:databaseName是数据库名字,searchFilter是输入的过滤条件,typesFilter是视图、表、 - * 存储过程中的一者或者几者 - * - * @param bean 数据 - */ - private List fetchTableProcedures(TableViewList.TableProcedureBean bean) throws Exception { - if (bean.refresh) { - clearCache(ConnectionConfig.getInstance().getConnection(bean.databaseName)); - } - Connection datasource = ConnectionConfig.getInstance().getConnection(bean.databaseName); - if (datasource == null) { - return Collections.emptyList(); - } - String[] schemas = DataCoreUtils.getDatabaseSchema(datasource); - - String searchFilter = bean.searchFilter.toLowerCase(); - boolean isOracleSystemSpace = DesignerEnvManager.getEnvManager().isOracleSystemSpace(); - // oracle不勾选显示所有表,则只显示用户下的(包括存储过程和table表) - DataBaseDetail detail = DataOperator.getInstance().getDataBaseDetail(datasource, isOracleSystemSpace); - if (ArrayUtils.isNotEmpty(detail.getSchemas())) { - schemas = detail.getSchemas(); - } - if (bean.typesFilter.length == 1 && ComparatorUtils.equals(bean.typesFilter[0], TableProcedure.PROCEDURE)) { - return processStoreProcedure(schemas, datasource, DataBaseType.ORACLE.equals(detail.getType()), searchFilter); - } else { - return processTableAndView(schemas, datasource, searchFilter, DataBaseType.ORACLE.equals(detail.getType()), bean.typesFilter); - } - } - - private void clearCache(Connection datasource) { - String[] schemas = DataCoreUtils.getDatabaseSchema(datasource); - schemas = (schemas == null || schemas.length == 0) ? new String[]{null} : schemas; - for (String schema : schemas) { - doClearCache(datasource, schema); - } - doClearCache(datasource, null); - } - - private void doClearCache(Connection datasource, String schema) { - DataCoreUtils.refreshTables(datasource, TableProcedure.TABLE, schema); - DataCoreUtils.refreshTables(datasource, TableProcedure.VIEW, schema); - DataCoreUtils.refreshTables(datasource, TableProcedure.PROCEDURE, schema); - } - - private List processStoreProcedure(String[] schemas, Connection datasource, boolean isOracle, String searchFilter) throws Exception { - List tableProcedures = new ArrayList<>(); - boolean isBlank = StringUtils.isBlank(searchFilter); - boolean isOracleSysSpace = DesignerEnvManager.getEnvManager().isOracleSystemSpace(); - List sqlTablees = DataCoreUtils.getProcedures(datasource, schemas, isOracle, isOracleSysSpace); - for (TableProcedure[] sqlTables : sqlTablees) { - if (sqlTables == null) { - continue; - } - for (TableProcedure sqlTable : sqlTables) { - String name = sqlTable.toString().toLowerCase(); - if (isBlank || name.contains(searchFilter)) { - tableProcedures.add(sqlTable); - } - } - } - return tableProcedures; - } - - private List processTableAndView(String[] schemas, Connection datasource, String searchFilter, boolean isOracle, String... typesFilter) - throws Exception { - List tableProcedures = new ArrayList<>(); - boolean isBlank = StringUtils.isBlank(searchFilter); - boolean isOracleSystemSpace = DesignerEnvManager.getEnvManager().isOracleSystemSpace(); - if (!isOracle) { - String schema = null; - for (String type : typesFilter) { - //非oracle数据库,默认都是显示所有表的,参数为true - TableProcedure[] sqlTables = DataCoreUtils.getTables(datasource, type, schema, true); - if (Objects.isNull(sqlTables)) { - return tableProcedures; - } - for (TableProcedure sqlTable : sqlTables) { - if (isBlank || sqlTable.getName().toLowerCase().contains(searchFilter)) { - tableProcedures.add(sqlTable); - } - } - } - } else { - for (String type : typesFilter) { - for (String schema : schemas) { - TableProcedure[] sqlTables = DataCoreUtils.getTables(datasource, type, schema, isOracleSystemSpace); - if (Objects.isNull(sqlTables)) { - return tableProcedures; - } - // oracle的表名加上模式 - for (TableProcedure ta : sqlTables) { - String name = ta.getSchema() + '.' + ta.getName(); - if (isBlank || name.toLowerCase().contains(searchFilter)) { - tableProcedures.add(ta); - } - } - } - } - } - return tableProcedures; - } - - public void updatePageQuery(String pageQuery) { - DBTableData tableData = dbTableData.getValue(); - if (ComparatorUtils.equals(pageQuery, tableData.getPageQuerySql())) { - return; - } - tableData.setPageQuerySql(pageQuery); - dbTableData.postValue(tableData); - } - - public void updateQuery(String query) { - DBTableData tableData = dbTableData.getValue(); - if (ComparatorUtils.equals(query, tableData.getQuery())) { - return; - } - tableData.setQuery(query); - dbTableData.postValue(tableData); - } - - public void refreshParameters() { - DBTableData tableData = dbTableData.getValue(); - if (needRefreshParameter(tableData)) { - tableData.setParameters(calParameter(tableData)); - } - dbTableData.postValue(tableData); - } - - private boolean needRefreshParameter(DBTableData tableData) { - String[] paramTexts = new String[2]; - paramTexts[0] = tableData.getQuery(); - paramTexts[1] = tableData.getPageQuerySql(); - Parameter[] parameters = ParameterHelper.analyze4Parameters(paramTexts, false); - - if (parameters.length < 1 && tableData.getParameters().length < 1) { - return false; - } - boolean isIn = true; - ParameterProvider[] list = tableData.getParameters(); - List name = new ArrayList<>(); - for (ParameterProvider parameter : list) { - name.add(parameter.getName()); - } - for (Parameter parameter : parameters) { - if (!name.contains(parameter.getName())) { - isIn = false; - break; - } - } - return list.length != parameters.length || !isIn; - } - - private Parameter[] calParameter(DBTableData tableData) { - - String[] paramTexts = new String[2]; - paramTexts[0] = SqlUtils.tryPureSqlText(tableData.getQuery()); - paramTexts[1] = SqlUtils.tryPureSqlText(tableData.getPageQuerySql()); - Parameter[] oldParameters = Arrays.asList(tableData.getParameters()).toArray(new Parameter[0]); - return ParameterUtils.analyzeAndUnionParameters(paramTexts, oldParameters); - } - - public void updateDBName(String dbName) { - DBTableData tableData = dbTableData.getValue(); - tableData.setDatabase(new NameDatabaseConnection(dbName)); - dbTableData.postValue(tableData); - } -}