|
|
|
package com.fr.design.file;
|
|
|
|
|
|
|
|
import com.fr.base.chart.chartdata.CallbackEvent;
|
|
|
|
import com.fr.base.io.BaseBook;
|
|
|
|
import com.fr.design.DesignerEnvManager;
|
|
|
|
import com.fr.design.base.mode.DesignModeContext;
|
|
|
|
import com.fr.design.base.mode.DesignerMode;
|
|
|
|
import com.fr.design.data.DesignTableDataManager;
|
|
|
|
import com.fr.design.file.filter.ClassFilter;
|
|
|
|
import com.fr.design.i18n.Toolkit;
|
|
|
|
import com.fr.design.mainframe.DesignerContext;
|
|
|
|
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
|
|
|
|
import com.fr.design.mainframe.JTemplate;
|
|
|
|
import com.fr.design.mainframe.JVirtualTemplate;
|
|
|
|
import com.fr.design.ui.util.UIUtil;
|
|
|
|
import com.fr.file.FILE;
|
|
|
|
import com.fr.file.FileNodeFILE;
|
|
|
|
import com.fr.general.ComparatorUtils;
|
|
|
|
import com.fr.invoke.ClassHelper;
|
|
|
|
import com.fr.log.FineLoggerFactory;
|
|
|
|
import com.fr.plugin.context.PluginContext;
|
|
|
|
import com.fr.plugin.manage.PluginManager;
|
|
|
|
import com.fr.stable.CoreConstants;
|
|
|
|
import com.fr.stable.StringUtils;
|
|
|
|
import com.fr.third.org.apache.commons.io.FilenameUtils;
|
|
|
|
|
|
|
|
import javax.swing.SwingWorker;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.ListIterator;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 历史模板缓存
|
|
|
|
*
|
|
|
|
* @see HistoryTemplateListPane
|
|
|
|
*/
|
|
|
|
public class HistoryTemplateListCache implements CallbackEvent {
|
|
|
|
|
|
|
|
//最大保存内存中面板数,为0时关闭优化内存
|
|
|
|
private static final int DEAD_LINE = DesignerEnvManager.getEnvManager().getCachingTemplateLimit();
|
|
|
|
private List<JTemplate<?, ?>> historyList;
|
|
|
|
private JTemplate<?, ?> editingTemplate;
|
|
|
|
private SwingWorker<Boolean, Void> stashWorker;
|
|
|
|
|
|
|
|
public static HistoryTemplateListCache getInstance() {
|
|
|
|
return Holder.INSTANCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static class Holder {
|
|
|
|
private static final HistoryTemplateListCache INSTANCE = new HistoryTemplateListCache();
|
|
|
|
}
|
|
|
|
|
|
|
|
private HistoryTemplateListCache() {
|
|
|
|
historyList = new ArrayList<>();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 关闭选择的文件
|
|
|
|
*
|
|
|
|
* @param selected 选择的
|
|
|
|
*/
|
|
|
|
public void closeSelectedReport(JTemplate<?, ?> selected) {
|
|
|
|
DesignTableDataManager.closeTemplate(selected);
|
|
|
|
//直接关闭模板的时候(当且仅当设计器tab上只剩一个模板)退出权限编辑
|
|
|
|
if (DesignModeContext.isAuthorityEditing() && historyList.size() <= 1) {
|
|
|
|
DesignModeContext.switchTo(DesignerMode.NORMAL);
|
|
|
|
}
|
|
|
|
if (contains(selected) == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
selected.fireJTemplateClosed();
|
|
|
|
selected.stopEditing();
|
|
|
|
try {
|
|
|
|
historyList.remove(contains(selected));
|
|
|
|
selected.getEditingFILE().closeTemplate();
|
|
|
|
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Closed_Warn_Text", selected.getEditingFILE().getName()));
|
|
|
|
MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FineLoggerFactory.getLogger().error(e.getMessage(), e);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 临时关闭选择的文件
|
|
|
|
*
|
|
|
|
* @param selected 选择的
|
|
|
|
*/
|
|
|
|
public void closeVirtualSelectedReport(JTemplate<?, ?> selected) {
|
|
|
|
DesignTableDataManager.closeTemplate(selected);
|
|
|
|
if (contains(selected) == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
selected.fireJTemplateClosed();
|
|
|
|
selected.stopEditing();
|
|
|
|
try {
|
|
|
|
selected.getEditingFILE().closeTemplate();
|
|
|
|
} catch (Exception e) {
|
|
|
|
FineLoggerFactory.getLogger().error(e.getMessage(), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public JTemplate<?, ?> getCurrentEditingTemplate() {
|
|
|
|
return this.editingTemplate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param jt jt
|
|
|
|
* @see DesignerFrameFileDealerPane#setCurrentEditingTemplate(JTemplate)
|
|
|
|
*/
|
|
|
|
public void setCurrentEditingTemplate(JTemplate<?, ?> jt) {
|
|
|
|
this.editingTemplate = jt;
|
|
|
|
//如果当前历史面板中没有
|
|
|
|
|
|
|
|
if (contains(jt) == -1) {
|
|
|
|
addHistory();
|
|
|
|
}
|
|
|
|
MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList);
|
|
|
|
//设置tab栏为当前选中的那一栏
|
|
|
|
if (editingTemplate != null) {
|
|
|
|
MutilTempalteTabPane.getInstance().setSelectedIndex(contains(jt));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 添加历史记录
|
|
|
|
*/
|
|
|
|
public void addHistory() {
|
|
|
|
if (editingTemplate == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DesignerEnvManager.getEnvManager().addRecentOpenedFilePath(editingTemplate.getPath());
|
|
|
|
historyList.add(editingTemplate);
|
|
|
|
closeOverLineTemplate();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public List<JTemplate<?, ?>> getHistoryList() {
|
|
|
|
return historyList;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 清空历史记录
|
|
|
|
*/
|
|
|
|
public void removeAllHistory() {
|
|
|
|
historyList.clear();
|
|
|
|
this.editingTemplate = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getHistoryCount() {
|
|
|
|
return historyList.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public JTemplate<?, ?> get(int index) {
|
|
|
|
if (index > historyList.size() - 1 || index < 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
Collections.reverse(historyList);
|
|
|
|
JTemplate<?, ?> select = historyList.get(index);
|
|
|
|
Collections.reverse(historyList);
|
|
|
|
return select;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public JTemplate<?, ?> getTemplate(int index) {
|
|
|
|
return historyList.get(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取模板的index
|
|
|
|
*
|
|
|
|
* @param jt 模板
|
|
|
|
* @return 位置
|
|
|
|
*/
|
|
|
|
public int contains(JTemplate<?, ?> jt) {
|
|
|
|
return contains(jt, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int contains(FILE file) {
|
|
|
|
return contains(null, file);
|
|
|
|
}
|
|
|
|
|
|
|
|
private int contains(JTemplate jt, FILE file) {
|
|
|
|
FILE item = null;
|
|
|
|
if (jt != null) {
|
|
|
|
item = jt.getEditingFILE();
|
|
|
|
} else {
|
|
|
|
item = file;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < historyList.size(); i++) {
|
|
|
|
if (ComparatorUtils.equals(historyList.get(i).getEditingFILE(), item)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 判断是否打开过该模板
|
|
|
|
* 由于切换环境不会关闭模板,可能存在同名的模板,所以该方法不能准确找到所选的模板,
|
|
|
|
*
|
|
|
|
* @param filename 文件名
|
|
|
|
* @return 文件位置
|
|
|
|
* @deprecated use HistoryTemplateListCache#contains(com.fr.design.mainframe.JTemplate) instead
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
public int contains(String filename) {
|
|
|
|
for (int i = 0; i < historyList.size(); i++) {
|
|
|
|
String historyPath = historyList.get(i).getPath();
|
|
|
|
//文件路径和历史路径都是 reportlets/xxx/xxx/xxx/xx.suffix
|
|
|
|
if (filename.equals(historyPath)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 是否是当前编辑的文件
|
|
|
|
*
|
|
|
|
* @param filename 文件名
|
|
|
|
* @return 是则返回TRUE
|
|
|
|
*/
|
|
|
|
public boolean isCurrentEditingFile(String filename) {
|
|
|
|
String editingFileName = editingTemplate.getPath();
|
|
|
|
return ComparatorUtils.equals(filename, editingFileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void callback() {
|
|
|
|
getCurrentEditingTemplate().repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 打开new模板的同时关闭old模板,优先关已保存的、先打开的
|
|
|
|
*/
|
|
|
|
public void closeOverLineTemplate() {
|
|
|
|
int size = historyList.size();
|
|
|
|
int vCount = size - DEAD_LINE;
|
|
|
|
if (DEAD_LINE == 0 || vCount <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < vCount; i++) {
|
|
|
|
JTemplate overTemplate = historyList.get(i);
|
|
|
|
|
|
|
|
if (overTemplate.getEditingFILE().exists() && overTemplate.isALLSaved() && overTemplate != editingTemplate) {
|
|
|
|
closeVirtualSelectedReport(overTemplate);
|
|
|
|
historyList.set(i, new JVirtualTemplate(overTemplate.getEditingFILE()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void deleteFile(FileNodeFILE file) {
|
|
|
|
boolean isDir = file.isDirectory();
|
|
|
|
|
|
|
|
String suffix = isDir ? CoreConstants.SEPARATOR : StringUtils.EMPTY;
|
|
|
|
|
|
|
|
// path like reportlets/xx/xxx/xxx
|
|
|
|
String path = file.getPath() + suffix;
|
|
|
|
|
|
|
|
ListIterator<JTemplate<?, ?>> iterator = historyList.listIterator();
|
|
|
|
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
JTemplate<?, ?> template = iterator.next();
|
|
|
|
String tPath = template.getPath();
|
|
|
|
if (isDir ? tPath.startsWith(path) : tPath.equals(path)) {
|
|
|
|
int size = getHistoryCount();
|
|
|
|
iterator.remove();
|
|
|
|
int index = iterator.nextIndex();
|
|
|
|
if (size == index + 1 && index > 0) {
|
|
|
|
//如果删除的是后一个Tab,则定位到前一个
|
|
|
|
MutilTempalteTabPane.getInstance().setSelectedIndex(index - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//如果打开过,则删除,实时刷新多tab面板
|
|
|
|
int openFileCount = getHistoryCount();
|
|
|
|
if (openFileCount == 0) {
|
|
|
|
DesignerContext.getDesignerFrame().addAndActivateJTemplate();
|
|
|
|
}
|
|
|
|
|
|
|
|
JTemplate selectedFile = MutilTempalteTabPane.getInstance().getSelectedFile();
|
|
|
|
if (!isCurrentEditingFile(selectedFile.getPath())) {
|
|
|
|
//如果此时面板上的实时刷新的selectedIndex得到的和历史的不一样
|
|
|
|
DesignerContext.getDesignerFrame().activateJTemplate(selectedFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
MutilTempalteTabPane.getInstance().repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public boolean rename(FILE tplFile, String from, String to) {
|
|
|
|
boolean isDir = tplFile.isDirectory();
|
|
|
|
|
|
|
|
JTemplate<?, ?> template;
|
|
|
|
|
|
|
|
template = this.getCurrentEditingTemplate();
|
|
|
|
if (template != null) {
|
|
|
|
String editingPath = FilenameUtils.standard(template.getEditingFILE().getPath());
|
|
|
|
if (isDir ? editingPath.contains(from + CoreConstants.SEPARATOR) : editingPath.equals(from)) {
|
|
|
|
FILE renameFile = template.getEditingFILE();
|
|
|
|
renameFile.setPath(editingPath.replace(from, to));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < this.getHistoryCount(); i++) {
|
|
|
|
template = this.get(i);
|
|
|
|
String editingPath = FilenameUtils.standard(template.getEditingFILE().getPath());
|
|
|
|
if (isDir ? editingPath.contains(from + CoreConstants.SEPARATOR) : editingPath.equals(from)) {
|
|
|
|
FILE renameFile = template.getEditingFILE();
|
|
|
|
renameFile.setPath(editingPath.replace(from, to));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 切换环境时暂存打开的模板内容,key 是在历史中的index,value 是模板xml 内容byte[]
|
|
|
|
*/
|
|
|
|
private Map<Integer, FILE> stashFILEMap;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 切换环境前将正在编辑的模板暂存起来,并且在新环境中重新读取一遍,暂存的不是模板文件的内容而是模板对象的内容
|
|
|
|
* <p>
|
|
|
|
* 防止新环境加载到的同名 Class 和模板对象中的 Class 不一致,在新环境存储失败
|
|
|
|
*
|
|
|
|
* @see HistoryTemplateListCache#load()
|
|
|
|
*/
|
|
|
|
public void stash() {
|
|
|
|
stashWorker = new SwingWorker<Boolean, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Boolean doInBackground() throws Exception {
|
|
|
|
_stash();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
stashWorker.execute();
|
|
|
|
|
|
|
|
}
|
|
|
|
private 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.templateToStashFile();
|
|
|
|
if (file != null) {
|
|
|
|
stashFILEMap.put(i, file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FineLoggerFactory.getLogger().info("Env Change Template Stashed.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private boolean checkStash() {
|
|
|
|
try {
|
|
|
|
return stashWorker.get();
|
|
|
|
} catch (Exception e) {
|
|
|
|
FineLoggerFactory.getLogger().debug(e.getMessage(), e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 切换环境前将正在编辑的模板暂存起来后,在新环境重新读取一遍
|
|
|
|
* <p>
|
|
|
|
* 防止新环境加载到的同名 Class 和模板对象中的 Class 不一致,在新环境存储失败
|
|
|
|
*
|
|
|
|
* @see HistoryTemplateListCache#stash()
|
|
|
|
*/
|
|
|
|
public void load() {
|
|
|
|
if (!checkStash()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
FineLoggerFactory.getLogger().info("{} is being reloaded", stashedFile.getName());
|
|
|
|
JTemplate<?, ?> template = historyList.get(i);
|
|
|
|
template.refreshResource(stashedFile);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FineLoggerFactory.getLogger().error(e.getMessage(), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stashFILEMap.clear();
|
|
|
|
}
|
|
|
|
FineLoggerFactory.getLogger().info("Env Change Template Loaded.");
|
|
|
|
}
|
|
|
|
|
|
|
|
private void loadCurrentTemplate(JTemplate<?, ?> template) {
|
|
|
|
DesignerContext.getDesignerFrame().addAndActivateJTemplate(template);
|
|
|
|
setCurrentEditingTemplate(template);
|
|
|
|
FineLoggerFactory.getLogger().info("Env Change Current Editing Template " + template.getTemplateName());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 重新载入当前模板,刷新数据/对象
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
public void reloadCurrentTemplate() {
|
|
|
|
reloadAllEditingTemplate();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 重绘当前模板
|
|
|
|
*/
|
|
|
|
public void repaintCurrentEditingTemplate() {
|
|
|
|
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
getCurrentEditingTemplate().repaint();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 插件安装后/启用 重新加载模板资源
|
|
|
|
*/
|
|
|
|
private void _reloadAllEditingTemplate(PluginContext context) {
|
|
|
|
FineLoggerFactory.getLogger().info("Plugin env change reload all template started");
|
|
|
|
long start = System.currentTimeMillis();
|
|
|
|
int size = historyList.size();
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
JTemplate<?, ?> template = historyList.get(i);
|
|
|
|
// 判断刷新逻辑比较耗时,且可能出现插件安装后误判导致不刷新
|
|
|
|
// 插件安装/启用场景比较少,因此插件安装/启用后每次均进行刷新
|
|
|
|
FILE file = template.getEditingFILE();
|
|
|
|
FILE stashFile = template.templateToStashFile();
|
|
|
|
if (stashFile != null) {
|
|
|
|
FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName());
|
|
|
|
template.refreshResource(stashFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FineLoggerFactory.getLogger().info("Plugin env change reload all template ended");
|
|
|
|
FineLoggerFactory.getLogger().info("Reload all template spend: {} ms", (System.currentTimeMillis() - start));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 根据具体插件来刷新模板
|
|
|
|
* @param context
|
|
|
|
*/
|
|
|
|
public void reloadAllEditingTemplateByPlugin(PluginContext context) {
|
|
|
|
_reloadAllEditingTemplate(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 直接刷新所以模板
|
|
|
|
*/
|
|
|
|
public void reloadAllEditingTemplate() {
|
|
|
|
_reloadAllEditingTemplate(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void replaceCurrentEditingTemplate(JTemplate<?, ?> jt) {
|
|
|
|
int index = contains(this.editingTemplate);
|
|
|
|
this.editingTemplate = jt;
|
|
|
|
historyList.set(index, jt);
|
|
|
|
MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList);
|
|
|
|
MutilTempalteTabPane.getInstance().setSelectedIndex(contains(jt));
|
|
|
|
}
|
|
|
|
}
|