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.
2180 lines
66 KiB
2180 lines
66 KiB
package com.fr.design.mainframe; |
|
|
|
import com.fr.base.Parameter; |
|
import com.fr.base.TRL; |
|
import com.fr.base.extension.FileExtension; |
|
import com.fr.base.info.TemplateSaveInfoContext; |
|
import com.fr.base.io.BaseBook; |
|
import com.fr.base.iofile.attr.DesignBanCopyAttrMark; |
|
import com.fr.base.iofile.attr.ForkIdAttrMark; |
|
import com.fr.base.iofile.attr.TemplateIdAttrMark; |
|
import com.fr.base.iofile.attr.TemplateThemeAttrMark; |
|
import com.fr.base.svg.IconUtils; |
|
import com.fr.base.theme.TemplateTheme; |
|
import com.fr.base.theme.TemplateThemeCompatible; |
|
import com.fr.base.theme.TemplateThemeConfig; |
|
import com.fr.base.theme.ThemedTemplate; |
|
import com.fr.base.vcs.DesignerMode; |
|
import com.fr.decision.config.FSConfig; |
|
import com.fr.design.DesignModelAdapter; |
|
import com.fr.design.DesignState; |
|
import com.fr.design.DesignerEnvManager; |
|
import com.fr.design.ExtraDesignClassManager; |
|
import com.fr.design.actions.TableDataSourceAction; |
|
import com.fr.design.actions.edit.RedoAction; |
|
import com.fr.design.actions.edit.UndoAction; |
|
import com.fr.design.actions.file.SaveAsTemplateAction; |
|
import com.fr.design.actions.file.SaveTemplateAction; |
|
import com.fr.design.actions.file.WebPreviewUtils; |
|
import com.fr.design.base.mode.DesignModeContext; |
|
import com.fr.design.data.datapane.TableDataTreePane; |
|
import com.fr.design.designer.DesignerProxy; |
|
import com.fr.design.designer.TargetComponent; |
|
import com.fr.design.dialog.FineJOptionPane; |
|
import com.fr.design.dialog.InformationWarnPane; |
|
import com.fr.design.file.HistoryTemplateListCache; |
|
import com.fr.design.file.HistoryTemplateListPane; |
|
import com.fr.design.file.TemplateResourceManager; |
|
import com.fr.design.fun.DesignerFrameUpButtonProvider; |
|
import com.fr.design.fun.MenuHandler; |
|
import com.fr.design.fun.PreviewProvider; |
|
import com.fr.design.fun.PropertyItemPaneProvider; |
|
import com.fr.design.fun.ReportSupportedFileUIProvider; |
|
import com.fr.design.gui.frpane.HyperlinkGroupPane; |
|
import com.fr.design.gui.frpane.HyperlinkGroupPaneActionProvider; |
|
import com.fr.design.gui.ibutton.UIButton; |
|
import com.fr.design.gui.imenu.UIMenuItem; |
|
import com.fr.design.i18n.Toolkit; |
|
import com.fr.design.layout.FRGUIPaneFactory; |
|
import com.fr.design.mainframe.authority.JTemplateAuthorityChecker; |
|
import com.fr.design.mainframe.chart.info.ChartInfoCollector; |
|
import com.fr.design.mainframe.check.CheckButton; |
|
import com.fr.design.mainframe.template.info.TemplateProcessInfo; |
|
import com.fr.design.mainframe.template.info.TimeConsumeTimer; |
|
import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; |
|
import com.fr.design.mainframe.toolbar.VcsScene; |
|
import com.fr.design.menu.MenuDef; |
|
import com.fr.design.menu.NameSeparator; |
|
import com.fr.design.menu.ShortCut; |
|
import com.fr.design.module.DesignModuleFactory; |
|
import com.fr.design.preview.PagePreview; |
|
import com.fr.design.ui.util.UIUtil; |
|
import com.fr.design.utils.DesignUtils; |
|
import com.fr.design.utils.TemplateUtils; |
|
import com.fr.design.worker.save.CallbackSaveWorker; |
|
import com.fr.design.worker.save.EmptyCallBackSaveWorker; |
|
import com.fr.design.worker.save.SaveFailureHandler; |
|
import com.fr.design.worker.save.type.SaveType; |
|
import com.fr.design.worker.save.type.SaveTypeWorker; |
|
import com.fr.design.write.submit.DBManipulationInWidgetEventPane; |
|
import com.fr.design.write.submit.DBManipulationPane; |
|
import com.fr.event.EventDispatcher; |
|
import com.fr.file.FILE; |
|
import com.fr.file.FILEChooserPane; |
|
import com.fr.file.FileFILE; |
|
import com.fr.file.MemFILE; |
|
import com.fr.file.StashedFILE; |
|
import com.fr.form.ui.NoneWidget; |
|
import com.fr.form.ui.Widget; |
|
import com.fr.general.ComparatorUtils; |
|
import com.fr.locale.InterProviderFactory; |
|
import com.fr.log.FineLoggerFactory; |
|
import com.fr.nx.app.designer.toolbar.TemplateTransformer; |
|
import com.fr.nx.app.designer.utils.CptAndCptxCompatibilityUtil; |
|
import com.fr.nx.app.designer.utils.CptCompileUtil; |
|
import com.fr.nx.cptx.entry.metadata.CptxMetadata; |
|
import com.fr.nx.cptx.utils.CptxFileUtils; |
|
import com.fr.plugin.context.PluginContext; |
|
import com.fr.plugin.context.PluginRuntime; |
|
import com.fr.plugin.injectable.PluginModule; |
|
import com.fr.plugin.manage.PluginFilter; |
|
import com.fr.plugin.observer.PluginEvent; |
|
import com.fr.plugin.observer.PluginEventListener; |
|
import com.fr.plugin.observer.PluginEventType; |
|
import com.fr.plugin.observer.PluginListenerRegistration; |
|
import com.fr.report.InconsistentLockException; |
|
import com.fr.report.LockedException; |
|
import com.fr.report.UnLockedException; |
|
import com.fr.report.cell.Elem; |
|
import com.fr.report.cell.cellattr.CellImage; |
|
import com.fr.report.lock.LockInfoOperator; |
|
import com.fr.stable.ArrayUtils; |
|
import com.fr.stable.Filter; |
|
import com.fr.stable.ProductConstants; |
|
import com.fr.stable.StringUtils; |
|
import com.fr.stable.core.UUID; |
|
import com.fr.widgettheme.designer.WidgetThemeDisplayAction; |
|
import com.fr.workspace.WorkContext; |
|
import com.fr.workspace.base.UserInfo; |
|
import com.fr.workspace.server.lock.TplOperator; |
|
|
|
import javax.swing.BorderFactory; |
|
import javax.swing.Icon; |
|
import javax.swing.JComponent; |
|
import javax.swing.JOptionPane; |
|
import javax.swing.SwingConstants; |
|
import javax.swing.undo.UndoManager; |
|
import java.awt.BorderLayout; |
|
import java.awt.Dimension; |
|
import java.awt.FontMetrics; |
|
import java.io.ByteArrayOutputStream; |
|
import java.nio.file.Paths; |
|
import java.util.Arrays; |
|
import java.util.List; |
|
import java.util.Set; |
|
import java.util.concurrent.Callable; |
|
|
|
/** |
|
* 报表设计和表单设计的编辑区域(设计器编辑的IO文件) |
|
*/ |
|
public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>> extends TargetComponent<T> implements ToolBarMenuDockPlus, DesignerProxy, JTemplateSave, TabChangeListener, ThemedTemplate { |
|
|
|
private static final String DEFAULT_TAB_OPERATOR = "DefaultTabOperator"; |
|
// TODO ALEX_SEP editingFILE这个属性一定要吗?如果非要不可,有没有可能保证不为null |
|
|
|
private static final int PREDEFINED_ICON_WIDTH = 27; |
|
private static final int PREFIX_NUM = 3000; |
|
protected FILE editingFILE = null; |
|
// alex:初始状态为saved,这样不管是新建模板,还是打开模板,如果未做任何操作直接关闭,不提示保存 |
|
private boolean saved = true; |
|
private boolean authoritySaved = true; |
|
private UIButton templateThemeButton; |
|
private UndoManager undoMananger; |
|
private UndoManager authorityUndoManager; |
|
protected U undoState; |
|
protected U authorityUndoState = null; |
|
protected T template; // 当前模板 |
|
private boolean isNewCreateTpl = false; //当前模板是否为新建模板 |
|
private volatile boolean forbidden; |
|
|
|
/** |
|
* 模板过程的相关信息 |
|
* |
|
* @deprecated move to cloud ops plugin,left only for compatible |
|
*/ |
|
@Deprecated |
|
protected TemplateProcessInfo<T> processInfo; |
|
|
|
private JComponent centerPane; |
|
private DesignModelAdapter<T, ?> designModel; |
|
private PreviewProvider previewType; |
|
private String templateOpenFailedTip; |
|
|
|
/** |
|
* 统计模板制作耗时 |
|
* |
|
* @deprecated move to cloud ops plugin,left only for compatible |
|
*/ |
|
@Deprecated |
|
protected TimeConsumeTimer consumeTimer = new TimeConsumeTimer(); |
|
private volatile boolean saving = false; |
|
private volatile boolean opening = false; |
|
private volatile boolean openFailed = false; |
|
|
|
/** |
|
* UI界面模板运行时唯一的id 不存储在模板中 仅在运行时使用 模板界面上关闭就不关注了 |
|
*/ |
|
private final String runtimeId = UUID.randomUUID().toString(); |
|
|
|
private PluginEventListener pluginListener; |
|
// 监听全局主题数据更新 |
|
private TemplateThemeConfig.ThemeConfigChangeListener themeConfigChangeListener; |
|
|
|
public JTemplate() { |
|
initAndStartPlugin(); |
|
startListenThemeConfig(); |
|
} |
|
|
|
public JTemplate(T t, String defaultFileName) { |
|
this(t, new MemFILE(JTemplateNameHelper.newTemplateNameByIndex(defaultFileName)), true); |
|
} |
|
|
|
public JTemplate(T t, FILE file) { |
|
this(t, file, false); |
|
} |
|
|
|
public JTemplate(T t, FILE file, Parameter[] parameters) { |
|
this(t, file, false, parameters); |
|
} |
|
|
|
public JTemplate(T t, FILE file, boolean isNewFile) { |
|
this(t, file, isNewFile, null); |
|
} |
|
|
|
public JTemplate(T t, FILE file, boolean isNewFile, Parameter[] parameters) { |
|
super(t); |
|
HistoryTemplateListCache.getInstance().setCurrentOpeningTemplate(this); |
|
if (isNewFile) { |
|
// REPORT-58486: 必须在初始的UndoState创建前设置主题,使得初始的UndoState就包含了主题效果 |
|
setUpTheme4NewTemplate(); |
|
} |
|
beforeInit(); |
|
// 判断是否切换设计器状态到禁止拷贝剪切 |
|
if (t.getAttrMark(DesignBanCopyAttrMark.XML_TAG) != null) { |
|
DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.BAN_COPY_AND_CUT); |
|
} else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing() && !DesignModeContext.isDuchampMode()) { |
|
DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.NORMAL); |
|
} |
|
this.template = getTarget(); |
|
this.previewType = parserPreviewProvider(t.getPreviewType()); |
|
this.editingFILE = file; |
|
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
|
this.setBorder(BorderFactory.createEmptyBorder()); |
|
if (parameters == null) { |
|
designModel = createDesignModel(); |
|
} else { |
|
designModel = createDesignModel(parameters); |
|
} |
|
addCenterPane(); |
|
isNewCreateTpl = isNewFile; |
|
this.undoState = createUndoState(); |
|
|
|
initAndStartPlugin(); |
|
startListenThemeConfig(); |
|
} |
|
|
|
private void initAndStartPlugin() { |
|
initPluginPane(); |
|
startListenPlugin(); |
|
} |
|
|
|
private void startListenPlugin() { |
|
|
|
PluginFilter filter = new PluginFilter() { |
|
@Override |
|
public boolean accept(PluginContext context) { |
|
return context.contain(PropertyItemPaneProvider.XML_TAG); |
|
} |
|
}; |
|
this.pluginListener = new PluginEventListener(PropertyItemPaneProvider.LAST) { |
|
@Override |
|
public void on(PluginEvent event) { |
|
PluginContext context = event.getContext(); |
|
PluginRuntime runtime = context.getRuntime(); |
|
Set<PropertyItemPaneProvider> providers = runtime.get(PropertyItemPaneProvider.XML_TAG); |
|
for (PropertyItemPaneProvider provider : providers) { |
|
addPane(provider); |
|
} |
|
} |
|
}; |
|
PluginListenerRegistration.getInstance().listen(PluginEventType.AfterRun, this.pluginListener, filter); |
|
} |
|
|
|
private void startListenThemeConfig() { |
|
if (themeConfigChangeListener == null) { |
|
themeConfigChangeListener = new TemplateThemeConfig.ThemeConfigChangeListener() { |
|
@Override |
|
public void onThemeConfigChanged(TemplateThemeConfig.ThemeConfigEvent event) { |
|
TemplateTheme usingTheme = getTemplateTheme(); |
|
boolean isUsingThemeChanged = StringUtils.equals(event.themName, usingTheme.getName()); |
|
|
|
if (event.action == TemplateThemeConfig.ThemeConfigAction.REMOVE || |
|
event.action == TemplateThemeConfig.ThemeConfigAction.UPDATE) { |
|
if (isUsingThemeChanged) { |
|
checkAndResetTheme(); |
|
} else { |
|
// 修改主题配置,但是没有修改主题名称 , 需要重新保存文件 |
|
fireSuperTargetModified(); |
|
} |
|
} |
|
} |
|
}; |
|
TemplateThemeConfig<? extends TemplateTheme> config = getUsingTemplateThemeConfig(); |
|
if (config != null) { |
|
config.addThemeConfigChangeListener(themeConfigChangeListener); |
|
} |
|
} |
|
} |
|
|
|
private void stopListenThemeConfig() { |
|
if (themeConfigChangeListener != null) { |
|
TemplateThemeConfig<? extends TemplateTheme> config = getUsingTemplateThemeConfig(); |
|
if (config != null) { |
|
config.removeThemeConfigChangeListener(themeConfigChangeListener); |
|
} |
|
} |
|
} |
|
|
|
private void initPluginPane() { |
|
|
|
ExtraDesignClassManager classManager = PluginModule.getAgent(PluginModule.ExtraDesign); |
|
Set<PropertyItemPaneProvider> providers = classManager.getArray(PropertyItemPaneProvider.XML_TAG); |
|
for (PropertyItemPaneProvider provider : providers) { |
|
addPane(provider); |
|
} |
|
} |
|
|
|
@Override |
|
public void fireTabChange() { |
|
// do nothing |
|
} |
|
|
|
protected <R> void addPane(PropertyItemPaneProvider provider) { |
|
// do nothing |
|
} |
|
|
|
public void refreshFormDesigner() { |
|
// do nothing |
|
} |
|
|
|
|
|
/** |
|
* @deprecated move to cloud ops plugin,left only for compatible |
|
*/ |
|
@Deprecated |
|
void onGetFocus() { |
|
consumeTimer.start(); |
|
} |
|
|
|
/** |
|
* @deprecated move to cloud ops plugin,left only for compatible |
|
*/ |
|
@Deprecated |
|
void onLostFocus() { |
|
consumeTimer.stop(); |
|
} |
|
|
|
|
|
// 刷新右侧属性面板 |
|
public abstract void refreshEastPropertiesPane(); |
|
|
|
public abstract TargetComponent getCurrentElementCasePane(); |
|
|
|
public abstract JComponent getCurrentReportComponentPane(); |
|
|
|
/** |
|
* 为另存的模板创建新的模板id |
|
*/ |
|
protected void generateNewTemplateIdForSaveAs() { |
|
generateTemplateId(); |
|
} |
|
|
|
/** |
|
* 如果没有 forkId, 则计算 forkId |
|
* 要求在 templateId, 创建后执行。 |
|
*/ |
|
protected void computeForkIdIfAbsent() { |
|
|
|
ForkIdAttrMark forkIdAttrMark = this.template.getAttrMark(ForkIdAttrMark.XML_TAG); |
|
if (forkIdAttrMark == null || StringUtils.isEmpty(forkIdAttrMark.getForkId())) { |
|
this.template.addAttrMark(new ForkIdAttrMark(this.template.getTemplateID())); |
|
} |
|
} |
|
|
|
/** |
|
* 收集图表信息 |
|
*/ |
|
private void collectInfo() { |
|
ChartInfoCollector.getInstance().collectInfo(template.getTemplateID(), StringUtils.EMPTY, getProcessInfo(), 0); |
|
} |
|
|
|
/** |
|
* 另存模板时收集图表信息 |
|
* |
|
* @param originID 原始模板id |
|
*/ |
|
private void collectInfoWhenSaveAs(String originID) { |
|
ChartInfoCollector.getInstance().collectInfo(template.getTemplateID(), originID, getProcessInfo(), 0); |
|
} |
|
|
|
/** |
|
* @deprecated move to cloud ops plugin |
|
*/ |
|
@Deprecated |
|
public abstract TemplateProcessInfo<T> getProcessInfo(); |
|
|
|
public U getUndoState() { |
|
return undoState; |
|
} |
|
|
|
/** |
|
* set/get 模板屏幕分辨率 |
|
*/ |
|
public abstract void setJTemplateResolution(int resolution); |
|
|
|
public abstract int getJTemplateResolution(); |
|
|
|
|
|
/** |
|
* 初始化权限细粒度撤销状态 |
|
*/ |
|
public void iniAuthorityUndoState() { |
|
this.authorityUndoState = createUndoState(); |
|
} |
|
|
|
/** |
|
* 有条件取消格式刷 |
|
*/ |
|
public void doConditionCancelFormat() { |
|
} |
|
|
|
@Override |
|
public int getMenuState() { |
|
return DesignState.WORK_SHEET; |
|
} |
|
|
|
/** |
|
* 取消格式 |
|
*/ |
|
@Override |
|
public void cancelFormat() { |
|
} |
|
|
|
//因为报表的tab从0开始,所以表单默认为-1吧 |
|
public int getEditingReportIndex() { |
|
return -1; |
|
} |
|
|
|
public String getPath() { |
|
return getEditingFILE().getPath(); |
|
} |
|
|
|
protected abstract JComponent createCenterPane(); |
|
|
|
/** |
|
* 去除选择 |
|
*/ |
|
public abstract void removeTemplateSelection(); |
|
|
|
|
|
public void setSheetCovered(boolean isCovered) { |
|
|
|
} |
|
|
|
/** |
|
* 在权限编辑的状态下,切换左下角角色树的角色时,判断对应的额sheet是不是需要corver |
|
* |
|
* @param roles 角色 |
|
*/ |
|
public void judgeSheetAuthority(String roles) { |
|
|
|
} |
|
|
|
/** |
|
* 模板初始化之前 |
|
*/ |
|
private void beforeInit() { |
|
EventDispatcher.fire(JTemplateEvent.BEFORE_TEMPLATE_INIT, this); |
|
} |
|
|
|
/** |
|
* 模板激活之前之前 |
|
*/ |
|
protected void beforeActive() { |
|
EventDispatcher.fire(JTemplateEvent.BEFORE_TEMPLATE_ACTIVE, this); |
|
} |
|
|
|
/** |
|
* 模板关闭时 |
|
*/ |
|
public void whenClose() { |
|
// stop的时候 pluginListener 和 PluginFilter 都会移除 |
|
PluginListenerRegistration.getInstance().stopListen(this.pluginListener); |
|
stopListenThemeConfig(); |
|
} |
|
|
|
/** |
|
* 用于 切换工作目录 时的模板资源暂存 |
|
* |
|
* @return |
|
*/ |
|
public FILE templateToStashFile4Envchange() { |
|
FILE file = this.getEditingFILE(); |
|
if (file.isEnvFile()) { |
|
// 切换工作目录时,模板锁信息被清除,因此这里需要将环境相关模板文件转化为与环境无关的内存模板文件,再创建暂存文件 |
|
return new StashedFILE(new MemFILE(file.getName()), exportBaseBook2ByteArray(), template.suffix()); |
|
} else { |
|
// 其它情况下,直接创建暂存文件 |
|
return templateToStashFile(); |
|
} |
|
} |
|
|
|
public FILE templateToStashFile() { |
|
FILE file = this.getEditingFILE(); |
|
return new StashedFILE(file, exportBaseBook2ByteArray(), template.suffix()); |
|
} |
|
|
|
private byte[] exportBaseBook2ByteArray() { |
|
try { |
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
|
BaseBook target = this.getTarget(); |
|
if (target != null) { |
|
target.export(outputStream); |
|
return outputStream.toByteArray(); |
|
} |
|
// 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error("Export BaseBook to Byte Array Failed"); |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
return new byte[0]; |
|
} |
|
|
|
|
|
/** |
|
* 刷新内部资源 |
|
* <p> |
|
* 刷新资源的同时。 |
|
* CenterPane 负责监听改动。 |
|
* 所以需要同步处理 |
|
*/ |
|
@Deprecated |
|
public void refreshResource() { |
|
if (JTemplateFactory.isAvailable()) { |
|
refreshResource(this.editingFILE); |
|
} |
|
} |
|
|
|
public void refreshResource(FILE file) { |
|
|
|
setTargetByFile(file); |
|
UIUtil.invokeLaterIfNeeded(new Runnable() { |
|
@Override |
|
public void run() { |
|
refreshDesignerFromResource(); |
|
} |
|
}); |
|
|
|
} |
|
|
|
protected void refreshDesignerFromResource() { |
|
// 先移除旧的。 |
|
removeCenterPane(); |
|
// 加入新的 |
|
addCenterPane(); |
|
|
|
refreshToolArea(); |
|
|
|
TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).refreshDockingView(); |
|
} |
|
|
|
/** |
|
* 刷新 模板资源 和 EditingFILE |
|
* 仅在切换工作目录,reload模板时使用 |
|
* |
|
* @param file |
|
*/ |
|
public void refreshResourceAndEditingFILE(FILE file) { |
|
// 这里替换EditingFILE是为了在切换工作目录后,将模板文件对象设置成环境无关文件对象 |
|
this.editingFILE = file instanceof StashedFILE ? ((StashedFILE) file).getInsideFILE() : file; |
|
refreshResource(file); |
|
} |
|
|
|
private void setTargetByFile(FILE file) { |
|
T newTemplate = JTemplateFactory.asIOFile(file, this.suffix()); |
|
if (newTemplate != null) { |
|
this.template = newTemplate; |
|
setTarget(this.template); |
|
} |
|
} |
|
|
|
private void addCenterPane() { |
|
|
|
this.centerPane = createCenterPane(); |
|
this.add(centerPane, BorderLayout.CENTER); |
|
} |
|
|
|
private void removeCenterPane() { |
|
|
|
JComponent centerPane = this.centerPane; |
|
this.remove(centerPane); |
|
} |
|
|
|
/** |
|
* 刷新容器 |
|
*/ |
|
public abstract void refreshContainer(); |
|
|
|
/** |
|
* 去除参数面板选择 |
|
*/ |
|
public abstract void removeParameterPaneSelection(); |
|
|
|
/** |
|
* 缩放参数 |
|
*/ |
|
public abstract void setScale(int resolution); |
|
|
|
public abstract int getScale(); |
|
|
|
/** |
|
* 缩放参数自适应 |
|
*/ |
|
public abstract int selfAdaptUpdate(); |
|
|
|
protected abstract DesignModelAdapter<T, ?> createDesignModel(); |
|
|
|
protected DesignModelAdapter<T, ?> createDesignModel(Parameter[] parameters) { |
|
// 空实现 兼容下 |
|
return null; |
|
} |
|
|
|
|
|
/** |
|
* 创建菜单项Preview |
|
* |
|
* @return 菜单 |
|
*/ |
|
public abstract UIMenuItem[] createMenuItem4Preview(); |
|
|
|
/** |
|
* @return |
|
*/ |
|
public DesignModelAdapter<T, ?> getModel() { |
|
return designModel; |
|
} |
|
|
|
/** |
|
* 重新计算大小 |
|
*/ |
|
public void doResize() { |
|
|
|
} |
|
|
|
/** |
|
* 是否保存了 |
|
* |
|
* @return 是则返回true |
|
*/ |
|
public boolean isSaved() { |
|
return DesignerMode.isAuthorityEditing() ? this.authoritySaved : this.saved; |
|
} |
|
|
|
/** |
|
* 是否都保存了 |
|
* |
|
* @return 是则返回true |
|
*/ |
|
public boolean isALLSaved() { |
|
return this.saved && this.authoritySaved; |
|
} |
|
|
|
|
|
/** |
|
* 是否在权限编辑时做过操作 |
|
* |
|
* @return 是则返回true |
|
*/ |
|
public boolean isDoSomethingInAuthority() { |
|
return authorityUndoManager != null && authorityUndoManager.canUndo(); |
|
} |
|
|
|
public void setSaved(boolean isSaved) { |
|
if (DesignerMode.isAuthorityEditing()) { |
|
authoritySaved = isSaved; |
|
} else { |
|
saved = isSaved; |
|
} |
|
} |
|
|
|
/** |
|
* @return |
|
*/ |
|
public UndoManager getUndoManager() { |
|
if (DesignerMode.isAuthorityEditing()) { |
|
if (this.authorityUndoManager == null) { |
|
this.authorityUndoManager = new UndoManager(); |
|
int limit = DesignerEnvManager.getEnvManager().getUndoLimit(); |
|
limit = (limit <= 0) ? -1 : limit; |
|
|
|
this.authorityUndoManager.setLimit(limit); |
|
} |
|
return authorityUndoManager; |
|
} |
|
if (this.undoMananger == null) { |
|
this.undoMananger = new UndoManager(); |
|
int limit = DesignerEnvManager.getEnvManager().getUndoLimit(); |
|
limit = (limit <= 0) ? -1 : limit; |
|
|
|
this.undoMananger.setLimit(limit); |
|
} |
|
return this.undoMananger; |
|
} |
|
|
|
/** |
|
* 清除权限细粒度撤销 |
|
*/ |
|
public void cleanAuthorityUndo() { |
|
authorityUndoManager = null; |
|
authorityUndoState = null; |
|
authoritySaved = true; |
|
} |
|
|
|
|
|
/** |
|
* 可以撤销 |
|
* |
|
* @return 是则返回true |
|
*/ |
|
public boolean canUndo() { |
|
return this.getUndoManager().canUndo(); |
|
} |
|
|
|
/** |
|
* 可以重做 |
|
* |
|
* @return 是则返回true |
|
*/ |
|
public boolean canRedo() { |
|
return this.getUndoManager().canRedo(); |
|
} |
|
|
|
/** |
|
* 撤销 |
|
*/ |
|
public void undo() { |
|
this.getUndoManager().undo(); |
|
// 撤销前模版使用主题可能已经被删除或修改,需要重置模版样式 |
|
checkAndResetTheme(true); |
|
fireSuperTargetModified(); |
|
} |
|
|
|
/** |
|
* 重做 |
|
*/ |
|
public void redo() { |
|
this.getUndoManager().redo(); |
|
// 重做前模版使用主题可能已经被删除或修改,需要重置模版样式 |
|
checkAndResetTheme(true); |
|
fireSuperTargetModified(); |
|
} |
|
|
|
public void undoToCurrent() { |
|
UIUtil.invokeLaterIfNeeded(new Runnable() { |
|
@Override |
|
public void run() { |
|
BaseUndoState current = JTemplate.this.getUndoState(); |
|
current.applyState(); |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* 模板更新 |
|
*/ |
|
@Override |
|
public void fireTargetModified() { |
|
U newState = createUndoState(); |
|
if (newState == null) { |
|
return; |
|
} |
|
//如果是在不同的模式下产生的 |
|
if (DesignerMode.isAuthorityEditing()) { |
|
this.getUndoManager().addEdit(new UndoStateEdit(authorityUndoState, newState)); |
|
authorityUndoState = newState; |
|
} else { |
|
this.getUndoManager().addEdit(new UndoStateEdit(undoState, newState)); |
|
undoState = newState; |
|
} |
|
fireSuperTargetModified(); |
|
} |
|
|
|
/** |
|
* 用于在退出权限编辑的时候,将所有操作的有权限编辑的效果作为一个动作放入正常报表undoManager中 |
|
*/ |
|
public void fireAuthorityStateToNomal() { |
|
U newState = createUndoState(); |
|
if (newState == null) { |
|
return; |
|
} |
|
newState.setAuthorityType(BaseUndoState.AUTHORITY_STATE); |
|
this.getUndoManager().addEdit(new UndoStateEdit(undoState, newState)); |
|
undoState = newState; |
|
fireSuperTargetModified(); |
|
} |
|
|
|
public boolean accept(Object o) { |
|
return true; |
|
} |
|
|
|
private void fireSuperTargetModified() { |
|
if (DesignerMode.isAuthorityEditing()) { |
|
this.authoritySaved = false; |
|
} else { |
|
this.saved = false; |
|
} |
|
HistoryTemplateListPane.getInstance().getCurrentEditingTemplate().setSaved(false); |
|
super.fireTargetModified(); |
|
} |
|
|
|
public void fireTargetModified(boolean shouldCreateNewUndoState) { |
|
if (shouldCreateNewUndoState) { |
|
fireTargetModified(); |
|
} else { |
|
super.fireTargetModified(); |
|
} |
|
} |
|
|
|
protected abstract U createUndoState(); |
|
|
|
protected abstract void applyUndoState(U u); |
|
|
|
/** |
|
* 停止编辑, 判断保存属性 * |
|
*/ |
|
@Override |
|
public void stopEditing() { |
|
} |
|
|
|
|
|
/** |
|
* 得到正在编辑的FILE |
|
* |
|
* @return |
|
*/ |
|
public FILE getEditingFILE() { |
|
return this.editingFILE; |
|
} |
|
|
|
|
|
/** |
|
* richer:保存文件的后缀名 |
|
* |
|
* @return 返回后缀名 |
|
*/ |
|
public abstract String suffix(); |
|
|
|
/** |
|
* 添加图片到格子中 |
|
*/ |
|
public void setPictureElem(Elem elem, CellImage cellImage) { |
|
// 子类实现 |
|
} |
|
|
|
/** |
|
* 是否保存 |
|
* |
|
* @return 保存模板 |
|
*/ |
|
@Deprecated |
|
public boolean saveTemplate() { |
|
return this.saveTemplate(true); |
|
} |
|
|
|
/** |
|
* 保存 |
|
* |
|
* @return 保存成功返回true |
|
*/ |
|
@Deprecated |
|
public boolean saveTemplate2Env() { |
|
return this.saveTemplate(false); |
|
} |
|
|
|
/** |
|
* 另存 |
|
* |
|
* @return 保存成功返回true |
|
*/ |
|
@Deprecated |
|
public boolean saveAsTemplate() { |
|
return this.saveAsTemplate(true); |
|
} |
|
|
|
/** |
|
* 另存 |
|
* |
|
* @return 保存成功返回true |
|
*/ |
|
@Deprecated |
|
public boolean saveAsTemplate2Env() { |
|
return this.saveAsTemplate(false); |
|
} |
|
|
|
/** |
|
* Web预览的时候需要隐藏掉除“报表运行环境”外的路径(C盘D盘等) isShowLoc = false |
|
* 被云端运维插件修改用于收集埋点 |
|
* |
|
* @param isShowLoc 是否本地 |
|
* @return 保存成功返回true |
|
*/ |
|
@Deprecated |
|
public boolean saveTemplate(boolean isShowLoc) { |
|
FILE editingFILE = this.getEditingFILE(); |
|
// carl:editingFILE没有,当然不存了,虽然不会有这种情况 |
|
if (editingFILE == null) { |
|
return false; |
|
} |
|
|
|
// 检查一下editingFILE是不是已存在的文件,如果不存在则用saveAs |
|
if (!editingFILE.exists()) { |
|
return saveAsTemplate(isShowLoc); |
|
} |
|
collectInfo(); |
|
TemplateSaveInfoContext.getInstance().startCollect(template); |
|
boolean result = this.saveFile(); |
|
TemplateSaveInfoContext.getInstance().stopCollect(result); |
|
return result; |
|
} |
|
|
|
private boolean isCancelOperation(int operation) { |
|
return operation == FILEChooserPane.CANCEL_OPTION || |
|
operation == FILEChooserPane.JOPTIONPANE_CANCEL_OPTION; |
|
} |
|
|
|
private boolean isOkOperation(int operation) { |
|
return operation == FILEChooserPane.JOPTIONPANE_OK_OPTION || |
|
operation == FILEChooserPane.OK_OPTION; |
|
} |
|
|
|
public boolean saveAsTemplate(boolean isShowLoc) { |
|
FILE editingFILE = this.getEditingFILE(); |
|
if (editingFILE == null) { |
|
return false; |
|
} |
|
return saveAsTemplate(isShowLoc, editingFILE.getName()); |
|
} |
|
|
|
/** |
|
* 保存 |
|
* |
|
* @param isShowLoc 是否显示“报表运行环境”外的路径(C盘D盘等) |
|
* @param fileName 保存文件名 |
|
* @return |
|
*/ |
|
@Deprecated |
|
public boolean saveAsTemplate(boolean isShowLoc, String fileName) { |
|
String oldName = this.getPath(); |
|
// alex:如果是SaveAs的话需要让用户来选择路径了 |
|
FILEChooserPane fileChooser = getFILEChooserPane(isShowLoc); |
|
addChooseFILEFilter(fileChooser); |
|
fileChooser.setFileNameTextField(fileName, this.suffix()); |
|
int chooseResult = fileChooser.showSaveDialog(DesignerContext.getDesignerFrame(), this.suffix()); |
|
|
|
if (isCancelOperation(chooseResult)) { |
|
return false; |
|
} |
|
// 源文件 |
|
FILE sourceFile = editingFILE; |
|
|
|
if (isOkOperation(chooseResult)) { |
|
// 目标文件 |
|
editingFILE = fileChooser.getSelectedFILE(); |
|
} |
|
|
|
boolean lockedTarget = |
|
// 目标本地文件 |
|
!editingFILE.isEnvFile() || |
|
// 目标远程文件 |
|
WorkContext.getCurrent().get(TplOperator.class).saveAs(editingFILE.getPath()); |
|
if (lockedTarget) { |
|
boolean saved = saveNewFile(editingFILE, oldName); |
|
// 目标文件保存成功并且源文件不一致的情况下,把源文件锁释放掉 |
|
if (saved && !ComparatorUtils.equals(editingFILE.getPath(), sourceFile.getPath())) { |
|
WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(sourceFile.getPath()); |
|
} |
|
return saved; |
|
} else { |
|
FineJOptionPane.showMessageDialog( |
|
DesignerContext.getDesignerFrame(), |
|
Toolkit.i18nText("Fine-Design-Basic_Save_Failure"), |
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Alert"), |
|
JOptionPane.WARNING_MESSAGE); |
|
return false; |
|
} |
|
} |
|
|
|
protected void addChooseFILEFilter(FILEChooserPane fileChooser) { |
|
|
|
} |
|
|
|
|
|
/** |
|
* 保存新模板时会进入此方法(新建模板直接保存,或者另存为) |
|
* 被云端运维插件修改用于收集埋点 |
|
*/ |
|
protected boolean saveNewFile(FILE editingFILE, String oldName) { |
|
String originID = StringUtils.EMPTY; |
|
String currentId = this.template.getTemplateID(); |
|
if (StringUtils.isNotEmpty(currentId)) { |
|
originID = currentId; |
|
} |
|
// 在保存之前,初始化 templateID |
|
generateNewTemplateIdForSaveAs(); |
|
computeForkIdIfAbsent(); |
|
|
|
this.editingFILE = editingFILE; |
|
TemplateSaveInfoContext.getInstance().startCollect(template); |
|
boolean result = this.saveToNewFile(oldName); |
|
TemplateSaveInfoContext.getInstance().stopCollect(result); |
|
if (result) { |
|
DesignerFrameFileDealerPane.getInstance().refresh(); |
|
collectInfoWhenSaveAs(originID); |
|
} |
|
return result; |
|
} |
|
|
|
protected boolean saveToNewFile(String oldName) { |
|
boolean result = false; |
|
String path = this.editingFILE.getPath(); |
|
Set<ReportSupportedFileUIProvider> providers = ExtraDesignClassManager.getInstance().getArray(ReportSupportedFileUIProvider.XML_TAG); |
|
for (ReportSupportedFileUIProvider provider : providers) { |
|
result = result || provider.saveToNewFile(path, this); |
|
} |
|
result = result || saveToNewFile4Cptx(path); |
|
if (!result) { |
|
result = this.saveFile(); |
|
//更换最近打开 |
|
DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(oldName, this.getPath()); |
|
this.refreshToolArea(); |
|
} |
|
return result; |
|
} |
|
|
|
private boolean saveToNewFile4Cptx(String targetPath) { |
|
if (FileExtension.CPTX.matchExtension(targetPath)) { |
|
TemplateTransformer.TO_CPTX.transform(this); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
protected void mkNewFile(FILE file) { |
|
try { |
|
file.mkfile(); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
|
|
/** |
|
* 将模板另存为可以分享出去的混淆后内置数据集模板 |
|
* |
|
* @return 是否另存成功 |
|
*/ |
|
public boolean saveShareFile() { |
|
return true; |
|
} |
|
|
|
public Widget getSelectElementCase() { |
|
return new NoneWidget(); |
|
} |
|
|
|
protected FILEChooserPane getFILEChooserPane(boolean isShowLoc) { |
|
return FILEChooserPane.getInstance(true, isShowLoc); |
|
} |
|
|
|
protected boolean saveFile() { |
|
FILE editingFILE = this.getEditingFILE(); |
|
|
|
if (editingFILE == null || editingFILE instanceof MemFILE) { |
|
return false; |
|
} |
|
try { |
|
checkBeforeSave(); |
|
export(); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
SaveFailureHandler.getInstance().process(e); |
|
return false; |
|
} |
|
this.editingFILE = editingFILE; |
|
this.saved = true; |
|
this.authoritySaved = true; |
|
DesignerContext.getDesignerFrame().setTitle(); |
|
this.fireJTemplateSaved(); |
|
return true; |
|
} |
|
|
|
public boolean isNewCreateTpl() { |
|
return isNewCreateTpl; |
|
} |
|
|
|
protected void checkBeforeSave() throws Exception { |
|
// 保存前校验下未解锁 |
|
LockInfoOperator lockInfoOperator = WorkContext.getCurrent().get(LockInfoOperator.class); |
|
String path = getEditingFILE().getPath(); |
|
if (lockInfoOperator.isTplUnLocked(path)) { |
|
throw new UnLockedException(); |
|
} |
|
//睡眠超过90s之后,锁信息会被清掉,之后其他人可能打开模板进行锁定,所以定这里还判断一下模板是否被其他人锁 |
|
UserInfo userInfo = lockInfoOperator.getUserInfo(path); |
|
if (userInfo != null) { |
|
throw new LockedException(userInfo); |
|
} |
|
// 过滤掉本地文件 |
|
boolean localFile = getEditingFILE() instanceof FileFILE; |
|
boolean inconsistent = !localFile && getEditingFILE().exists() |
|
&& !lockInfoOperator.consistentCheckAndLockIfNecessary(path); |
|
if (inconsistent) { |
|
throw new InconsistentLockException(); |
|
} |
|
} |
|
|
|
public byte[] exportData() throws Exception { |
|
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { |
|
BaseBook target = getTarget(); |
|
if (target != null) { |
|
target.export(outputStream); |
|
return outputStream.toByteArray(); |
|
} |
|
} |
|
return new byte[0]; |
|
} |
|
|
|
protected boolean export() throws Exception { |
|
return this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(getEditingFILE())); |
|
|
|
} |
|
|
|
// /////////////////////////////toolbarMenuDock////////////////////////////////// |
|
|
|
/** |
|
* 文件的4个菜单 |
|
* |
|
* @return 返回菜单 |
|
*/ |
|
@Override |
|
public ShortCut[] shortcut4FileMenu() { |
|
if (DesignerMode.isVcsMode()) { |
|
return VcsScene.shortcut4FileMenu(this); |
|
} else if (DesignerMode.isAuthorityEditing()) { |
|
return new ShortCut[]{new SaveTemplateAction(this), new UndoAction(this), new RedoAction(this)}; |
|
} else { |
|
return new ShortCut[]{new SaveTemplateAction(this), new SaveAsTemplateAction(this), new UndoAction(this), new RedoAction(this)}; |
|
} |
|
|
|
} |
|
|
|
/** |
|
* 目标菜单 |
|
* |
|
* @return 菜单 |
|
*/ |
|
@Override |
|
public MenuDef[] menus4Target() { |
|
MenuDef tplMenu = new MenuDef(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_M_Template"), 'T'); |
|
tplMenu.setAnchor(MenuHandler.TEMPLATE); |
|
if (!DesignerMode.isAuthorityEditing()) { |
|
tplMenu.addShortCut(new NameSeparator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_WorkBook"))); |
|
tplMenu.addShortCut(new TableDataSourceAction(this)); |
|
tplMenu.addShortCut(shortcut4TemplateMenu()); |
|
} |
|
if (!DesignerMode.isVcsMode()) { |
|
tplMenu.addShortCut(shortCuts4Authority()); |
|
} |
|
|
|
//查找替换 |
|
tplMenu.addShortCut(new NameSeparator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Replace_Name_Separate"))); |
|
tplMenu.addShortCut((ShortCut) DesignModuleFactory.getITReplaceAction()); |
|
tplMenu.insertShortCut(1, new WidgetThemeDisplayAction<>(this)); |
|
return new MenuDef[]{tplMenu}; |
|
} |
|
|
|
/** |
|
* 模板菜单 |
|
* |
|
* @return 返回菜单 |
|
*/ |
|
@Override |
|
public abstract ShortCut[] shortcut4TemplateMenu(); |
|
|
|
/** |
|
* 权限细粒度模板菜单 |
|
* |
|
* @return 菜单 |
|
*/ |
|
@Override |
|
public abstract ShortCut[] shortCuts4Authority(); |
|
|
|
// /////////////////////////////JTemplateActionListener////////////////////////////////// |
|
|
|
/** |
|
* 增加模板Listener |
|
* |
|
* @param l 模板Listener |
|
*/ |
|
public void addJTemplateActionListener(JTemplateActionListener l) { |
|
List<Object> list = Arrays.asList(this.listenerList.getListeners(JTemplateActionListener.class)); |
|
if (!list.contains(l)) { |
|
this.listenerList.add(JTemplateActionListener.class, l); |
|
} |
|
} |
|
|
|
/** |
|
* 移除模板Listener |
|
* |
|
* @param l 模板Listener |
|
*/ |
|
public void removeJTemplateActionListener(JTemplateActionListener l) { |
|
this.listenerList.remove(JTemplateActionListener.class, l); |
|
} |
|
|
|
/** |
|
* 模板保存前触发 |
|
*/ |
|
public void fireJTemplateSaveBefore() { |
|
Object[] listeners = listenerList.getListenerList(); |
|
|
|
for (int i = listeners.length - 2; i >= 0; i -= 2) { |
|
if (listeners[i] == JTemplateActionListener.class) { |
|
((JTemplateActionListener) listeners[i + 1]).templateSaveBefore(this); |
|
} |
|
} |
|
this.repaint(30); |
|
} |
|
|
|
/** |
|
* 触发模板关闭 |
|
*/ |
|
public void fireJTemplateClosed() { |
|
// Guaranteed to return a non-null array |
|
Object[] listeners = listenerList.getListenerList(); |
|
|
|
// Process the listeners last to first, notifying |
|
// those that are interested in this event |
|
for (int i = listeners.length - 2; i >= 0; i -= 2) { |
|
if (listeners[i] == JTemplateActionListener.class) { |
|
((JTemplateActionListener) listeners[i + 1]).templateClosed(this); |
|
} |
|
} |
|
this.undoState = null; |
|
this.repaint(30); |
|
} |
|
|
|
/** |
|
* 触发模板保存 |
|
*/ |
|
public void fireJTemplateSaved() { |
|
// Guaranteed to return a non-null array |
|
Object[] listeners = listenerList.getListenerList(); |
|
|
|
// Process the listeners last to first, notifying |
|
// those that are interested in this event |
|
for (int i = listeners.length - 1; i >= 0; i -= 1) { |
|
if (listeners[i] == JTemplateActionListener.class) { |
|
((JTemplateActionListener) listeners[i + 1]).templateSaved(this); |
|
} |
|
} |
|
|
|
this.repaint(30); |
|
} |
|
|
|
/** |
|
* 触发模板打开 |
|
*/ |
|
public void fireJTemplateOpened() { |
|
// Guaranteed to return a non-null array |
|
Object[] listeners = listenerList.getListenerList(); |
|
|
|
// Process the listeners last to first, notifying |
|
// those that are interested in this event |
|
for (int i = listeners.length - 2; i >= 0; i -= 2) { |
|
if (listeners[i] == JTemplateActionListener.class) { |
|
((JTemplateActionListener) listeners[i + 1]).templateOpened(this); |
|
} |
|
} |
|
|
|
this.repaint(30); |
|
} |
|
|
|
/** |
|
* 模板切换时,恢复原来的状态 |
|
*/ |
|
public void revert() { |
|
|
|
} |
|
|
|
private int getVersionCompare(String versionString) { |
|
if (StringUtils.isBlank(versionString)) { |
|
return 0; |
|
} |
|
//8.0.0可以打开8.0.1的模板. |
|
int len = ProductConstants.DESIGNER_VERSION.length() - 1; |
|
return ComparatorUtils.compare(versionString.substring(0, len), ProductConstants.DESIGNER_VERSION.substring(0, len)); |
|
|
|
} |
|
|
|
private int getVersionCompareHBB(String versionString) { |
|
if (StringUtils.isBlank(versionString)) { |
|
return 0; |
|
} |
|
return ComparatorUtils.compare(versionString, "HBB"); |
|
|
|
} |
|
|
|
private boolean isHigherThanCurrent(String versionString) { |
|
return getVersionCompare(versionString) > 0; |
|
} |
|
|
|
private boolean isLowerThanCurrent(String versionString) { |
|
return getVersionCompare(versionString) < 0; |
|
} |
|
|
|
private boolean isLowerThanHBB(String versionString) { |
|
return getVersionCompareHBB(versionString) < 0; |
|
} |
|
|
|
/** |
|
* 判断是否是新版设计器 |
|
* |
|
* @param showTipPane 是否需要展示弹窗 |
|
* @return 是返回true |
|
*/ |
|
public boolean isNewDesigner(boolean showTipPane) { |
|
String xmlDesignerVersion = getTarget().getXMLDesignerVersion(); |
|
if (isLowerThanHBB(xmlDesignerVersion)) { |
|
String info = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Open-New_Form_Tip"); |
|
String moreInfo = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Server_Version_Tip_More_Info"); |
|
if (showTipPane) { |
|
new InformationWarnPane(info, moreInfo, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips")).show(); |
|
} |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public boolean isNewDesigner() { |
|
return isNewDesigner(true); |
|
} |
|
|
|
/** |
|
* 是否是就版本设计器 |
|
* |
|
* @param showTipPane 是否需要展示弹窗 |
|
* @return 是就返回true |
|
*/ |
|
public boolean isOldDesigner(boolean showTipPane) { |
|
String xmlDesignerVersion = getTarget().getXMLDesignerVersion(); |
|
if (isHigherThanCurrent(xmlDesignerVersion)) { |
|
String infor = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Template_Version_Not_Match", DesignUtils.parseVersion(xmlDesignerVersion)); |
|
String moreInfo = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Server_Version_Tip_More_Info"); |
|
if (showTipPane) { |
|
new InformationWarnPane(infor, moreInfo, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips")).show(); |
|
} |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public boolean isOldDesigner() { |
|
return isOldDesigner(true); |
|
} |
|
|
|
/** |
|
* |
|
*/ |
|
public void setComposite() { |
|
|
|
} |
|
|
|
/** |
|
* @return |
|
*/ |
|
public PreviewProvider getPreviewType() { |
|
return previewType; |
|
} |
|
|
|
/** |
|
* 刷新工具区域 |
|
*/ |
|
public void refreshToolArea() { |
|
|
|
} |
|
|
|
|
|
/** |
|
* 是否是工作薄 |
|
* |
|
* @return 是则返回true |
|
*/ |
|
public abstract boolean isJWorkBook(); |
|
|
|
/** |
|
* 激活指定的template |
|
*/ |
|
public void activeJTemplate(int index, JTemplate jt) { |
|
beforeActive(); |
|
DesignerContext.getDesignerFrame().activateJTemplate(this); |
|
} |
|
|
|
/** |
|
* 激活已存在的模板 |
|
*/ |
|
public void activeOldJTemplate() { |
|
beforeActive(); |
|
DesignerContext.getDesignerFrame().activateJTemplate(this); |
|
} |
|
|
|
/** |
|
* 激活新的模板 |
|
*/ |
|
public void activeNewJTemplate() { |
|
beforeActive(); |
|
DesignerContext.getDesignerFrame().addAndActivateJTemplate(this); |
|
} |
|
|
|
/** |
|
* 将要激活打开其他模板,使当前模板灭活 |
|
* 默认 do nothing 返回true |
|
* |
|
* @return true:成功停用当前模板 |
|
*/ |
|
public boolean deactivateTemplate() { |
|
return true; |
|
} |
|
|
|
|
|
/** |
|
* 将要激活打开其他模板,使当前模板灭活 |
|
* 默认 do nothing 返回true |
|
* |
|
* @return true:成功停用当前模板 |
|
*/ |
|
public boolean deactivateTemplate(JTemplate jTemplate) { |
|
//兼容调用老的接口 |
|
return deactivateTemplate(); |
|
} |
|
|
|
/** |
|
* 返回当前支持的超链界面pane |
|
* |
|
* @return 超链连接界面 |
|
*/ |
|
public abstract HyperlinkGroupPane getHyperLinkPane(HyperlinkGroupPaneActionProvider hyperlinkGroupPaneActionProvider); |
|
|
|
/** |
|
* 返回当前支持的超链界面pane |
|
* 没有悬浮弹窗,显示为两列 |
|
* |
|
* @return 超链连接界面 |
|
*/ |
|
public abstract HyperlinkGroupPane getHyperLinkPaneNoPop(HyperlinkGroupPaneActionProvider hyperlinkGroupPaneActionProvider); |
|
|
|
/** |
|
* 是否是图表 |
|
* |
|
* @return 默认不是 |
|
*/ |
|
public boolean isChartBook() { |
|
return false; |
|
} |
|
|
|
public abstract void setAuthorityMode(boolean isUpMode); |
|
|
|
/** |
|
* 是否是参数面板的模式 |
|
* |
|
* @return 不是 |
|
*/ |
|
public boolean isUpMode() { |
|
return false; |
|
} |
|
|
|
/** |
|
* 设置预览方式 |
|
* |
|
* @param previewType |
|
*/ |
|
public void setPreviewType(PreviewProvider previewType) { |
|
if (this.previewType == previewType) { |
|
return; |
|
} |
|
this.previewType = previewType; |
|
getTarget().setPreviewType(previewType.previewTypeCode()); |
|
} |
|
|
|
/** |
|
* 得到预览的大图标 |
|
* |
|
* @return |
|
*/ |
|
public Icon getPreviewLargeIcon() { |
|
PreviewProvider provider = getPreviewType(); |
|
String iconPath = provider.iconPathForLarge(); |
|
return IconUtils.readIcon(iconPath); |
|
} |
|
|
|
/** |
|
* 获取所有参数 |
|
* |
|
* @return |
|
*/ |
|
public Parameter[] getParameters() { |
|
return new Parameter[0]; |
|
} |
|
|
|
/** |
|
* 获取模板参数 |
|
* |
|
* @return |
|
*/ |
|
public Parameter[] getJTemplateParameters() { |
|
return new Parameter[0]; |
|
} |
|
|
|
/** |
|
* 请求表单焦点 |
|
*/ |
|
public void requestGridFocus() { |
|
|
|
} |
|
|
|
/** |
|
* 创建内置sql提交的pane |
|
* |
|
* @return 内置sql提交的pane |
|
* @date 2014-10-14-下午7:39:27 |
|
*/ |
|
public DBManipulationPane createDBManipulationPane() { |
|
return new DBManipulationPane(); |
|
} |
|
|
|
/** |
|
* 创建控件事件里内置sql提交的pane |
|
* |
|
* @return 内置sql提交的pane |
|
* @date 2014-10-14-下午7:39:27 |
|
*/ |
|
public DBManipulationPane createDBManipulationPaneInWidget() { |
|
return new DBManipulationInWidgetEventPane(); |
|
} |
|
|
|
/** |
|
* 取小图标,主要用于多TAB标签栏 |
|
* |
|
* @return 图表 |
|
*/ |
|
public abstract Icon getIcon(); |
|
|
|
|
|
/** |
|
* 复制JS代码 |
|
*/ |
|
public void copyJS() { |
|
} |
|
|
|
/** |
|
* 系列风格改动 |
|
*/ |
|
public void styleChange() { |
|
|
|
} |
|
|
|
/** |
|
* 创建分享模板的按钮, 目前只有jworkbook实现了 |
|
* |
|
* @return 分享模板按钮 |
|
*/ |
|
public UIButton[] createShareButton() { |
|
return new UIButton[0]; |
|
} |
|
|
|
/** |
|
* 略 |
|
* |
|
* @param provider 预览模式 |
|
*/ |
|
public void previewMenuActionPerformed(PreviewProvider provider) { |
|
setPreviewType(provider); |
|
WebPreviewUtils.preview(this, provider); |
|
} |
|
|
|
/** |
|
* 支持的预览模式 |
|
* |
|
* @return 预览模式 |
|
*/ |
|
public PreviewProvider[] supportPreview() { |
|
return ExtraDesignClassManager.getInstance().getTemplatePreviews(new Filter<PreviewProvider>() { |
|
@Override |
|
public boolean accept(PreviewProvider previewProvider) { |
|
return previewProvider.accept(JTemplate.this); |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* 预览模式转换 |
|
* |
|
* @param typeCode 类型 |
|
* @return 预览模式 |
|
*/ |
|
public PreviewProvider parserPreviewProvider(int typeCode) { |
|
PreviewProvider pp = null; |
|
PreviewProvider[] previewProviders = supportPreview(); |
|
for (PreviewProvider p : previewProviders) { |
|
if (p.previewTypeCode() == typeCode) { |
|
pp = p; |
|
} |
|
} |
|
if (pp == null) { |
|
return new PagePreview(); |
|
} |
|
return pp; |
|
} |
|
|
|
public boolean acceptToolbarItem(Class clazz) { |
|
return true; |
|
} |
|
|
|
/** |
|
* 加载插件中的按钮 |
|
* |
|
* @return 按钮组 |
|
*/ |
|
public UIButton[] createExtraButtons() { |
|
UIButton[] uiButtons = new UIButton[0]; |
|
Set<DesignerFrameUpButtonProvider> providers = ExtraDesignClassManager.getInstance().getArray(DesignerFrameUpButtonProvider.XML_TAG); |
|
for (DesignerFrameUpButtonProvider provider : providers) { |
|
uiButtons = ArrayUtils.addAll(uiButtons, provider.getUpButtons(getMenuState())); |
|
} |
|
templateThemeButton = createTemplateThemeButton(); |
|
uiButtons = ArrayUtils.addAll(uiButtons, templateThemeButton); |
|
|
|
return uiButtons; |
|
} |
|
|
|
public UIButton[] createCheckButton() { |
|
return new UIButton[]{new CheckButton()}; |
|
} |
|
|
|
protected UIButton createTemplateThemeButton() { |
|
UIButton button = new UIButton(IconUtils.readIcon("/com/fr/design/standard/template_theme")) { |
|
@Override |
|
public Dimension getPreferredSize() { |
|
FontMetrics metrics = getFontMetrics(getFont()); |
|
int width = Math.min(metrics.stringWidth(getText()) + PREDEFINED_ICON_WIDTH, 100); |
|
return new Dimension(width, 20); |
|
} |
|
}; |
|
button.setToolTipText(getTemplateTheme().getName()); |
|
button.setText(getTemplateTheme().getName()); |
|
button.setName(getTemplateTheme().getName()); |
|
button.setAlignmentX(SwingConstants.LEFT); |
|
button.set4ToolbarButton(); |
|
button.setEnabled(true); |
|
return button; |
|
} |
|
|
|
/** |
|
* 由于老版本的模板没有模板ID,当勾选使用参数模板时候,就加一个模板ID attr |
|
* |
|
* @param isUseParamTemplate 是否使用参数模板 |
|
*/ |
|
public void needAddTemplateIdAttr(boolean isUseParamTemplate) { |
|
if (isUseParamTemplate && template.getAttrMark(TemplateIdAttrMark.XML_TAG) == null) { |
|
generateTemplateId(); |
|
} |
|
} |
|
|
|
private void generateTemplateId() { |
|
String templateId = UUID.randomUUID().toString(); |
|
template.addAttrMark(new TemplateIdAttrMark(templateId)); |
|
template.setTemplateID(templateId); |
|
} |
|
|
|
public abstract String route(); |
|
|
|
public String getTemplateName() { |
|
return getEditingFILE().getName() + compatibilityTip(); |
|
} |
|
|
|
/** |
|
* 设置新引擎后,有不支持的功能时,设计器中模板的标题需要加上“兼容模式”或者“不支持分页引擎”来提示用户 |
|
*/ |
|
private String compatibilityTip() { |
|
if (!CptAndCptxCompatibilityUtil.isEngineXEnable(this.getTarget(), getEditingFILE().getPath())) { |
|
return StringUtils.EMPTY; |
|
} |
|
String path = this.getEditingFILE().getPath(); |
|
CptxMetadata metadata = Paths.get(path).isAbsolute() ? null : CptxFileUtils.getMetadata(path); |
|
//是否是兼容模式,兼容模式下,设置了新引擎的cpt和cptx的后缀不同 |
|
if (metadata != null && metadata.isForceCpt()) { |
|
if (path.endsWith(".cptx")) { |
|
return InterProviderFactory.getProvider().getLocText("Fine-Plugin_Engine_Compatibility_Mode"); |
|
} else if (path.endsWith(".cpt")) { |
|
return InterProviderFactory.getProvider().getLocText("Fine-Plugin_Engine_Paging_Engine_Not_Work"); |
|
} |
|
} |
|
return StringUtils.EMPTY; |
|
} |
|
|
|
public String getTemplatePredefinedStyle() { |
|
return StringUtils.EMPTY; |
|
} |
|
|
|
/** |
|
* 指定 设计器界面 NORTH组件 |
|
* 默认是 菜单区域 |
|
* |
|
* @return NORTH组件 |
|
*/ |
|
public JComponent north4DesignerFrame() { |
|
return NorthRegionContainerPane.getInstance(); |
|
} |
|
|
|
/** |
|
* 指定 设计器界面 CENTER组件 |
|
* 默认是 模板对应的工具栏区域+模板设计区域 |
|
* |
|
* @return CENTER组件 |
|
*/ |
|
public JComponent center4DesignerFrame() { |
|
return CenterRegionContainerPane.getInstance(); |
|
} |
|
|
|
/** |
|
* 指定 设计器界面 WEST组件 |
|
* 默认是 模板目录树+数据集编辑区域 |
|
* |
|
* @return WEST组件 |
|
*/ |
|
public JComponent west4DesignerFrame() { |
|
return WestRegionContainerPane.getInstance(); |
|
} |
|
|
|
/** |
|
* 指定 设计器界面 EAST组件 |
|
* 默认是 属性配置界面 |
|
* |
|
* @return EAST组件 |
|
*/ |
|
public JComponent east4DesignerFrame() { |
|
return EastRegionContainerPane.getInstance(); |
|
} |
|
|
|
private CallbackSaveWorker save(boolean showLoc) { |
|
fireJTemplateSaveBefore(); |
|
FILE editingFILE = this.getEditingFILE(); |
|
// carl:editingFILE没有,当然不存了,虽然不会有这种情况 |
|
if (editingFILE == null) { |
|
return new EmptyCallBackSaveWorker(); |
|
} |
|
// 检查一下editingFILE是不是已存在的文件,如果不存在则用saveAs |
|
if (!editingFILE.exists()) { |
|
return saveAs(showLoc); |
|
} |
|
return getSaveCallBackSaveWorker(); |
|
} |
|
|
|
/** |
|
* 被云端运维插件修改用于收集埋点 |
|
*/ |
|
private boolean saveRealFileByWorker() throws Exception { |
|
collectInfo(); |
|
return saveRealFile(); |
|
} |
|
|
|
private void callBackForSave() { |
|
JTemplate.this.saved = true; |
|
JTemplate.this.authoritySaved = true; |
|
DesignerContext.getDesignerFrame().setTitle(); |
|
JTemplate.this.fireJTemplateSaved(); |
|
} |
|
|
|
private boolean saveRealFile() throws Exception { |
|
if (checkJTemplateAuthority()) { |
|
FILE editingFILE = this.getEditingFILE(); |
|
if (editingFILE == null || editingFILE instanceof MemFILE) { |
|
return false; |
|
} |
|
checkBeforeSave(); |
|
export(); |
|
this.editingFILE = editingFILE; |
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
private boolean checkJTemplateAuthority() { |
|
if (!FSConfig.getInstance().getAuthorizeAttr().isDataConnectionAuthority()) { |
|
return true; |
|
} |
|
JTemplateAuthorityChecker jTemplateAuthorityChecker = new JTemplateAuthorityChecker(this); |
|
if (jTemplateAuthorityChecker.isAuthority()) { |
|
return true; |
|
} else { |
|
jTemplateAuthorityChecker.showAuthorityFailPromptDialog(); |
|
return false; |
|
} |
|
} |
|
|
|
|
|
private CallbackSaveWorker saveAs(boolean showLoc) { |
|
FILE editingFILE = this.getEditingFILE(); |
|
if (editingFILE == null) { |
|
return new EmptyCallBackSaveWorker(); |
|
} |
|
String oldName = this.getPath(); |
|
// alex:如果是SaveAs的话需要让用户来选择路径了 |
|
FILEChooserPane fileChooser = getFILEChooserPane(showLoc); |
|
addChooseFILEFilter(fileChooser); |
|
fileChooser.setFileNameTextField(editingFILE.getName(), this.suffix()); |
|
int chooseResult = fileChooser.showSaveDialog(DesignerContext.getDesignerFrame(), this.suffix()); |
|
if (isCancelOperation(chooseResult)) { |
|
return new EmptyCallBackSaveWorker(); |
|
} |
|
// 源文件 |
|
FILE sourceFile = editingFILE; |
|
|
|
if (isOkOperation(chooseResult)) { |
|
// 目标文件 |
|
editingFILE = fileChooser.getSelectedFILE(); |
|
} |
|
FILE finalEditingFILE = editingFILE; |
|
CallbackSaveWorker worker = new CallbackSaveWorker(new Callable<Boolean>() { |
|
@Override |
|
public Boolean call() throws Exception { |
|
TemplateSaveInfoContext.getInstance().startRecord(); |
|
TemplateSaveInfoContext.getInstance().collectInfo(template.suffix()); |
|
return saveAs(finalEditingFILE, sourceFile, oldName); |
|
} |
|
}, this); |
|
|
|
worker.addSuccessCallback(new Runnable() { |
|
@Override |
|
public void run() { |
|
boolean isChangedFile = !JTemplate.this.saved; |
|
if (isChangedFile) { |
|
CptCompileUtil.compile(JTemplate.this); |
|
} |
|
callBackForSave(); |
|
// 当前打开的是正在保存的模板才刷新 |
|
if (ComparatorUtils.equals(JTemplate.this.template.getTemplateID(), |
|
HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().template.getTemplateID())) { |
|
refreshToolArea(); |
|
} |
|
DesignerFrameFileDealerPane.getInstance().refreshAndOutOfSearch(); |
|
DesignerFrameFileDealerPane.getInstance().stateChange(); |
|
} |
|
}); |
|
return worker; |
|
|
|
} |
|
|
|
private boolean saveAs(FILE editingFILE, FILE sourceFile, String oldName) throws Exception { |
|
boolean lockedTarget = |
|
// 目标本地文件 |
|
!editingFILE.isEnvFile() || |
|
// 目标远程文件 |
|
WorkContext.getCurrent().get(TplOperator.class).saveAs(editingFILE.getPath()); |
|
if (lockedTarget) { |
|
boolean saved = saveNewRealFile(editingFILE, oldName); |
|
// 目标文件保存成功并且源文件不一致的情况下,把源文件锁释放掉 |
|
if (saved && !ComparatorUtils.equals(editingFILE.getPath(), sourceFile.getPath())) { |
|
WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(sourceFile.getPath()); |
|
} |
|
return saved; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
/** |
|
* 另存为时在 save worker 中保存实际的文件; |
|
* 被云端运维插件修改用于收集埋点 |
|
*/ |
|
private boolean saveNewRealFile(FILE editingFILE, String oldName) throws Exception { |
|
|
|
String originID = StringUtils.EMPTY; |
|
String currentId = this.template.getTemplateID(); |
|
if (StringUtils.isNotEmpty(currentId)) { |
|
originID = currentId; |
|
} |
|
// 在保存之前,初始化 templateID |
|
generateNewTemplateIdForSaveAs(); |
|
computeForkIdIfAbsent(); |
|
|
|
this.editingFILE = editingFILE; |
|
boolean result = this.saveToNewRealFile(oldName); |
|
if (result) { |
|
collectInfoWhenSaveAs(originID); |
|
} |
|
return result; |
|
} |
|
|
|
private boolean saveToNewRealFile(String oldName) throws Exception { |
|
boolean result = false; |
|
Set<ReportSupportedFileUIProvider> providers = ExtraDesignClassManager.getInstance().getArray(ReportSupportedFileUIProvider.XML_TAG); |
|
for (ReportSupportedFileUIProvider provider : providers) { |
|
result = result || provider.saveToNewFile(this.editingFILE.getPath(), this); |
|
} |
|
if (!result) { |
|
/* |
|
* 1.在CptCompileUtil::haveChanged改变报表引擎属性 |
|
* 2.在这三种情况下:1.cptx文件另存为cpt文件 2.cptx另存为cptx文件 3.设置了新引擎的cpt文件另存为cpt文件, |
|
* 因为文件的编译目录改变了,需要重新预编译,因此设置jTemplate的保存状态为false |
|
* */ |
|
if (CptAndCptxCompatibilityUtil.needRecompile(oldName, this)) { |
|
this.saved = false; |
|
} |
|
result = this.saveRealFile(); |
|
// 更换最近打开 |
|
DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(oldName, this.getPath()); |
|
} |
|
return result; |
|
} |
|
|
|
@Override |
|
public CallbackSaveWorker save() { |
|
return save(true); |
|
} |
|
|
|
@Override |
|
public CallbackSaveWorker saveAs() { |
|
return saveAs(true); |
|
} |
|
|
|
/** |
|
* 获取保存用到的saveWorker |
|
*/ |
|
private CallbackSaveWorker getSaveCallBackSaveWorker() { |
|
CallbackSaveWorker worker = new CallbackSaveWorker(new Callable<Boolean>() { |
|
@Override |
|
public Boolean call() throws Exception { |
|
TemplateSaveInfoContext.getInstance().startRecord(); |
|
TemplateSaveInfoContext.getInstance().collectInfo(template.suffix()); |
|
return saveRealFileByWorker(); |
|
} |
|
}, this); |
|
|
|
worker.addSuccessCallback(new Runnable() { |
|
@Override |
|
public void run() { |
|
callBackForSave(); |
|
//在保存后的回调中执行预编译流程 |
|
CptCompileUtil.compile(JTemplate.this); |
|
} |
|
}); |
|
return worker; |
|
} |
|
|
|
/** |
|
* 获取保存的类别执行的callable |
|
*/ |
|
private Callable<SaveType.TypeEnum> getSaveTypeCallable() { |
|
return () -> { |
|
fireJTemplateSaveBefore(); |
|
FILE editingFILE = getEditingFILE(); |
|
// carl:editingFILE没有,当然不存了,虽然不会有这种情况 |
|
if (editingFILE == null) { |
|
return SaveType.TypeEnum.EMPTY; |
|
} |
|
// 检查一下editingFILE是不是已存在的文件,如果不存在则用saveAs |
|
if (!editingFILE.exists()) { |
|
return SaveType.TypeEnum.SAVE_AS; |
|
} |
|
return SaveType.TypeEnum.SAVE; |
|
}; |
|
} |
|
|
|
/** |
|
* 根据保存类型获取对应的saveWorker |
|
* |
|
* @param saveType 保存类型 |
|
*/ |
|
private CallbackSaveWorker getSaveTypeWorker(SaveType saveType) { |
|
CallbackSaveWorker callbackSaveWorker; |
|
switch (saveType.getType()) { |
|
case EMPTY: |
|
callbackSaveWorker = new EmptyCallBackSaveWorker(); |
|
break; |
|
case SAVE: |
|
callbackSaveWorker = getSaveCallBackSaveWorker(); |
|
break; |
|
default: |
|
callbackSaveWorker = saveAs(true); |
|
} |
|
return callbackSaveWorker; |
|
} |
|
|
|
|
|
@Override |
|
public void saveDirectly() { |
|
if (isSaving()) { |
|
// 处理连按ctrl+s触发多线程保存的问题 |
|
// 这里为什么可以不用加锁而直接判断isSaving: |
|
// 实测actionPerformed有线程安全的特性,同一时间只有一个AWT线程走到这里,setSaving是线程安全的(SaveTemplateAction.actionPerformed) |
|
// 多线程场景是因为我们用了SwingWorker子线程处理保存 |
|
return; |
|
} |
|
new SaveTypeWorker(getSaveTypeCallable(), this) { |
|
@Override |
|
protected void done() { |
|
try { |
|
SaveType saveType = get(); |
|
CallbackSaveWorker callbackSaveWorker = getSaveTypeWorker(saveType); |
|
//告诉一下后面执行的saveWorker,当前判断文件是否存在的操作是否已经进行了开始转圈的那个等待动画,避免重复 |
|
callbackSaveWorker.setSlowly(saveType.isSlowly()); |
|
callbackSaveWorker.start(getRuntimeId()); |
|
//如果是空也就是不保存,需要恢复一下界面(如果saveTypeWorker里进行了操作的话) |
|
if (callbackSaveWorker instanceof EmptyCallBackSaveWorker) { |
|
setSaving(false); |
|
if (saveType.isSlowly()) { |
|
if (ComparatorUtils.equals(getName(), HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getName())) { |
|
DesignerContext.getDesignerFrame().getCenterTemplateCardPane().hideCover(); |
|
} |
|
} |
|
DesignerFrameFileDealerPane.getInstance().stateChange(); |
|
} |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
}.start(); |
|
} |
|
|
|
@Override |
|
public void saveAsDirectly() { |
|
CallbackSaveWorker worker = saveAs(); |
|
worker.start(getRuntimeId()); |
|
} |
|
|
|
@Override |
|
public CallbackSaveWorker save2Env() { |
|
return save(false); |
|
} |
|
|
|
@Override |
|
public CallbackSaveWorker saveAs2Env() { |
|
return saveAs(false); |
|
} |
|
|
|
public boolean isSaving() { |
|
return saving; |
|
} |
|
|
|
public void setSaving(boolean saving) { |
|
this.saving = saving; |
|
} |
|
|
|
public boolean isOpening() { |
|
return opening; |
|
} |
|
|
|
public void setOpening(boolean opening) { |
|
this.opening = opening; |
|
} |
|
|
|
public boolean isOpenFailed() { |
|
return openFailed; |
|
} |
|
|
|
public void setOpenFailed(boolean openFailed) { |
|
this.openFailed = openFailed; |
|
} |
|
|
|
public boolean isForbidden() { |
|
return forbidden; |
|
} |
|
|
|
public void setForbidden(boolean forbidden) { |
|
this.forbidden = forbidden; |
|
} |
|
|
|
public boolean checkEnable() { |
|
return !isSaving() && !isOpening() && !isOpenFailed() && !isForbidden(); |
|
} |
|
|
|
public String getRuntimeId() { |
|
return runtimeId; |
|
} |
|
|
|
protected void setUpTheme4NewTemplate() { |
|
TemplateTheme theme = getUsingTemplateThemeConfig().cachedFetchTheme4NewTemplate(); |
|
TemplateThemeAttrMark themeAttrMark = getTarget().getAttrMark(TemplateThemeAttrMark.XML_TAG); |
|
if (themeAttrMark == null) { |
|
themeAttrMark = new TemplateThemeAttrMark(); |
|
getTarget().addAttrMark(themeAttrMark); |
|
} |
|
themeAttrMark.setName(theme.getName()); |
|
themeAttrMark.setDark(theme.isDark()); |
|
} |
|
|
|
public String getTemplateOpenFailedTip() { |
|
return templateOpenFailedTip; |
|
} |
|
|
|
public void setTemplateOpenFailedTip(String templateOpenFailedTip) { |
|
this.templateOpenFailedTip = templateOpenFailedTip; |
|
} |
|
|
|
@Override |
|
public void setTemplateTheme(TemplateTheme newTheme, TemplateThemeCompatible compatible) { |
|
if (templateThemeButton != null) { |
|
ThemedTemplate.super.setTemplateTheme(newTheme, compatible); |
|
String name = newTheme.getName(); |
|
templateThemeButton.setText(name); |
|
templateThemeButton.setToolTipText(name); |
|
} |
|
} |
|
|
|
/** |
|
* 定位 |
|
* |
|
* @param trl |
|
*/ |
|
public void navigate(TRL trl) { |
|
|
|
} |
|
|
|
public void generateForBiddenTemplate() { |
|
|
|
} |
|
|
|
public void setDesignerUIMode() { |
|
DesignerUIModeConfig.getInstance().setAbsoluteMeasureUIMode(); |
|
} |
|
|
|
/** |
|
* 判断当前的模板是否是有效的模板 |
|
* |
|
* @param jt 模板 |
|
* @return 是/否 |
|
*/ |
|
public static boolean isValid(JTemplate jt) { |
|
return jt != null && jt != JNullTemplate.NULL; |
|
} |
|
|
|
/** |
|
* 获取此模板所使用的tab栏操作类型 |
|
* |
|
* @return |
|
*/ |
|
public String getTemplateTabOperatorType() { |
|
return DEFAULT_TAB_OPERATOR; |
|
} |
|
|
|
/** |
|
* 当前模板是否可以被保存 |
|
* |
|
* @return 是/否 |
|
*/ |
|
public boolean canBeSaved() { |
|
return true; |
|
} |
|
|
|
/** |
|
* 当前的模板是否支持缓存 |
|
* |
|
* @return 是/否 |
|
*/ |
|
public boolean supportCache() { |
|
return true; |
|
} |
|
|
|
/** |
|
* 获取此模板在tab栏中显示的名称 |
|
* |
|
* @return |
|
*/ |
|
public String getTabShowName(JTemplate<?, ?> jTemplate) { |
|
String name = TemplateUtils.createLockeTemplatedName(jTemplate, jTemplate.getTemplateName()); |
|
if (!jTemplate.isSaved() && !name.endsWith(" *")) { |
|
name += " *"; |
|
} |
|
return name; |
|
} |
|
|
|
/** |
|
* 切换环境之前是否需要保存 |
|
* |
|
* @return |
|
*/ |
|
public boolean needSaveBeforeSwitchEnv() { |
|
return false; |
|
} |
|
|
|
}
|
|
|