Browse Source

REPORT-51919 主题切换

【问题原因】
新增模版主题功能:
主题管理面板和主题使用面板中对主题的获取操作,全部异步化,
提高加载性能

【改动思路】
同上
research/11.0
Starryi 3 years ago
parent
commit
4118096815
  1. 86
      designer-base/src/main/java/com/fr/design/mainframe/theme/AsyncThemeFetcher.java
  2. 66
      designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java
  3. 63
      designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeListPane.java
  4. 40
      designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeManagePane.java

86
designer-base/src/main/java/com/fr/design/mainframe/theme/AsyncThemeFetcher.java

@ -0,0 +1,86 @@
package com.fr.design.mainframe.theme;
import com.fr.base.theme.TemplateTheme;
import com.fr.base.theme.TemplateThemeConfig;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.module.ModuleContext;
import java.util.concurrent.ExecutorService;
/**
* @author Starryi
* @version 1.0
* Created by Starryi on 2021/8/24
*/
public class AsyncThemeFetcher<T extends TemplateTheme> {
private final ExecutorService executorService;
private final TemplateThemeConfig<T> config;
public AsyncThemeFetcher(int threads, TemplateThemeConfig<T> config) {
this.executorService = ModuleContext.getExecutor().newFixedThreadPool(
threads,
new NamedThreadFactory(this.getClass().getName())
);
this.config = config;
}
public void shutdown() {
executorService.shutdown();
}
public boolean isShutdown() {
return executorService.isShutdown();
}
public void submit(String themeName, AsyncThemeFetchCallback<T> callback) {
callback.beforeCachedFetch();
executorService.submit(new Runnable() {
@Override
public void run() {
if (executorService.isShutdown()) {
return;
}
T theme = config.cachedFetch(themeName, new TemplateThemeConfig.CacheCondition<T>() {
@Override
public boolean shouldCacheTheme(T theme) {
return callback.shouldCache(AsyncThemeFetcher.this, theme);
}
});
if (executorService.isShutdown()) {
return;
}
callback.afterCachedFetch(theme);
}
});
}
public interface AsyncThemeFetchCallback<T extends TemplateTheme> {
void beforeCachedFetch();
boolean shouldCache(AsyncThemeFetcher<T> fetcher, T theme);
void afterCachedFetch(T theme);
}
public static class AsyncThemeFetchCallbackAdapter<T extends TemplateTheme> implements AsyncThemeFetchCallback<T> {
@Override
public void beforeCachedFetch() {
}
@Override
public boolean shouldCache(AsyncThemeFetcher<T> fetcher, T theme) {
// 如果Fetcher已经关闭就不放进缓存里了
// 因为可切换工作目录,所以submit时的工作目录环境与最终获取到主题数据时的工作目录环境可能不是同一个,
// 如果仍然放进缓存中,会污染当前工作目录环境的主题缓存.
// TODO: 除了根据asyncThemeFetch的关闭情况来判断是否缓存主题,也可以更加精细的判断前后的工作目录环境是否时同一个
// TODO: 后续看情况再优化吧.
return !fetcher.isShutdown();
}
@Override
public void afterCachedFetch(T theme) {
}
}
}

66
designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java

@ -55,16 +55,13 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
private boolean hovering = false;
private MouseAdapter clickListener;
private final ExecutorService asyncThemeFetcher;
public TemplateThemeBlock(String name,
TemplateThemeConfig<T> config,
TemplateThemeProfilePane<T> profilePane,
ExecutorService asyncThemeFetcher) {
TemplateThemeProfilePane<T> profilePane) {
this.name = name;
this.config = config;
this.profilePane = profilePane;
this.asyncThemeFetcher = asyncThemeFetcher;
initializePane();
addMouseListener(new MouseAdapter() {
@ -91,8 +88,6 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
repaint();
}
});
fetchTheme();
}
private void initializePane() {
@ -119,6 +114,21 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
add(infoPane, BorderLayout.SOUTH);
}
public void setTheme(T theme) {
this.theme = theme;
thumbnailLabel.setIcon(null);
if (theme != null) {
ThemeThumbnail thumbnail = theme.getThumbnail();
if (thumbnail != null) {
Image image = thumbnail.getImage();
if (image != null) {
thumbnailLabel.setIcon(new ImageIcon(image));
}
}
}
repaint();
}
public T getTheme() {
return this.theme;
}
@ -166,48 +176,6 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
profileDialog.setVisible(true);
}
public void fetchTheme() {
if (asyncThemeFetcher.isShutdown()) {
return;
}
asyncThemeFetcher.submit(new Runnable() {
@Override
public void run() {
if (asyncThemeFetcher.isShutdown()) {
return;
}
theme = null;
// 耗时的同步操作,如远程设计器场景
theme = config.cachedFetch(name, new TemplateThemeConfig.CacheCondition<T>() {
@Override
public boolean shouldCacheTheme(T theme) {
// 如果Fetcher已经关闭就不放进缓存里了
// 因为可切换工作目录,所以submit时的工作目录环境与最终获取到主题数据时的工作目录环境可能不是同一个,
// 如果仍然放进缓存中,会污染当前工作目录环境的主题缓存.
// TODO: 除了根据asyncThemeFetch的关闭情况来判断是否缓存主题,也可以更加精细的判断前后的工作目录环境是否时同一个
// TODO: 后续看情况再优化吧.
return !asyncThemeFetcher.isShutdown();
}
});
if (asyncThemeFetcher.isShutdown()) {
return;
}
if (theme != null) {
ThemeThumbnail thumbnail = theme.getThumbnail();
if (thumbnail != null) {
Image image = thumbnail.getImage();
if (image != null) {
thumbnailLabel.setIcon(new ImageIcon(image));
}
}
}
repaint();
}
});
}
@Override
public void paint(Graphics g) {
super.paint(g);
@ -215,7 +183,7 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
if (template != null) {
TemplateThemeConfig<? extends TemplateTheme> templateUsingConfig = template.getUsingTemplateThemeConfig();
TemplateTheme templateTheme = template.getTemplateTheme();
if (templateUsingConfig == this.config && StringUtils.equals(templateTheme.getName(), theme.getName())) {
if (templateUsingConfig == this.config && StringUtils.equals(templateTheme.getName(), name)) {
theme4currentTemplateMarkIcon.paintIcon(this, g, 176, 0);
}
}

63
designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeListPane.java

@ -2,14 +2,12 @@ package com.fr.design.mainframe.theme;
import com.fr.base.theme.TemplateTheme;
import com.fr.base.theme.TemplateThemeConfig;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.designer.IntervalConstants;
import com.fr.design.dialog.BasicPane;
import com.fr.design.event.ChangeEvent;
import com.fr.design.event.ChangeListener;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.module.ModuleContext;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
@ -22,7 +20,6 @@ import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
/**
* @author Starryi
@ -33,12 +30,9 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
public static final int BLOCK_COUNT_ROW_LINE = 3;
public static final int BLOCK_GAP = IntervalConstants.INTERVAL_L1;
public static final int CONTENT_WIDTH = 630;
public static final int ASYNC_FETCH_THEME_THREAD_COUNT = 10;
private final ExecutorService asyncThemeFetcher =
ModuleContext.getExecutor().newFixedThreadPool(
10,
new NamedThreadFactory("TemplateThemeListPane")
);
private final AsyncThemeFetcher<T> asyncThemeFetcher;
protected final TemplateThemeConfig<T> config;
private final TemplateThemeProfilePane<T> profilePane;
@ -57,6 +51,7 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
this.config = config;
this.profilePane = profilePane;
this.contentListPane = new JPanel();
this.asyncThemeFetcher = new AsyncThemeFetcher<>(ASYNC_FETCH_THEME_THREAD_COUNT, config);
initializePane();
}
@ -100,7 +95,7 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
}
private TemplateThemeBlock<T> createNewTemplateThemeBlock(String name) {
final TemplateThemeBlock<T> block = new TemplateThemeBlock<>(name, config, profilePane, asyncThemeFetcher);
final TemplateThemeBlock<T> block = new TemplateThemeBlock<>(name, config, profilePane);
block.addClickListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
@ -108,6 +103,19 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
setSelectedBlock(block);
}
});
asyncThemeFetcher.submit(name, new AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter<T>() {
@Override
public void beforeCachedFetch() {
super.beforeCachedFetch();
block.setTheme(null);
}
@Override
public void afterCachedFetch(T theme) {
super.afterCachedFetch(theme);
block.setTheme(theme);
}
});
return block;
}
@ -128,6 +136,10 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
}
}
private void asyncFetchTheme(String themeName) {
asyncThemeFetcher.submit(themeName, new AsyncThemeListItemFetchCallback(themeName));
}
@Override
protected String title4PopupWindow() {
return null;
@ -142,21 +154,22 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
themeConfigChangeListener = new TemplateThemeConfig.ThemeConfigChangeListener() {
@Override
public void onThemeConfigChanged(TemplateThemeConfig.ThemeConfigEvent event) {
String themeName = event.themName;
TemplateThemeBlock<T> existingBlock = blockCache.get(event.themName);
switch (event.action) {
case DEFAULT_THEME_4_NEW_TEMPLATE_UPDATE: {
if (block4newTemplate != null) {
block4newTemplate.fetchTheme();
block4newTemplate.repaint();
}
if (existingBlock != null) {
existingBlock.fetchTheme();
existingBlock.repaint();
}
block4newTemplate = existingBlock;
break;
}
case UPDATE: {
if (existingBlock != null) {
existingBlock.fetchTheme();
asyncFetchTheme(themeName);
}
break;
}
@ -176,6 +189,7 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
if (existingBlock == null) {
// TODO 这里是否还能继续优化?
fillContentListPane();
asyncFetchTheme(themeName);
validate();
repaint();
}
@ -198,4 +212,29 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
public void stopAsyncFetchTheme() {
asyncThemeFetcher.shutdown();
}
private class AsyncThemeListItemFetchCallback extends AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter<T> {
private final String themeName;
public AsyncThemeListItemFetchCallback(String themeName) {
this.themeName = themeName;
}
@Override
public void beforeCachedFetch() {
super.beforeCachedFetch();
TemplateThemeBlock<T> block = blockCache.get(themeName);
if (block != null) {
block.setTheme(null);
}
}
@Override
public void afterCachedFetch(T theme) {
super.afterCachedFetch(theme);
TemplateThemeBlock<T> block = blockCache.get(themeName);
if (block != null) {
block.setTheme(theme);
}
}
}
}

40
designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeManagePane.java

@ -58,6 +58,8 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
private final TemplateThemeListPane<T> themeListPane;
private final TemplateThemeProfilePane<T> profilePane;
private final AsyncThemeFetcher<T> asyncThemeFetcher;
public static TemplateThemeManagePane<FormTheme> createFormThemesManagerPane() {
FormThemeConfig config = FormThemeConfig.getInstance();
FormThemeProfilePane editPane = new FormThemeProfilePane(config);
@ -76,6 +78,7 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
this.themeListPane = new TemplateThemeListPane<>(config, profilePane);
this.removeAction = new RemoveThemeAction(false);
this.setTheme4NewTemplateButton = new UIButton(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Default_Setting"));
this.asyncThemeFetcher = new AsyncThemeFetcher<>(1, config);
initializePane();
}
@ -167,9 +170,9 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
setTheme4NewTemplateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
T style = themeListPane.getSelectedTheme();
if (style != null) {
config.setThemeName4NewTemplate(style.getName());
T theme = themeListPane.getSelectedTheme();
if (theme != null) {
config.setThemeName4NewTemplate(theme.getName());
}
}
});
@ -188,8 +191,8 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
MenuDef menuDef = new MenuDef(Toolkit.i18nText("Fine-Design_Basic_Action_Add"));
menuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH);
menuDef.setRePaint(true);
menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Light_Theme"), config.cachedFetchLightTheme4New()));
menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Dark_Theme"), config.cachedFetchDarkTheme4New()));
menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Light_Theme"), config.getLightThemeName4New()));
menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Dark_Theme"), config.getDarkThemeName4New()));
return menuDef;
}
@ -211,6 +214,9 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
@Override
public void actionPerformed(ActionEvent e) {
T theme = TemplateThemeManagePane.this.themeListPane.getSelectedTheme();
if (theme == null) {
return;
}
int result = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this),
Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Delete_Tip", theme.getName()),
Toolkit.i18nText("Fine-Design_Basic_Delete"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
@ -226,20 +232,35 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
}
private class AddThemeAction extends UpdateAction {
private final T theme4New;
private T prototypeTheme;
public AddThemeAction(String name, T theme4New) {
public AddThemeAction(String name, String prototypeThemeName) {
setName(name);
setMnemonic('R');
this.theme4New = theme4New;
asyncThemeFetcher.submit(prototypeThemeName, new AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter<T>() {
@Override
public void beforeCachedFetch() {
super.beforeCachedFetch();
prototypeTheme = null;
}
@Override
public void afterCachedFetch(T theme) {
super.afterCachedFetch(theme);
prototypeTheme = theme;
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
if (prototypeTheme == null) {
return;
}
Window parent = SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this);
TemplateThemeProfileDialog<T> profileDialog = new TemplateThemeProfileDialog<>(parent, profilePane);
try {
T theme = (T) theme4New.clone();
T theme = (T) prototypeTheme.clone();
theme.setName(StringUtils.EMPTY);
theme.setMutable(true);
theme.setRemovable(true);
@ -285,6 +306,7 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
}
public void stopAsyncFetchTheme() {
asyncThemeFetcher.shutdown();
themeListPane.stopAsyncFetchTheme();
}
}
Loading…
Cancel
Save