Browse Source

Merge pull request #759 in DESIGN/design from ~JEO/report-design:persist/10.0 to persist/10.0

* commit 'baacba086ca8f2532b4f31f15b7cfdf8899098dc':
  MOBILE-19684 同时安装顶部参数插件和导航参数插件时设计器显示重复值
  REPORT-14515 环境切换后模板另存面板没有刷新
  REPORT-13202 包含插件控件的模板切换环境后存储出错
  REPORT-14020 可以重复打开设计器 调试的代码上次误传了
  记录次数bugfix
  REPORT-14022 【难还原】最新的29号release,莫名其妙的卡住很久,后台百分百的cpu占用 合并发送,去重;每次query 200条,放入内存,发送成功再进行新的请求 同步更改到final
persist/10.0
Kara 6 years ago
parent
commit
04741fbbf0
  1. 2
      designer-base/src/main/java/com/fr/design/DesignModelAdapter.java
  2. 84
      designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java
  3. 10
      designer-base/src/main/java/com/fr/design/mainframe/AbstractAppProvider.java
  4. 68
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  5. 63
      designer-base/src/main/java/com/fr/design/mainframe/JTemplateFactory.java
  6. 106
      designer-base/src/main/java/com/fr/file/StashedFILE.java
  7. 10
      designer-form/src/main/java/com/fr/design/widget/ui/designer/mobile/ParaMobileDefinePane.java
  8. 6
      designer-realize/src/main/java/com/fr/design/mainframe/app/DesignerAppActivator.java
  9. 61
      designer-realize/src/main/java/com/fr/start/module/DesignerStartup.java

2
designer-base/src/main/java/com/fr/design/DesignModelAdapter.java

@ -134,7 +134,7 @@ public abstract class DesignModelAdapter<T extends BaseBook, S extends JTemplate
*/ */
@Deprecated @Deprecated
public Parameter[] getReportParameters() { public Parameter[] getReportParameters() {
return getTableDataParameters(); return getTemplateParameters();
} }
/** /**

84
designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java

@ -1,6 +1,7 @@
package com.fr.design.file; package com.fr.design.file;
import com.fr.base.chart.chartdata.CallbackEvent; import com.fr.base.chart.chartdata.CallbackEvent;
import com.fr.base.io.BaseBook;
import com.fr.design.DesignerEnvManager; import com.fr.design.DesignerEnvManager;
import com.fr.design.base.mode.DesignModeContext; import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.DesignTableDataManager;
@ -8,20 +9,25 @@ import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.JTemplateFactory;
import com.fr.design.mainframe.JVirtualTemplate; import com.fr.design.mainframe.JVirtualTemplate;
import com.fr.design.module.DesignModuleFactory; import com.fr.design.module.DesignModuleFactory;
import com.fr.file.FILE; import com.fr.file.FILE;
import com.fr.file.FileNodeFILE; import com.fr.file.FileNodeFILE;
import com.fr.file.StashedFILE;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.stable.CoreConstants; import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.io.FilenameUtils; import com.fr.third.org.apache.commons.io.FilenameUtils;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map;
/** /**
* 历史模板缓存 * 历史模板缓存
@ -305,4 +311,82 @@ public class HistoryTemplateListCache implements CallbackEvent {
} }
return true; return true;
} }
/**
* 切换环境时暂存打开的模板内容key 是在历史中的indexvalue 是模板xml 内容byte[]
*/
private Map<Integer, FILE> stashFILEMap;
/**
* 切换环境前将正在编辑的模板暂存起来并且在新环境中重新读取一遍暂存的不是模板文件的内容而是模板对象的内容
* <p>
* 防止新环境加载到的同名 Class 和模板对象中的 Class 不一致在新环境存储失败
*
* @see HistoryTemplateListCache#load()
*/
public void stash() {
FineLoggerFactory.getLogger().info("Env Change Template Stashing...");
if (stashFILEMap == null) {
stashFILEMap = new HashMap<Integer, FILE>();
} else {
stashFILEMap.clear();
}
int size = historyList.size();
for (int i = 0; i < size; i++) {
JTemplate<?, ?> template = historyList.get(i);
FILE file = template.getEditingFILE();
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BaseBook target = template.getTarget();
if (target != null) {
target.export(outputStream);
stashFILEMap.put(i, new StashedFILE(file, outputStream.toByteArray()));
}
// 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
FineLoggerFactory.getLogger().info("Env Change Template Stashed.");
}
/**
* 切换环境前将正在编辑的模板暂存起来后在新环境重新读取一遍
* <p>
* 防止新环境加载到的同名 Class 和模板对象中的 Class 不一致在新环境存储失败
*
* @see HistoryTemplateListCache#stash()
*/
public void load() {
FineLoggerFactory.getLogger().info("Env Change Template Loading...");
if (stashFILEMap != null && stashFILEMap.size() != 0) {
int size = historyList.size();
for (int i = 0; i < size; i++) {
try {
FILE stashedFile = stashFILEMap.get(i);
// 可能有模板 stash 失败的情况,在 load 的时候不更新它
// 或者这个模板是被模板内存优化功能处理过的,不用处理
if (stashedFile == null) {
continue;
}
JTemplate<?, ?> template = JTemplateFactory.createJTemplate(stashedFile);
if (template != null) {
historyList.set(i, template);
// 替换当前正在编辑的模板,使用添加并激活的方式,以便使用统一的入口来处理监听事件
if (isCurrentEditingFile(template.getPath())) {
DesignerContext.getDesignerFrame().addAndActivateJTemplate(template);
setCurrentEditingTemplate(template);
FineLoggerFactory.getLogger().info("Env Change Current Editing Template.");
}
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
stashFILEMap.clear();
MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList);
MutilTempalteTabPane.getInstance().repaint();
}
FineLoggerFactory.getLogger().info("Env Change Template Loaded.");
}
} }

10
designer-base/src/main/java/com/fr/design/mainframe/AbstractAppProvider.java

@ -8,7 +8,7 @@ import com.fr.stable.fun.mark.API;
* Created by Administrator on 2016/3/17/0017. * Created by Administrator on 2016/3/17/0017.
*/ */
@API(level = App.CURRENT_LEVEL) @API(level = App.CURRENT_LEVEL)
public abstract class AbstractAppProvider<T extends IOFile> extends AbstractProvider implements App{ public abstract class AbstractAppProvider<T extends IOFile> extends AbstractProvider implements App {
public int currentAPILevel() { public int currentAPILevel() {
return CURRENT_LEVEL; return CURRENT_LEVEL;
@ -21,12 +21,12 @@ public abstract class AbstractAppProvider<T extends IOFile> extends AbstractProv
@Override @Override
public void process() { public void process() {
DesignerFrame.registApp(this); JTemplateFactory.register(this);
} }
@Override @Override
public void undo() { public void undo() {
DesignerFrame.removeApp(this); JTemplateFactory.remove(this);
} }
} }

68
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java

@ -52,7 +52,6 @@ import com.fr.plugin.injectable.PluginModule;
import com.fr.plugin.manage.PluginFilter; import com.fr.plugin.manage.PluginFilter;
import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEvent;
import com.fr.plugin.observer.PluginEventListener; import com.fr.plugin.observer.PluginEventListener;
import com.fr.stable.CoreConstants;
import com.fr.stable.OperatingSystem; import com.fr.stable.OperatingSystem;
import com.fr.stable.ProductConstants; import com.fr.stable.ProductConstants;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
@ -115,11 +114,9 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
private static final int MENU_HEIGHT = 26; private static final int MENU_HEIGHT = 26;
private static final Integer SECOND_LAYER = new Integer(100); private static final Integer SECOND_LAYER = 100;
private static final Integer TOP_LAYER = new Integer((200)); private static final Integer TOP_LAYER = 200;
private static java.util.List<App<?>> appList = new java.util.ArrayList<App<?>>();
private List<DesignerOpenedListener> designerOpenedListenerList = new ArrayList<>(); private List<DesignerOpenedListener> designerOpenedListenerList = new ArrayList<>();
@ -326,7 +323,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
this.progressDialog = new ProgressDialog(this); this.progressDialog = new ProgressDialog(this);
} }
public void closeAuthorityEditing(){ public void closeAuthorityEditing() {
DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.NORMAL); DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.NORMAL);
WestRegionContainerPane.getInstance().replaceDownPane( WestRegionContainerPane.getInstance().replaceDownPane(
TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter())); TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()));
@ -342,19 +339,22 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
* 注册app. * 注册app.
* *
* @param app 注册app. * @param app 注册app.
* @deprecated use {@link JTemplateFactory#register(App)} instead
*/ */
@Deprecated
public static void registApp(App<?> app) { public static void registApp(App<?> app) {
JTemplateFactory.register(app);
if (app != null) {
appList.add(app);
}
} }
/**
* 移除app
*
* @param app app
* @deprecated use {@link JTemplateFactory#remove(App)} instead
*/
@Deprecated
public static void removeApp(App<?> app) { public static void removeApp(App<?> app) {
JTemplateFactory.remove(app);
if (app != null) {
appList.remove(app);
}
} }
/** /**
@ -1013,39 +1013,17 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
*/ */
private void openFile(FILE tplFile) { private void openFile(FILE tplFile) {
String fileName = tplFile.getName(); JTemplate jt = JTemplateFactory.createJTemplate(tplFile);
int indexOfLastDot = fileName.lastIndexOf(CoreConstants.DOT); if (jt == null) {
if (indexOfLastDot < 0) {
return; return;
} }
String fileExtention = fileName.substring(indexOfLastDot + 1); // 新的form不往前兼容
for (int i = 0, len = appList.size(); i < len; i++) { if (inValidDesigner(jt)) {
App<?> app = appList.get(i); this.addAndActivateJTemplate();
String[] defaultAppExtentions = app.defaultExtensions(); MutilTempalteTabPane.getInstance().setTemTemplate(
boolean opened = false; HistoryTemplateListPane.getInstance().getCurrentEditingTemplate());
for (int j = 0; j < defaultAppExtentions.length; j++) { } else {
if (defaultAppExtentions[j].equalsIgnoreCase(fileExtention)) { activeTemplate(jt);
// 不要catch
JTemplate jt = app.openTemplate(tplFile);
if (jt == null) {
return;
}
// 新的form不往前兼容
if (inValidDesigner(jt)) {
this.addAndActivateJTemplate();
MutilTempalteTabPane.getInstance().setTemTemplate(
HistoryTemplateListPane.getInstance().getCurrentEditingTemplate());
} else {
activeTemplate(jt);
}
opened = true;
break;
}
}
if (opened) {
break;
}
} }
} }

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

@ -0,0 +1,63 @@
package com.fr.design.mainframe;
import com.fr.file.FILE;
import com.fr.stable.CoreConstants;
import com.fr.third.javax.annotation.Nonnull;
import com.fr.third.javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public final class JTemplateFactory {
private static final List<App<?>> ALL_APP = new ArrayList<App<?>>();
private JTemplateFactory() {
}
/**
* 生成设计器编辑模板对象
*
* @param file 包含了模板名称类型以及内容的文件
* @return 设计器编辑的模板对象
*/
@Nullable
public static JTemplate<?, ?> createJTemplate(@Nonnull FILE file) {
String fileName = file.getName();
int indexOfLastDot = fileName.lastIndexOf(CoreConstants.DOT);
if (indexOfLastDot < 0) {
return null;
}
String fileExtension = fileName.substring(indexOfLastDot + 1);
for (App<?> app : ALL_APP) {
String[] defaultAppExtensions = app.defaultExtensions();
for (String defaultAppExtension : defaultAppExtensions) {
if (defaultAppExtension.equalsIgnoreCase(fileExtension)) {
JTemplate<?, ?> jt = app.openTemplate(file);
if (jt != null) {
return jt;
}
}
}
}
return null;
}
/**
* 注册app.
*
* @param app 注册app.
*/
public static void register(App<?> app) {
if (app != null) {
ALL_APP.add(app);
}
}
public static void remove(App<?> app) {
if (app != null) {
ALL_APP.remove(app);
}
}
}

106
designer-base/src/main/java/com/fr/file/StashedFILE.java

@ -0,0 +1,106 @@
package com.fr.file;
import javax.swing.Icon;
import javax.transaction.NotSupportedException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 切换环境用于暂存的文件类型
*/
public class StashedFILE implements FILE {
private FILE file;
private byte[] content;
public StashedFILE(FILE file, byte[] content) {
this.file = file;
this.content = content;
}
@Override
public String prefix() {
return file.prefix();
}
@Override
public boolean isDirectory() {
return file.isDirectory();
}
@Override
public String getName() {
return file.getName();
}
@Override
public Icon getIcon() {
return file.getIcon();
}
@Override
public String getPath() {
return file.getPath();
}
@Override
public void setPath(String path) {
throw new UnsupportedOperationException();
}
@Override
public FILE getParent() {
throw new UnsupportedOperationException();
}
@Override
public FILE[] listFiles() {
throw new UnsupportedOperationException();
}
@Override
public boolean createFolder(String name) {
throw new UnsupportedOperationException();
}
@Override
public boolean mkfile() throws Exception {
throw new UnsupportedOperationException();
}
@Override
public boolean exists() {
return false;
}
@Override
public void closeTemplate() throws Exception {
// do nothing
}
@Override
public InputStream asInputStream() throws Exception {
return new ByteArrayInputStream(content);
}
@Override
public OutputStream asOutputStream() throws Exception {
throw new NotSupportedException();
}
@Override
public String getEnvFullName() {
return file.getEnvFullName();
}
@Override
public boolean isMemFile() {
return true;
}
@Override
public boolean isEnvFile() {
return false;
}
}

10
designer-form/src/main/java/com/fr/design/widget/ui/designer/mobile/ParaMobileDefinePane.java

@ -21,7 +21,6 @@ import com.fr.form.ui.container.WParameterLayout;
import com.fr.form.ui.container.WSortLayout; import com.fr.form.ui.container.WSortLayout;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.general.SiteCenter; import com.fr.general.SiteCenter;
import com.fr.json.JSONException;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.report.ExtraReportClassManager; import com.fr.report.ExtraReportClassManager;
import com.fr.report.fun.MobileParamStyleProvider; import com.fr.report.fun.MobileParamStyleProvider;
@ -109,9 +108,9 @@ public class ParaMobileDefinePane extends MobileWidgetDefinePane {
Item[] items = new Item[pluginCreators.size() + 1]; Item[] items = new Item[pluginCreators.size() + 1];
MobileParamStyleProvider provider = new DefaultMobileParamStyle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Default")); MobileParamStyleProvider provider = new DefaultMobileParamStyle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Default"));
items[0] = new Item(provider.descriptor(), provider); items[0] = new Item(provider.descriptor(), provider);
for (int i = 0; i < pluginCreators.size(); i++) { int i = 1;
provider = pluginCreators.iterator().next(); for (MobileParamStyleProvider mobileParamStyleProvider : pluginCreators) {
items[i + 1] = new Item(provider.descriptor(), provider); items[i++] = new Item(mobileParamStyleProvider.descriptor(), mobileParamStyleProvider);
} }
return items; return items;
} }
@ -161,6 +160,7 @@ public class ParaMobileDefinePane extends MobileWidgetDefinePane {
private UIComboBox getParamLocationComboBox() { private UIComboBox getParamLocationComboBox() {
items = getItems(); items = getItems();
UIComboBox paramLocationComoBox = new UIComboBox(items); UIComboBox paramLocationComoBox = new UIComboBox(items);
paramLocationComoBox.addItemListener(new ItemListener() { paramLocationComoBox.addItemListener(new ItemListener() {
@Override @Override
@ -218,7 +218,7 @@ public class ParaMobileDefinePane extends MobileWidgetDefinePane {
break; break;
} }
} }
} catch (JSONException e) { } catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e); FineLoggerFactory.getLogger().error(e.getMessage(), e);
} }
paramLocationComboBox.setSelectedIndex(index); paramLocationComboBox.setSelectedIndex(index);

6
designer-realize/src/main/java/com/fr/design/mainframe/app/DesignerAppActivator.java

@ -1,7 +1,7 @@
package com.fr.design.mainframe.app; package com.fr.design.mainframe.app;
import com.fr.design.mainframe.App; import com.fr.design.mainframe.App;
import com.fr.design.mainframe.DesignerFrame; import com.fr.design.mainframe.JTemplateFactory;
import com.fr.module.Activator; import com.fr.module.Activator;
import com.fr.module.extension.Prepare; import com.fr.module.extension.Prepare;
@ -17,7 +17,7 @@ public class DesignerAppActivator extends Activator implements Prepare {
List<App> appList = rightCollectMutable(App.KEY); List<App> appList = rightCollectMutable(App.KEY);
for (App app : appList) { for (App app : appList) {
DesignerFrame.registApp(app); JTemplateFactory.register(app);
} }
} }
@ -26,7 +26,7 @@ public class DesignerAppActivator extends Activator implements Prepare {
List<App> appList = rightCollectMutable(App.KEY); List<App> appList = rightCollectMutable(App.KEY);
for (App app : appList) { for (App app : appList) {
DesignerFrame.removeApp(app); JTemplateFactory.remove(app);
} }
} }

61
designer-realize/src/main/java/com/fr/start/module/DesignerStartup.java

@ -1,6 +1,7 @@
package com.fr.start.module; package com.fr.start.module;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
import com.fr.event.Event; import com.fr.event.Event;
import com.fr.event.Listener; import com.fr.event.Listener;
@ -28,13 +29,13 @@ public class DesignerStartup extends Activator {
@Override @Override
@Metrics @Metrics
public void start() { public void start() {
startSub(PreStartActivator.class); startSub(PreStartActivator.class);
//启动基础部分 //启动基础部分
startSub(BasicActivator.class); startSub(BasicActivator.class);
final String[] args = getModule().upFindSingleton(StartupArgs.class).get(); final String[] args = getModule().upFindSingleton(StartupArgs.class).get();
final Designer designer = new Designer(args); final Designer designer = new Designer(args);
startSub(DesignerWorkspaceProvider.class); startSub(DesignerWorkspaceProvider.class);
registerEnvListener(); registerEnvListener();
//启动env //启动env
@ -49,7 +50,7 @@ public class DesignerStartup extends Activator {
} }
}); });
service.submit(new Runnable() { service.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
@ -63,46 +64,64 @@ public class DesignerStartup extends Activator {
DesignerContext.getDesignerFrame().setVisible(true); DesignerContext.getDesignerFrame().setVisible(true);
//启动画面结束 //启动画面结束
SplashContext.getInstance().hide(); SplashContext.getInstance().hide();
DesignerContext.getDesignerFrame().getProgressDialog().setVisible(true); DesignerContext.getDesignerFrame().getProgressDialog().setVisible(true);
startSub(StartFinishActivator.class); startSub(StartFinishActivator.class);
FineRuntime.startFinish(); FineRuntime.startFinish();
} }
private void browserDemo() { private void browserDemo() {
if (getModule().leftFindSingleton(StartupArgs.class) != null && getModule().leftFindSingleton(StartupArgs.class).isDemo()) { if (getModule().leftFindSingleton(StartupArgs.class) != null && getModule().leftFindSingleton(StartupArgs.class).isDemo()) {
ServerStarter.browserDemoURL(); ServerStarter.browserDemoURL();
} }
} }
/** /**
* 切换环境时重新启动所有相关模块 * 注册切换环境前后事件监听
*/ */
private void registerEnvListener() { private void registerEnvListener() {
listenEvent(WorkspaceEvent.BeforeSwitch, new Listener<Workspace>() { /*切换环境前,关闭所有相关模块,最后执行*/
listenEvent(WorkspaceEvent.BeforeSwitch, new Listener<Workspace>(Integer.MIN_VALUE) {
@Override @Override
public void on(Event event, Workspace param) { public void on(Event event, Workspace current) {
getSub(EnvBasedModule.class).stop(); getSub(EnvBasedModule.class).stop();
} }
}); });
/*切换环境后,重新启动所有相关模块,最先执行*/
listenEvent(WorkspaceEvent.AfterSwitch, new Listener<Workspace>(Integer.MAX_VALUE) { listenEvent(WorkspaceEvent.AfterSwitch, new Listener<Workspace>(Integer.MAX_VALUE) {
@Override @Override
public void on(Event event, Workspace param) { public void on(Event event, Workspace current) {
getSub(EnvBasedModule.class).start(); getSub(EnvBasedModule.class).start();
ExecutorService service = Executors.newSingleThreadExecutor(); // 切换后的环境是本地环境才启动内置服务器
service.submit(new Runnable() { if (current.isLocal()) {
@Override ExecutorService service = Executors.newSingleThreadExecutor();
public void run() { service.submit(new Runnable() {
FineEmbedServer.start(); @Override
} public void run() {
}); FineEmbedServer.start();
service.shutdown(); }
});
service.shutdown();
}
}
});
/*切换环境前,存储一下打开的所有文件对象,要先于 关闭相关模块部分 被触发*/
listenEvent(WorkspaceEvent.BeforeSwitch, new Listener<Workspace>(Integer.MAX_VALUE) {
@Override
public void on(Event event, Workspace workspace) {
HistoryTemplateListCache.getInstance().stash();
}
});
/*切换环境后,装载一下打开的所有文件对象,优先级低于默认优先级,要后于 启动相关模块部分 被触发*/
listenEvent(WorkspaceEvent.AfterSwitch, new Listener<Workspace>(Integer.MIN_VALUE) {
@Override
public void on(Event event, Workspace workspace) {
HistoryTemplateListCache.getInstance().load();
} }
}); });
} }

Loading…
Cancel
Save