Browse Source

REPORT-141296 设计器UI操作性能优化

fbp/feature
Richard.Fang 2 months ago
parent
commit
a7bef7e32a
  1. 3
      designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
  2. 1
      designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java
  3. 59
      designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java
  4. 8
      designer-base/src/main/java/com/fr/design/formula/FormulaPane.java
  5. 17
      designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridControlPane.java
  6. 40
      designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java
  7. 117
      designer-base/src/main/java/com/fr/env/SetupDataDesignerRemoteOperator.java
  8. 2
      designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java
  9. 51
      designer-realize/src/main/java/com/fanruan/config/SetupDataDesignerRemoteOperator.java
  10. 2
      designer-realize/src/main/java/com/fr/design/cell/editor/FormulaCellEditor.java

3
designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java

@ -240,7 +240,6 @@ public class EnvChangeEntrance {
}
private static void afterSwitch() {
TemplateTreePane.getInstance().refreshDockingView();
DesignModelAdapter<?, ?> model = DesignModelAdapter.getCurrentModelAdapter();
if (model != null) {
model.envChanged();
@ -515,7 +514,7 @@ public class EnvChangeEntrance {
final EnvListPane envListPane = new EnvListPane();
final BasicDialog envListDialog = envListPane.showWindow(DesignerContext.getDesignerFrame());
dialog = envListDialog;
SwingUtilities.invokeLater(() -> envListPane.populateEnvManager(envName));
envListPane.populateEnvManager(envName);
envListDialog.addDialogActionListener(new DialogActionAdapter() {
@Override

1
designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java

@ -33,7 +33,6 @@ public class PreferenceAction extends UpdateAction {
final DesignerFrame designerFrame = DesignerContext.getDesignerFrame();
final PreferencePane preferencePane = new PreferencePane();
BasicDialog basicDialog = preferencePane.showWindow(designerFrame);
basicDialog.setButtonEnabled(false);
// 将当前环境配置填充到PreferencePane中
preferencePane.populate(basicDialog, DesignerEnvManager.getEnvManager());
basicDialog.addDialogActionListener(new DialogActionAdapter() {

59
designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java

@ -8,6 +8,7 @@ import com.fine.theme.utils.FineUIStyle;
import com.fine.theme.utils.FineUIUtils;
import com.fr.config.Configuration;
import com.fr.config.ServerPreferenceConfig;
import com.fr.config.utils.SetupDataHelper;
import com.fr.design.DesignerEnvManager;
import com.fr.design.RestartHelper;
import com.fr.design.dialog.BasicDialog;
@ -46,6 +47,7 @@ import com.fr.design.ui.util.UIUtil;
import com.fr.design.unit.UnitConvertUtil;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.widget.FRWidgetFactory;
import com.fr.env.SetupDataDesignerRemoteOperator;
import com.fr.general.ComparatorUtils;
import com.fr.general.FRFont;
import com.fr.general.Inter;
@ -54,6 +56,7 @@ import com.fr.io.attr.ImageExportAttr;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory;
import com.fr.report.ReportConfigManager;
import com.fr.report.ReportConfigManagerProvider;
import com.fr.stable.Constants;
import com.fr.third.apache.logging.log4j.Level;
import com.fr.third.guava.base.Supplier;
@ -69,7 +72,9 @@ import com.fr.workspace.server.vcs.VcsConfig;
import com.fr.workspace.server.vcs.git.config.GcConfig;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanSchedule;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import java.util.List;
import org.jetbrains.annotations.NotNull;
@ -259,6 +264,14 @@ public class PreferencePane extends BasicPane {
put(THREE_MONTH_INDEX, THREE_MONTH_INT);
}
});
private static final List<String> CONFIG_NAMESPACES = Arrays.asList(
VcsConfig.getInstance().getNameSpace(),
ServerPreferenceConfig.getInstance().getNameSpace(),
GcConfig.getInstance().getNameSpace(),
new ReportConfigManager().getNameSpace()
);
public PreferencePane() {
this.initComponents();
}
@ -491,7 +504,7 @@ public class PreferencePane extends BasicPane {
useVcsAutoSaveScheduleCheckBox.setEnabled(useV2);
}
}, basicDialog);
};
}
private JPanel createAutoCleanPane() {
Row autoCleanPane = new Row();
@ -880,12 +893,13 @@ public class PreferencePane extends BasicPane {
loadVersionControlSettings(designerEnvManager);
// 高级
loadAdvanceSettings(designerEnvManager);
// 异步加载配置后启用面板确认按钮
// 异步加载配置
loadConfigsAsync(basicDialog);
}
/**
* 选项-常用
*
* @param designerEnvManager
*/
private void loadCommonSettings(DesignerEnvManager designerEnvManager) {
@ -921,6 +935,7 @@ public class PreferencePane extends BasicPane {
/**
* 高级
*
* @param designerEnvManager
*/
private void loadAdvanceSettings(DesignerEnvManager designerEnvManager) {
@ -957,29 +972,31 @@ public class PreferencePane extends BasicPane {
}
private void loadConfigsAsync(BasicDialog dialog) {
List<Supplier<Object>> advanceConfigLoaders = Arrays.asList(
GcConfig.getInstance()::isGcEnable,
ServerPreferenceConfig.getInstance()::isUseUniverseDBM,
ReportConfigManager.getProviderInstance()::getImageExportAttr,
VcsConfig.getInstance()::isUseV2AutoClean,
VcsConfig.getInstance()::getV2CleanInterval,
VcsConfig.getInstance()::getV2RetainInterval,
() -> null
);
List<Consumer<Object>> advanceConfigUpdaters = Arrays.asList(
gcEnable -> updateGcConfigUI((Boolean) gcEnable),
useUniverseDBM -> useUniverseDBMCheckbox.setSelected((Boolean) useUniverseDBM),
imageExportAttr -> updateImageExportUI((ImageExportAttr) imageExportAttr),
useV2AutoClean -> useVcsAutoCleanScheduleCheckBox.setSelected(true),
v2CleanInterval -> autoCleanIntervalComboBox.setSelectedIndex(getIndex((Integer) v2CleanInterval)),
v2RetainInterval -> autoCleanRetainIntervalComboBox.setSelectedIndex(getIndex((Integer) v2RetainInterval)),
obj -> dialog.setButtonEnabled(true)
);
UIUtil.loadConfigsAndUpdateUI(advanceConfigLoaders, advanceConfigUpdaters);
UIUtil.executeAsyncTaskAndUpdateUI(() -> {
dialog.setButtonEnabled(false);
if (!WorkContext.getCurrent().isLocal()) {
SetupDataDesignerRemoteOperator.getInstance().fetchBatchConfDatas(CONFIG_NAMESPACES);
}
return null;
},
result -> {
populateConfigs();
dialog.setButtonEnabled(true);
});
}
private void populateConfigs() {
updateGcConfigUI(GcConfig.getInstance().isGcEnable());
useUniverseDBMCheckbox.setSelected(ServerPreferenceConfig.getInstance().isUseUniverseDBM());
updateImageExportUI(ReportConfigManager.getProviderInstance().getImageExportAttr());
useVcsAutoCleanScheduleCheckBox.setSelected(VcsConfig.getInstance().isUseV2AutoClean());
autoCleanIntervalComboBox.setSelectedIndex(getIndex(VcsConfig.getInstance().getV2CleanInterval()));
autoCleanRetainIntervalComboBox.setSelectedIndex(getIndex(VcsConfig.getInstance().getV2RetainInterval()));
}
/**
* 选项-版本管理
*
* @param designerEnvManager
*/
private void loadVersionControlSettings(DesignerEnvManager designerEnvManager) {

8
designer-base/src/main/java/com/fr/design/formula/FormulaPane.java

@ -48,6 +48,7 @@ import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.parameter.ParameterInputNoneListenerPane;
import com.fr.design.parameter.ParameterInputPane;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.ComparatorUtils;
import com.fr.general.FArray;
@ -1074,7 +1075,10 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
functionTypeScrollPane.setBorder(FineBorderFactory.createWrappedRoundBorder());
functionTypeList.setBackground(FlatUIUtils.getUIColor("background.normal", Color.WHITE));
initTypeListCellRenderer();
initGroupTypeModel();
UIUtil.executeAsyncTaskAndUpdateUI(() -> {
FunctionConstants.PLUGIN.getGroupName();
return null;
}, result -> initGroupTypeModel());
initTypeListSelectionListener();
return this.createNamePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Function_Category"), functionTypeScrollPane);
}
@ -1126,6 +1130,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
//hugh: 从函数分组插件中添加分组
FunctionConstants.addFunctionGroupFromPlugins(functionTypeListModel);
functionTypeList.setSelectedIndex(0);
}
private void initFunctionNameListCellRenderer() {
@ -1303,7 +1308,6 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
private JPanel initFunctionPane() {
JPanel functionTypePane = initFunctionTypeList();
JPanel functionNamePane = initFunctionNameList();
functionTypeList.setSelectedIndex(0);
return Layouts.row(LayoutConstants.HORIZONTAL_GAP,
cell(functionTypePane).weight(1), cell(functionNamePane).weight(1)
).getComponent();

17
designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridControlPane.java

@ -19,16 +19,11 @@ import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.theme.dialog.TemplateThemeProfileDialog;
import com.fr.design.menu.MenuDef;
import com.fr.design.menu.ToolBarDef;
import com.fr.design.ui.util.UIUtil;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.third.guava.base.Supplier;
import com.fr.third.javax.annotation.Nullable;
import com.fr.transaction.CallBackAdaptor;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
@ -216,15 +211,9 @@ public class TemplateThemeGridControlPane<T extends TemplateTheme> extends Basic
MenuDef menuDef = new MenuDef(Toolkit.i18nText("Fine-Design_Basic_Action_Add"));
menuDef.setIcon(new LazyIcon("add_popup"));
menuDef.setRePaint(true);
List<Supplier<String>> configLoaders = Arrays.asList(
config::getDefaultLightThemeName,
config::getDefaultDarkThemeName
);
List<Consumer<String>> configUpdaters = Arrays.asList(
lightThemeName -> menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Pane_Create_Light_Theme"), lightThemeName)),
darkThemeName -> menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Pane_Create_Dark_Theme"), darkThemeName))
);
UIUtil.loadConfigsAndUpdateUI(configLoaders, configUpdaters);
menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Pane_Create_Light_Theme"), config.getDefaultLightThemeName()));
menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Pane_Create_Dark_Theme"), config.getDefaultDarkThemeName()));
return menuDef;
}

40
designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java

@ -120,44 +120,4 @@ public class UIUtil {
}
}.execute();
}
/**
* 异步加载多个配置并更新UI每个配置加载的时间通常较短约几十毫秒
*
* @param <T> 配置对象的类型
* @param configLoaders 配置加载器列表每个加载器负责加载一种配置
* @param uiUpdaters UI 更新器列表每个更新器负责在 UI 上显示对应配置的值
*
* <p>
* 加载过程是异步的配置加载是顺序进行的即一个配置加载完成后才会加载下一个配置
* 配置加载任务会在后台线程中顺序执行所有配置加载完成后UI更新操作才会依次执行
* <p>
* 异常模式
* - 如果在加载某个配置时发生异常整个任务会失败后续的配置加载将不会继续执行
* - 异常会被捕获为 `ExecutionException` `InterruptedException`并在 `done()` 方法中记录日志
* - 配置加载过程中出现的错误会导致UI更新操作被跳过
*/
public static <T> void loadConfigsAndUpdateUI(List<Supplier<T>> configLoaders, List<Consumer<T>> uiUpdaters) {
new SwingWorker<List<T>, Void>() {
@Override
protected List<T> doInBackground() throws Exception {
List<T> results = new ArrayList<>();
for (Supplier<T> configLoader : configLoaders) {
results.add(configLoader.get());
}
return results;
}
@Override
protected void done() {
try {
List<T> configResults = get();
for (int i = 0; i < configResults.size(); i++) {
uiUpdaters.get(i).accept(configResults.get(i));
}
} catch (InterruptedException | ExecutionException e) {
FineLoggerFactory.getLogger().debug(e.getMessage(), e);
}
}
}.execute();
}
}

117
designer-base/src/main/java/com/fr/env/SetupDataDesignerRemoteOperator.java vendored

@ -0,0 +1,117 @@
package com.fr.env;
import com.fanruan.repository.ConfigRepository;
import com.fr.config.dao.DaoContext;
import com.fr.config.dao.impl.remote.RemoteConfigOperable;
import com.fr.config.utils.ConfData;
import com.fr.config.utils.ConfigReadUtils;
import com.fr.config.utils.PrefixHandler;
import com.fr.config.utils.SetupDataOperator;
import com.fr.nx.app.web.out.widget.utils.CollectionUtils;
import com.fr.stable.StringUtils;
import com.fr.tenant.context.TenantContext;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.sun.org.apache.xalan.internal.xsltc.compiler.Constants.STRING;
/**
* 设计器远程下获取Updata的操作类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2024/10/14
*/
public class SetupDataDesignerRemoteOperator implements SetupDataOperator {
private static final SetupDataDesignerRemoteOperator INSTANCE = new SetupDataDesignerRemoteOperator();
private static final String EMPTY_STRING = "";
/**
* 单例
*/
public static SetupDataDesignerRemoteOperator getInstance() {
return INSTANCE;
}
/**
* 批量拉取配置
* @param nameSpaces
*/
public void fetchBatchConfDatas(List<String> nameSpaces) {
if(nameSpaces.isEmpty()){
return;
}
List<String> namespaceList = nameSpaces.stream()
.filter(namespace -> !checkRemoteConfigCacheExistence(namespace))
.collect(Collectors.toList());
if(CollectionUtils.isEmpty(namespaceList)){
return;
}
ConfigRepository.getInstance().batchGetConfigsByConfigsCache(namespaceList, () -> {
batchSaveConfigs(namespaceList, TenantContext.getCurrentWithException().getId());
return null;
});
}
private void batchSaveConfigs(List<String> nameSpaces, String tenantId) {
nameSpaces.forEach(namespace -> {
String prefix = PrefixHandler.concatPrefix(namespace, EMPTY_STRING);
ConfigReadUtils.getData(prefix, tenantId);
ConfigReadUtils.getClassInfo(prefix, tenantId);
});
}
@Override
public ConfData getData(String prefix, String tenantId) {
String configNamespace = getConfigNameSpace(prefix);
if (checkRemoteConfigCacheExistence(configNamespace)) {
return createConfData(prefix, tenantId);
}
return ConfigRepository.getInstance().getConfigByConfigsCache(configNamespace, () -> createConfData(prefix, tenantId));
}
private ConfData createConfData(String prefix, String tenantId) {
ConfData data = new ConfData();
data.setDataMap(ConfigReadUtils.getData(prefix, tenantId));
data.setMap(ConfigReadUtils.getClassInfo(prefix, tenantId));
return data;
}
private String getConfigNameSpace(String id) {
if (StringUtils.isEmpty(id)) {
throw new IllegalArgumentException("id cannot be null");
}
int length = id.length();
for (int i = 0; i < length; i++) {
if (PrefixHandler.SEPERATOR == id.charAt(i)) {
return id.substring(0, i);
}
}
throw new IllegalArgumentException("cannot resolve namespace of " + id);
}
/**
* 检查远程配置缓存是否存在
* <p>
* 该方法通过判断三个远程配置相关的DAOEntityDaoXmlEntityDaoClassHelperDao是否在缓存中存在指定的命名空间
* 如果DAO实现了RemoteConfigOperable接口则会依次检查缓存
* 如果DAO不支持远程缓存检查返回false
*
* @param nameSpace 命名空间
* @return 如果三个远程DAO的缓存中都存在指定命名空间的数据返回true否则返回false
*/
private boolean checkRemoteConfigCacheExistence(String nameSpace) {
// 只判断一次,所有远程的Dao都实现了RemoteConfigOperable接口
if (DaoContext.getEntityDao() instanceof RemoteConfigOperable) {
return ((RemoteConfigOperable) DaoContext.getEntityDao()).checkCacheExistence(nameSpace) &&
((RemoteConfigOperable) DaoContext.getXmlEntityDao()).checkCacheExistence(nameSpace) &&
((RemoteConfigOperable) DaoContext.getClassHelperDao()).checkCacheExistence(nameSpace);
}
// 非远程配置不支持设计器缓存检查,返回false
return false;
}
}

2
designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java vendored

@ -12,7 +12,7 @@ import com.fanruan.carina.annotions.Stop;
import com.fanruan.carina.annotions.Supplemental;
import com.fanruan.config.ConfigProviderFactory;
import com.fanruan.config.LocalConfigSource;
import com.fanruan.config.SetupDataDesignerRemoteOperator;
import com.fr.env.SetupDataDesignerRemoteOperator;
import com.fanruan.config.realm.ConfigRealm;
import com.fanruan.dao.context.DBContextProvider;
import com.fanruan.dao.context.DBContextStarter;

51
designer-realize/src/main/java/com/fanruan/config/SetupDataDesignerRemoteOperator.java

@ -1,51 +0,0 @@
package com.fanruan.config;
import com.fanruan.repository.ConfigRepository;
import com.fr.config.utils.ConfData;
import com.fr.config.utils.ConfigReadUtils;
import com.fr.config.utils.PrefixHandler;
import com.fr.config.utils.SetupDataOperator;
import com.fr.stable.StringUtils;
/**
* 设计器远程下获取Updata的操作类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2024/10/14
*/
public class SetupDataDesignerRemoteOperator implements SetupDataOperator {
private static final SetupDataDesignerRemoteOperator INSTANCE = new SetupDataDesignerRemoteOperator();
/**
* 单例
*/
public static SetupDataDesignerRemoteOperator getInstance() {
return INSTANCE;
}
@Override
public ConfData getData(String prefix, String tenantId) {
return ConfigRepository.getInstance().getConfigByConfigsCache(getConfigNameSpace(prefix), () -> {
ConfData data = new ConfData();
data.setDataMap(ConfigReadUtils.getData(prefix, tenantId));
data.setMap(ConfigReadUtils.getClassInfo(prefix, tenantId));
return data;
});
}
private String getConfigNameSpace(String id) {
if (StringUtils.isEmpty(id)) {
throw new IllegalArgumentException("id cannot be null");
}
int length = id.length();
for (int i = 0; i < length; i++) {
if (PrefixHandler.SEPERATOR == id.charAt(i)) {
return id.substring(0, i);
}
}
throw new IllegalArgumentException("cannot resolve namespace of " + id);
}
}

2
designer-realize/src/main/java/com/fr/design/cell/editor/FormulaCellEditor.java

@ -6,7 +6,6 @@ package com.fr.design.cell.editor;
import com.fr.base.BaseFormula;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.formula.FormulaFactory;
import com.fr.design.formula.FunctionConstants;
import com.fr.design.formula.UIFormula;
import com.fr.design.mainframe.ElementCasePane;
import com.fr.grid.Grid;
@ -28,7 +27,6 @@ public class FormulaCellEditor extends com.fr.design.cell.editor.AbstractCellEdi
*/
public FormulaCellEditor(ElementCasePane<? extends TemplateElementCase> ePane) {
super(ePane);
SwingUtilities.invokeLater(() -> FunctionConstants.PLUGIN.getGroupName());
}
/**

Loading…
Cancel
Save