package com.fr.design.mainframe; import com.fr.base.BaseUtils; import com.fr.base.Parameter; import com.fr.base.TRL; import com.fr.base.extension.FileExtension; import com.fr.base.io.BaseBook; import com.fr.base.iofile.attr.DesignBanCopyAttrMark; 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.worker.save.CallbackSaveWorker; import com.fr.design.worker.save.EmptyCallBackSaveWorker; import com.fr.design.worker.save.SaveFailureHandler; 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.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.workspace.WorkContext; 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.Set; import java.util.concurrent.Callable; /** * 报表设计和表单设计的编辑区域(设计器编辑的IO文件) */ public abstract class JTemplate> extends TargetComponent implements ToolBarMenuDockPlus, DesignerProxy, JTemplateSave, TabChangeListener, ThemedTemplate { // 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 processInfo; private JComponent centerPane; private DesignModelAdapter 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 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 (isUsingThemeChanged && (event.action == TemplateThemeConfig.ThemeConfigAction.REMOVE || event.action == TemplateThemeConfig.ThemeConfigAction.UPDATE)) { checkAndResetTheme(); } } }; TemplateThemeConfig config = getUsingTemplateThemeConfig(); if (config != null) { config.addThemeConfigChangeListener(themeConfigChangeListener); } } } private void stopListenThemeConfig() { if (themeConfigChangeListener != null) { TemplateThemeConfig config = getUsingTemplateThemeConfig(); if (config != null) { config.removeThemeConfigChangeListener(themeConfigChangeListener); } } } private void initPluginPane() { ExtraDesignClassManager classManager = PluginModule.getAgent(PluginModule.ExtraDesign); Set providers = classManager.getArray(PropertyItemPaneProvider.XML_TAG); for (PropertyItemPaneProvider provider : providers) { addPane(provider); } } @Override public void fireTabChange() { // do nothing } protected 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(); } /** * 收集图表信息 */ 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 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]; } /** * 刷新内部资源 *

* 刷新资源的同时。 * 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 createDesignModel(); protected DesignModelAdapter createDesignModel(Parameter[] parameters) { // 空实现 兼容下 return null; } /** * 创建菜单项Preview * * @return 菜单 */ public abstract UIMenuItem[] createMenuItem4Preview(); /** * @return */ public DesignModelAdapter 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(); fireSuperTargetModified(); } /** * 重做 */ public void redo() { this.getUndoManager().redo(); // 重做前模版使用主题可能已经被删除或修改,需要重置模版样式 checkAndResetTheme(); 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(); return this.saveFile(); } 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(); this.editingFILE = editingFILE; boolean result = this.saveToNewFile(oldName); if (result) { DesignerFrameFileDealerPane.getInstance().refresh(); collectInfoWhenSaveAs(originID); } return result; } protected boolean saveToNewFile(String oldName) { boolean result = false; String path = this.editingFILE.getPath(); Set 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 { // 保存前校验下未解锁 if (WorkContext.getCurrent().get(LockInfoOperator.class).isTplUnLocked(getEditingFILE().getPath())) { throw new UnLockedException(); } // 过滤掉本地文件 boolean localFile = getEditingFILE() instanceof FileFILE; boolean inconsistent = !localFile && getEditingFILE().exists() && !WorkContext.getCurrent().get(LockInfoOperator.class).isConsistentLock(getEditingFILE().getPath()); 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()); 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) { 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; } /** * 返回当前支持的超链界面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 BaseUtils.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() { @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 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); } CallbackSaveWorker worker = new CallbackSaveWorker(new Callable() { @Override public Boolean call() throws Exception { return saveRealFileByWorker(); } }, this); worker.addSuccessCallback(new Runnable() { @Override public void run() { callBackForSave(); //在保存后的回调中执行预编译流程 CptCompileUtil.compile(JTemplate.this); } }); return worker; } /** * 被云端运维插件修改用于收集埋点 */ 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() { @Override public Boolean call() throws Exception { 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(); 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 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); } @Override public void saveDirectly() { CallbackSaveWorker worker = save(); worker.start(getRuntimeId()); } @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; } }