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 boolean hovering = false;
private MouseAdapter clickListener; private MouseAdapter clickListener;
private final ExecutorService asyncThemeFetcher;
public TemplateThemeBlock(String name, public TemplateThemeBlock(String name,
TemplateThemeConfig<T> config, TemplateThemeConfig<T> config,
TemplateThemeProfilePane<T> profilePane, TemplateThemeProfilePane<T> profilePane) {
ExecutorService asyncThemeFetcher) {
this.name = name; this.name = name;
this.config = config; this.config = config;
this.profilePane = profilePane; this.profilePane = profilePane;
this.asyncThemeFetcher = asyncThemeFetcher;
initializePane(); initializePane();
addMouseListener(new MouseAdapter() { addMouseListener(new MouseAdapter() {
@ -91,8 +88,6 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
repaint(); repaint();
} }
}); });
fetchTheme();
} }
private void initializePane() { private void initializePane() {
@ -119,6 +114,21 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
add(infoPane, BorderLayout.SOUTH); 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() { public T getTheme() {
return this.theme; return this.theme;
} }
@ -166,48 +176,6 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
profileDialog.setVisible(true); 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 @Override
public void paint(Graphics g) { public void paint(Graphics g) {
super.paint(g); super.paint(g);
@ -215,7 +183,7 @@ public class TemplateThemeBlock<T extends TemplateTheme> extends JPanel {
if (template != null) { if (template != null) {
TemplateThemeConfig<? extends TemplateTheme> templateUsingConfig = template.getUsingTemplateThemeConfig(); TemplateThemeConfig<? extends TemplateTheme> templateUsingConfig = template.getUsingTemplateThemeConfig();
TemplateTheme templateTheme = template.getTemplateTheme(); 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); 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.TemplateTheme;
import com.fr.base.theme.TemplateThemeConfig; import com.fr.base.theme.TemplateThemeConfig;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.designer.IntervalConstants; import com.fr.design.designer.IntervalConstants;
import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.BasicPane;
import com.fr.design.event.ChangeEvent; import com.fr.design.event.ChangeEvent;
import com.fr.design.event.ChangeListener; import com.fr.design.event.ChangeListener;
import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.module.ModuleContext;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
@ -22,7 +20,6 @@ import java.awt.event.MouseEvent;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutorService;
/** /**
* @author Starryi * @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_COUNT_ROW_LINE = 3;
public static final int BLOCK_GAP = IntervalConstants.INTERVAL_L1; public static final int BLOCK_GAP = IntervalConstants.INTERVAL_L1;
public static final int CONTENT_WIDTH = 630; public static final int CONTENT_WIDTH = 630;
public static final int ASYNC_FETCH_THEME_THREAD_COUNT = 10;
private final ExecutorService asyncThemeFetcher = private final AsyncThemeFetcher<T> asyncThemeFetcher;
ModuleContext.getExecutor().newFixedThreadPool(
10,
new NamedThreadFactory("TemplateThemeListPane")
);
protected final TemplateThemeConfig<T> config; protected final TemplateThemeConfig<T> config;
private final TemplateThemeProfilePane<T> profilePane; private final TemplateThemeProfilePane<T> profilePane;
@ -57,6 +51,7 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
this.config = config; this.config = config;
this.profilePane = profilePane; this.profilePane = profilePane;
this.contentListPane = new JPanel(); this.contentListPane = new JPanel();
this.asyncThemeFetcher = new AsyncThemeFetcher<>(ASYNC_FETCH_THEME_THREAD_COUNT, config);
initializePane(); initializePane();
} }
@ -100,7 +95,7 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
} }
private TemplateThemeBlock<T> createNewTemplateThemeBlock(String name) { 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() { block.addClickListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
@ -108,6 +103,19 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
setSelectedBlock(block); 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; 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 @Override
protected String title4PopupWindow() { protected String title4PopupWindow() {
return null; return null;
@ -142,21 +154,22 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
themeConfigChangeListener = new TemplateThemeConfig.ThemeConfigChangeListener() { themeConfigChangeListener = new TemplateThemeConfig.ThemeConfigChangeListener() {
@Override @Override
public void onThemeConfigChanged(TemplateThemeConfig.ThemeConfigEvent event) { public void onThemeConfigChanged(TemplateThemeConfig.ThemeConfigEvent event) {
String themeName = event.themName;
TemplateThemeBlock<T> existingBlock = blockCache.get(event.themName); TemplateThemeBlock<T> existingBlock = blockCache.get(event.themName);
switch (event.action) { switch (event.action) {
case DEFAULT_THEME_4_NEW_TEMPLATE_UPDATE: { case DEFAULT_THEME_4_NEW_TEMPLATE_UPDATE: {
if (block4newTemplate != null) { if (block4newTemplate != null) {
block4newTemplate.fetchTheme(); block4newTemplate.repaint();
} }
if (existingBlock != null) { if (existingBlock != null) {
existingBlock.fetchTheme(); existingBlock.repaint();
} }
block4newTemplate = existingBlock; block4newTemplate = existingBlock;
break; break;
} }
case UPDATE: { case UPDATE: {
if (existingBlock != null) { if (existingBlock != null) {
existingBlock.fetchTheme(); asyncFetchTheme(themeName);
} }
break; break;
} }
@ -176,6 +189,7 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
if (existingBlock == null) { if (existingBlock == null) {
// TODO 这里是否还能继续优化? // TODO 这里是否还能继续优化?
fillContentListPane(); fillContentListPane();
asyncFetchTheme(themeName);
validate(); validate();
repaint(); repaint();
} }
@ -198,4 +212,29 @@ public class TemplateThemeListPane<T extends TemplateTheme> extends BasicPane {
public void stopAsyncFetchTheme() { public void stopAsyncFetchTheme() {
asyncThemeFetcher.shutdown(); 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 TemplateThemeListPane<T> themeListPane;
private final TemplateThemeProfilePane<T> profilePane; private final TemplateThemeProfilePane<T> profilePane;
private final AsyncThemeFetcher<T> asyncThemeFetcher;
public static TemplateThemeManagePane<FormTheme> createFormThemesManagerPane() { public static TemplateThemeManagePane<FormTheme> createFormThemesManagerPane() {
FormThemeConfig config = FormThemeConfig.getInstance(); FormThemeConfig config = FormThemeConfig.getInstance();
FormThemeProfilePane editPane = new FormThemeProfilePane(config); FormThemeProfilePane editPane = new FormThemeProfilePane(config);
@ -76,6 +78,7 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
this.themeListPane = new TemplateThemeListPane<>(config, profilePane); this.themeListPane = new TemplateThemeListPane<>(config, profilePane);
this.removeAction = new RemoveThemeAction(false); this.removeAction = new RemoveThemeAction(false);
this.setTheme4NewTemplateButton = new UIButton(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Default_Setting")); this.setTheme4NewTemplateButton = new UIButton(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Default_Setting"));
this.asyncThemeFetcher = new AsyncThemeFetcher<>(1, config);
initializePane(); initializePane();
} }
@ -167,9 +170,9 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
setTheme4NewTemplateButton.addActionListener(new ActionListener() { setTheme4NewTemplateButton.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
T style = themeListPane.getSelectedTheme(); T theme = themeListPane.getSelectedTheme();
if (style != null) { if (theme != null) {
config.setThemeName4NewTemplate(style.getName()); 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 menuDef = new MenuDef(Toolkit.i18nText("Fine-Design_Basic_Action_Add"));
menuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH); menuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH);
menuDef.setRePaint(true); 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_Light_Theme"), config.getLightThemeName4New()));
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_Dark_Theme"), config.getDarkThemeName4New()));
return menuDef; return menuDef;
} }
@ -211,6 +214,9 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
T theme = TemplateThemeManagePane.this.themeListPane.getSelectedTheme(); T theme = TemplateThemeManagePane.this.themeListPane.getSelectedTheme();
if (theme == null) {
return;
}
int result = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this), int result = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this),
Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Delete_Tip", theme.getName()), 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); 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 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); setName(name);
setMnemonic('R'); 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 @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (prototypeTheme == null) {
return;
}
Window parent = SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this); Window parent = SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this);
TemplateThemeProfileDialog<T> profileDialog = new TemplateThemeProfileDialog<>(parent, profilePane); TemplateThemeProfileDialog<T> profileDialog = new TemplateThemeProfileDialog<>(parent, profilePane);
try { try {
T theme = (T) theme4New.clone(); T theme = (T) prototypeTheme.clone();
theme.setName(StringUtils.EMPTY); theme.setName(StringUtils.EMPTY);
theme.setMutable(true); theme.setMutable(true);
theme.setRemovable(true); theme.setRemovable(true);
@ -285,6 +306,7 @@ public class TemplateThemeManagePane<T extends TemplateTheme> extends BasicPane
} }
public void stopAsyncFetchTheme() { public void stopAsyncFetchTheme() {
asyncThemeFetcher.shutdown();
themeListPane.stopAsyncFetchTheme(); themeListPane.stopAsyncFetchTheme();
} }
} }
Loading…
Cancel
Save