diff --git a/designer-base/src/main/java/com/fr/common/listener/ManageDsListenerRegisterListener.java b/designer-base/src/main/java/com/fr/common/listener/ManageDsListenerRegisterListener.java new file mode 100644 index 000000000..6baa2e86b --- /dev/null +++ b/designer-base/src/main/java/com/fr/common/listener/ManageDsListenerRegisterListener.java @@ -0,0 +1,49 @@ +package com.fr.common.listener; + +import com.fr.design.data.DesignTableDataManager; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; +import javax.swing.event.ChangeListener; + +/** + * 管理数据集相关监听的注册 + * + * 原本的监听生命周期注册与销毁: + * + * 创建时组件时进行注册,在模板关闭时进行销毁 + * 但是在模板未关闭的这段时间,如果不断的打开和关闭某些弹窗,次数达到一定程度,会导致出现大量内存占用,除非此时关闭模板 + * + * 改成以下模式: + * + * 当组件可见或者被添加到某个大组件 注册相关监听 + * 当组件不可见或者被移除时 立即移除相关监听 + * 及时清理无效监听,减少实时内存占用 + * + * + * @author hades + * @version 11.0 + * Created by hades on 2022/2/14 + */ +public class ManageDsListenerRegisterListener implements AncestorListener { + + private ChangeListener changeListener; + + public ManageDsListenerRegisterListener(ChangeListener changeListener) { + this.changeListener = changeListener; + } + + @Override + public void ancestorAdded(AncestorEvent event) { + DesignTableDataManager.addDsChangeListener(changeListener); + } + + @Override + public void ancestorRemoved(AncestorEvent event) { + DesignTableDataManager.removeDsChangeLister(changeListener); + } + + @Override + public void ancestorMoved(AncestorEvent event) { + // do nothing + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java b/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java index f1758f068..8a57cca0b 100644 --- a/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java +++ b/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java @@ -172,23 +172,38 @@ public abstract class DesignTableDataManager { globalDsListeners.add(l); } + private static String getCurrentChangeListenerKey() { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + String key = StringUtils.EMPTY; + if (template != null) { + key = template.getPath(); + } + return key; + } + /** * 添加模板数据集改变 监听事件. * * @param l ChangeListener监听器 */ public static void addDsChangeListener(ChangeListener l) { - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - String key = StringUtils.EMPTY; - if (template != null) { - key = template.getPath(); - } + String key = getCurrentChangeListenerKey(); List dsListeners = dsListenersMap.get(key); if (dsListeners == null) { dsListeners = new ArrayList(); dsListenersMap.put(key, dsListeners); } - dsListeners.add(l); + if (!dsListeners.contains(l)) { + dsListeners.add(l); + } + } + + public static void removeDsChangeLister(ChangeListener l) { + String key = getCurrentChangeListenerKey(); + List dsListeners = dsListenersMap.get(key); + if (dsListeners != null) { + dsListeners.remove(l); + } } /** diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java index f65610526..6917f4c08 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java @@ -1,6 +1,7 @@ package com.fr.design.data.datapane; import com.fr.base.TableData; +import com.fr.common.listener.ManageDsListenerRegisterListener; import com.fr.concurrent.NamedThreadFactory; import com.fr.data.core.DataCoreUtils; import com.fr.data.core.db.DBUtils; @@ -648,12 +649,12 @@ public class ChoosePane extends BasicBeanPane implements Refresha */ @Override public void registerDSChangeListener() { - DesignTableDataManager.addDsChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - initDsNameComboBox(); - } - }); + this.addAncestorListener(new ManageDsListenerRegisterListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + initDsNameComboBox(); + } + })); } /** diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataComboBox.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataComboBox.java index ebbdbf0f3..140b294bf 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataComboBox.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataComboBox.java @@ -1,5 +1,6 @@ package com.fr.design.data.datapane; +import com.fr.common.listener.ManageDsListenerRegisterListener; import java.awt.Component; import java.awt.event.ItemEvent; import java.util.Iterator; @@ -148,7 +149,7 @@ public class TableDataComboBox extends UIComboBox implements Prepare4DataSourceC TableDataComboBox.this.refresh(DesignTableDataManager.getEditingTableDataSource()); } }; - DesignTableDataManager.addDsChangeListener(changeListener); + this.addAncestorListener(new ManageDsListenerRegisterListener(changeListener)); } public void registerGlobalDSChangeListener() { 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 5ed53cef4..5ee6654d4 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 @@ -14,14 +14,13 @@ import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UILockButton; import com.fr.design.mainframe.DesignerContext; import com.fr.file.ConnectionConfig; -import com.fr.general.ComparatorUtils; +import com.fr.report.LockItem; import com.fr.stable.StringUtils; import com.fr.transaction.CallBackAdaptor; import com.fr.transaction.Configurations; import com.fr.transaction.WorkerFacade; import com.fr.workspace.WorkContext; import com.fr.workspace.server.connection.DBConnectAuth; -import com.fr.report.LockItem; import javax.swing.SwingUtilities; import java.awt.Dimension; @@ -103,6 +102,7 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { continue; } Connection connection = mgr.getConnection(conName); + // nameList依赖items方法初始化,父类ItemEditableComboBoxPanel里异步执行item方法 filterConnection(connection, conName, nameList); } @@ -188,12 +188,10 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { } else { String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); if (StringUtils.isNotBlank(s)) { - for (int i = 0; i < this.getConnectionSize(); i++) { - String t = this.getConnection(i); - if (ComparatorUtils.equals(s, t)) { - this.setSelectedItem(s); - break; - } + // 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白 + // 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置 + if (ConnectionConfig.getInstance().getConnection(s) != null) { + this.setSelectedItem(s); } } // alex:如果这个ComboBox还是没有选中,那么选中第一个 diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java index 08274fd71..515bd8dd0 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java @@ -63,26 +63,27 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { public StoreProcedureDataWrapper(Component component, StoreProcedure storeProcedure, String storeprocedureName, String dsName) { this(component, storeProcedure, storeprocedureName, dsName, true); } - + /** - * @param: component loadingBar的父弹框(如果不设置父弹框的话,可能出现loadingBar隐藏在一个弹框后的情况) - * @param: storeProcedure 存储过程 - * @param: storeprocedureName 存储过程的名字(某些情况下可以为空) - * @param: dsName 存储过程一个返回数据集的名字 - * @param: needLoad 是否要加载 + * @param component loadingBar的父弹框(如果不设置父弹框的话,可能出现loadingBar隐藏在一个弹框后的情况) + * @param storeProcedure 存储过程 + * @param storeprocedureName 存储过程的名字(某些情况下可以为空) + * @param dsName 存储过程一个返回数据集的名字 + * @param needLoad 是否要加载 **/ public StoreProcedureDataWrapper(Component component, StoreProcedure storeProcedure, String storeprocedureName, String dsName, boolean needLoad) { this.dsName = dsName; this.storeProcedure = storeProcedure; this.storeProcedure.setCalculating(false); this.storeprocedureName = storeprocedureName; - if (needLoad) { - setWorker(); - } if (component == null) { component = new JFrame(); } + if (needLoad) { + setWorker(component); + } loadingBar = new AutoProgressBar(component, Toolkit.i18nText("Fine-Design_Basic_Loading_Data"), "", 0, 100) { + @Override public void doMonitorCanceled() { getWorker().cancel(true); } @@ -93,16 +94,17 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { * 数据集执行结果返回的所有字段 * * @return 数据集执行结果返回的所有字段 - * - * - * @date 2014-12-3-下午7:43:17 - * - */ + * @date 2014-12-3-下午7:43:17 + */ + @Override public List calculateColumnNameList() { if (columnNameList != null) { return columnNameList; } - if (!createStore(false)) { + + try { + createStore(false); + } catch (Exception e) { FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Engine_No_TableData")); return new ArrayList(); } @@ -114,11 +116,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { * 生成子节点 * * @return 节点数组 - * - * - * @date 2014-12-3-下午7:06:47 - * - */ + * @date 2014-12-3-下午7:06:47 + */ + @Override public ExpandMutableTreeNode[] load() { List namelist; if (storeProcedure.isCalculating()) { @@ -134,23 +134,16 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { return res; } - private boolean createStore(boolean needLoadingBar) { - try { - dataModels = DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar); - if (dataModels == null || dataModels.length == 0) { - return false; - } - for (int i = 0; i < dataModels.length; i++) { - if (ComparatorUtils.equals(this.dsName, storeprocedureName + "_" + dataModels[i].getName())) { - procedureDataModel = dataModels[i]; + private void createStore(boolean needLoadingBar) throws Exception { + dataModels = DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar); + if (dataModels != null && dataModels.length != 0) { + for (ProcedureDataModel dataModel : dataModels) { + if (ComparatorUtils.equals(this.dsName, storeprocedureName + "_" + dataModel.getName())) { + procedureDataModel = dataModel; break; } } - return true; - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); } - return false; } @Override @@ -159,17 +152,15 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { } /** - * 预览数据 - * - * @param previewModel 预览模式, 全部还是一个 - * - * - * @date 2014-12-3-下午7:05:50 - * - */ + * 预览数据 + * + * @param previewModel 预览模式, 全部还是一个 + * @date 2014-12-3-下午7:05:50 + */ public void previewData(final int previewModel) { this.previewModel = previewModel; connectionBar = new AutoProgressBar(new JFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Now_Create_Connection"), "", 0, 100) { + @Override public void doMonitorCanceled() { connectionBar.close(); worker.cancel(true); @@ -178,8 +169,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { worker.execute(); } - private void setWorker() { + private void setWorker(final Component parent) { worker = new SwingWorker() { + @Override protected Void doInBackground() throws Exception { loadingBar.close(); PreviewTablePane.resetPreviewTable(); @@ -195,6 +187,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { return null; } + @Override public void done() { try { get(); @@ -206,13 +199,15 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { case StoreProcedureDataWrapper.PREVIEW_ONE: previewData(); break; + default: + break; } } catch (Exception e) { + loadingBar.close(); if (!(e instanceof CancellationException)) { FineLoggerFactory.getLogger().error(e.getMessage(), e); - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), e.getMessage()); + FineJOptionPane.showMessageDialog(parent, e.getMessage()); } - loadingBar.close(); } } }; @@ -227,10 +222,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { /** * 预览返回的一个数据集 * - * - * @date 2014-12-3-下午7:42:53 - * - */ + * @date 2014-12-3-下午7:42:53 + */ + @Override public void previewData() { previewData(-1, -1); } @@ -240,13 +234,11 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { /** * 预览返回的一个数据集,带有显示值和实际值的标记结果 * - * @param keyIndex 实际值 - * @param valueIndex 显示值 - * - * - * @date 2014-12-3-下午7:42:27 - * - */ + * @param keyIndex 实际值 + * @param valueIndex 显示值 + * @date 2014-12-3-下午7:42:27 + */ + @Override public void previewData(final int keyIndex, final int valueIndex) { PreviewTablePane.previewStoreData(procedureDataModel, keyIndex, valueIndex); } @@ -257,7 +249,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { */ public void previewAllTable() { if (procedureDataModel == null) { - if (!createStore(true)) { + try { + createStore(true); + } catch (Exception e) { return; } } @@ -269,6 +263,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { return dsName; } + @Override public TableData getTableData() { return storeProcedure; } @@ -282,10 +277,12 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { * * @return 是否异常 */ + @Override public boolean isUnusual() { return false; } + @Override public boolean equals(Object obj) { return obj instanceof StoreProcedureDataWrapper && ComparatorUtils.equals(this.dsName, ((StoreProcedureDataWrapper) obj).getTableDataName()) diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/ShowOnlineWidgetMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/ShowOnlineWidgetMark.java new file mode 100644 index 000000000..1cf4a61b6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/locale/impl/ShowOnlineWidgetMark.java @@ -0,0 +1,26 @@ +package com.fr.design.locale.impl; + +import com.fr.general.GeneralContext; +import com.fr.general.locale.LocaleMark; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class ShowOnlineWidgetMark implements LocaleMark { + private Map map = new HashMap<>(); + + public ShowOnlineWidgetMark() { + map.put(Locale.CHINA, true); + map.put(Locale.TAIWAN, true); + map.put(Locale.US, false); + map.put(Locale.KOREA, false); + map.put(Locale.JAPAN, false); + } + + @Override + public Boolean getValue() { + Boolean result = map.get(GeneralContext.getLocale()); + return result == null ? false : result; + } +} \ No newline at end of file diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java index 6b75dff69..902347fb8 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java @@ -4,6 +4,7 @@ package com.fr.design.mainframe.chart; import com.fr.chart.chartattr.Chart; import com.fr.chart.chartattr.ChartCollection; import com.fr.chartx.attr.ChartProvider; +import com.fr.common.listener.ManageDsListenerRegisterListener; import com.fr.design.ChartTypeInterfaceManager; import com.fr.design.beans.FurtherBasicBeanPane; import com.fr.design.data.DesignTableDataManager; @@ -407,14 +408,14 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare * 数据集改变的事件监听 */ public void registerDSChangeListener() { - DesignTableDataManager.addDsChangeListener(new ChangeListener() { + this.addAncestorListener(new ManageDsListenerRegisterListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { AbstractChartAttrPane attrPane = paneList.get(tabsHeaderIconPane.getSelectedIndex()); if (attrPane.isShowing()) { attrPane.refreshChartDataPane(collection); } } - }); + })); } public boolean isInForm() { diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java index b5efad3b6..7137c180a 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java @@ -150,17 +150,19 @@ public class VanChartHyperLinkPane extends VanChartUIListControlPane { //安装平台内打开插件时,添加相应按钮 Set providers = ExtraDesignClassManager.getInstance().getArray(HyperlinkProvider.XML_TAG); - for (HyperlinkProvider provider : providers) { - NameableCreator nc = provider.createHyperlinkCreator(); - paneMap.put(nc.getHyperlink(), nc.getUpdatePane()); - } - java.util.List list = refreshList(paneMap); - NameObjectCreator[] creators = new NameObjectCreator[list.size()]; - for (int i = 0; list != null && i < list.size(); i++) { + int size = list.size(); + NameObjectCreator[] creators = new NameObjectCreator[list.size() + providers.size()]; + for (int i = 0; i < size; i++) { UIMenuNameableCreator uiMenuNameableCreator = list.get(i); creators[i] = new NameObjectCreator(uiMenuNameableCreator.getName(), uiMenuNameableCreator.getObj().getClass(), uiMenuNameableCreator.getPaneClazz()); - + } + for (HyperlinkProvider provider : providers) { + NameableCreator creator = provider.createHyperlinkCreator(); + if (creator != null) { + creators[size] = new NameObjectCreator(creator.menuName(), creator.getHyperlink(), creator.getUpdatePane()); + size++; + } } refreshNameableCreator(creators); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java b/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java index 8505af5ed..9eb11607c 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java @@ -41,10 +41,6 @@ import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.SwingConstants; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; @@ -55,6 +51,10 @@ import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; /** * @author null diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java b/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java index 7b3d4d239..9d1cee894 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java @@ -6,10 +6,13 @@ import com.fr.design.gui.ibutton.UIHeadGroup; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.locale.impl.ShowOnlineWidgetMark; import com.fr.design.mainframe.reuse.ComponentReuseNotificationInfo; import com.fr.design.mainframe.share.collect.ComponentCollector; import com.fr.design.mainframe.share.ui.local.LocalWidgetRepoPane; import com.fr.design.mainframe.share.ui.online.OnlineWidgetRepoPane; +import com.fr.general.locale.LocaleCenter; +import com.fr.general.locale.LocaleMark; import javax.swing.BorderFactory; import javax.swing.Icon; @@ -165,7 +168,13 @@ public class FormWidgetDetailPane extends FormDockView{ private void initPaneList() { paneList = new ArrayList<>(); paneList.add(LocalWidgetRepoPane.getInstance()); - paneList.add(OnlineWidgetRepoPane.getInstance()); + if (isShowOnlineWidgetRepoPane()) { + paneList.add(OnlineWidgetRepoPane.getInstance()); + } } + private boolean isShowOnlineWidgetRepoPane() { + LocaleMark localeMark = LocaleCenter.getMark(ShowOnlineWidgetMark.class); + return localeMark.getValue(); + } }