You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
524 lines
18 KiB
524 lines
18 KiB
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.module.DesignModuleFactory; |
|
import com.fr.design.ui.util.UIUtil; |
|
import com.fr.file.FILE; |
|
import com.fr.file.FileNodeFILE; |
|
import com.fr.file.StashedFILE; |
|
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 java.io.ByteArrayOutputStream; |
|
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; |
|
import javax.swing.SwingWorker; |
|
|
|
/** |
|
* 历史模板缓存 |
|
* |
|
* @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.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."); |
|
} |
|
|
|
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(); |
|
boolean needReload = context == null || needReloadTemplate(context, template); |
|
if (needReload) { |
|
try { |
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
|
BaseBook target = template.getTarget(); |
|
if (target != null) { |
|
FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName()); |
|
target.export(outputStream); |
|
FILE stashedFile = new StashedFILE(file, outputStream.toByteArray()); |
|
template.refreshResource(stashedFile); |
|
} |
|
// 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
} |
|
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); |
|
} |
|
|
|
private boolean needReloadTemplate(PluginContext context, JTemplate<?, ?> template) { |
|
BaseBook baseBook = template.getTarget(); |
|
if (baseBook != null) { |
|
String name = template.getEditingFILE().getName(); |
|
String pluginId = context.getID(); |
|
long start = System.currentTimeMillis(); |
|
Set<ClassLoader> set = ClassHelper.getClassLoadersByFilter(baseBook, ClassFilter.getInstance()); |
|
FineLoggerFactory.getLogger().info("{} find plugin classloader spend: {} ms", name, (System.currentTimeMillis() - start)); |
|
if (set != null) { |
|
for (ClassLoader classLoader : set) { |
|
if (ComparatorUtils.equals(pluginId, PluginManager.detectLeakingPlugin(classLoader))) { |
|
return true; |
|
} |
|
} |
|
} else { |
|
// set为null说明 检测classloader 这里返回true直接刷新 兜底行为 |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
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)); |
|
} |
|
}
|
|
|