diff --git a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java index 1fb6a94a81..6d8d5b9c0c 100644 --- a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java +++ b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java @@ -130,6 +130,11 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private int westRegionContainerWidth = 240; private String encryptionKey; private String jdkHome; + private boolean vcsEnable; + private boolean saveCommit; + private int saveInterval; + + //上一次登录弹窗的时间, 为了控制一天只弹一次窗口 private String lastShowBBSTime; @@ -1341,6 +1346,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { } } + private void readJettyPort(XMLableReader reader) { String tmpVal; if ((tmpVal = reader.getElementValue()) != null) { @@ -1601,6 +1607,9 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { this.setDragPermited(reader.getAttrAsBoolean("isDragPermited", false)); this.setUndoLimit(reader.getAttrAsInt("undoLimit", 5)); this.setDefaultStringToFormula(reader.getAttrAsBoolean("defaultStringToFormula", false)); + this.setVcsEnable(reader.getAttrAsBoolean("supportVcs", true)); + this.setSaveCommit(reader.getAttrAsBoolean("saveCommit", false)); + this.setSaveInterval(reader.getAttrAsInt("saveInterval", 60)); if ((tmpVal = reader.getAttrAsString("gridLineColor", null)) != null) { this.setGridLineColor(new Color(Integer.parseInt(tmpVal))); } @@ -1936,6 +1945,9 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { .attr("verticalScrollBarVisible", this.isVerticalScrollBarVisible()) .attr("horizontalScrollBarVisible", this.isHorizontalScrollBarVisible()) .attr("supportCellEditorDef", this.isSupportCellEditorDef()) + .attr("supportVcs", this.isVcsEnable()) + .attr("saveInterval", this.getSaveInterval()) + .attr("saveCommit", this.isSaveCommit()) .attr("isDragPermited", this.isDragPermited()) .attr("gridLineColor", this.getGridLineColor().getRGB()) .attr("paginationLineColor", this.getPaginationLineColor().getRGB()) @@ -1946,4 +1958,28 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private void writeDesignerPushUpdateAttr(XMLPrintWriter writer) { this.designerPushUpdateConfigManager.writeXML(writer); } + + public boolean isVcsEnable() { + return vcsEnable; + } + + public void setVcsEnable(boolean vcsEnable) { + this.vcsEnable = vcsEnable; + } + + public boolean isSaveCommit() { + return saveCommit; + } + + public void setSaveCommit(boolean saveCommit) { + this.saveCommit = saveCommit; + } + + public int getSaveInterval() { + return saveInterval; + } + + public void setSaveInterval(int saveInterval) { + this.saveInterval = saveInterval; + } } diff --git a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java index aa679de9bf..e7db515af5 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java @@ -41,6 +41,8 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; @@ -135,6 +137,12 @@ public class PreferencePane extends BasicPane { private UICheckBox joinProductImproveCheckBox; private UICheckBox autoPushUpdateCheckBox; + private UICheckBox vcsEnableCheckBox; + private UICheckBox saveCommitCheckBox; + private IntegerEditor saveIntervalEditor; + + + public PreferencePane() { this.initComponents(); } @@ -155,6 +163,7 @@ public class PreferencePane extends BasicPane { createEditPane(generalPane); createGuiOfGridPane(generalPane); createColorSettingPane(generalPane); + createVcsSettingPane(generalPane); // ConfPane JPanel confLocationPane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); @@ -193,6 +202,36 @@ public class PreferencePane extends BasicPane { advancePane.add(spaceUpPane); } + private void createVcsSettingPane(JPanel generalPane) { + JPanel vcsPane = FRGUIPaneFactory.createVerticalTitledBorderPane(Toolkit.i18nText("Fine-Design_Vcs_Title")); + generalPane.add(vcsPane); + vcsEnableCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Vcs_SaveAuto")); + saveCommitCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Vcs_No_Delete")); + saveIntervalEditor = new IntegerEditor(30); + JPanel memorySpace = new JPanel(FRGUIPaneFactory.createLeftZeroLayout()); + UILabel everyLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Every")); + UILabel delayLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Delay")); + memorySpace.add(everyLabel); + memorySpace.add(saveIntervalEditor); + memorySpace.add(delayLabel); + vcsEnableCheckBox.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + boolean selected = vcsEnableCheckBox.isSelected(); + if (selected) { + saveCommitCheckBox.setEnabled(true); + saveIntervalEditor.setEnabled(true); + } else { + saveCommitCheckBox.setEnabled(false); + saveIntervalEditor.setEnabled(false); + } + } + }); + vcsPane.add(vcsEnableCheckBox); + vcsPane.add(memorySpace); + vcsPane.add(saveCommitCheckBox); + } + private void createFunctionPane(JPanel generalPane) { JPanel functionPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preference_Function")); generalPane.add(functionPane); @@ -542,6 +581,13 @@ public class PreferencePane extends BasicPane { defaultStringToFormulaBox.setEnabled(false); defaultStringToFormulaBox.setSelected(false); } + vcsEnableCheckBox.setSelected(designerEnvManager.isVcsEnable()); + if (!vcsEnableCheckBox.isSelected()) { + saveIntervalEditor.setEnabled(false); + saveCommitCheckBox.setEnabled(false); + } + saveIntervalEditor.setValue(designerEnvManager.getSaveInterval()); + saveCommitCheckBox.setSelected(designerEnvManager.isSaveCommit()); supportCellEditorDefCheckBox.setSelected(designerEnvManager.isSupportCellEditorDef()); @@ -631,6 +677,9 @@ public class PreferencePane extends BasicPane { designerEnvManager.setOracleSystemSpace(this.oracleSpace.isSelected()); designerEnvManager.setCachingTemplateLimit((int) this.cachingTemplateSpinner.getValue()); designerEnvManager.setJoinProductImprove(this.joinProductImproveCheckBox.isSelected()); + designerEnvManager.setSaveInterval(this.saveIntervalEditor.getValue()); + designerEnvManager.setVcsEnable(this.vcsEnableCheckBox.isSelected()); + designerEnvManager.setSaveCommit(this.saveCommitCheckBox.isSelected()); if (this.autoPushUpdateCheckBox != null) { designerEnvManager.setAutoPushUpdateEnabled(this.autoPushUpdateCheckBox.isSelected()); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java index cef5c86a08..32b9d11401 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java @@ -26,6 +26,7 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.vcs.ui.FileVersionsPanel; import com.fr.design.menu.KeySetUtils; import com.fr.design.menu.ShortCut; import com.fr.design.menu.ToolBarDef; @@ -43,9 +44,12 @@ import com.fr.plugin.manage.PluginFilter; import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEventListener; import com.fr.stable.CoreConstants; +import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; import com.fr.third.org.apache.commons.io.FilenameUtils; import com.fr.workspace.WorkContext; +import com.fr.design.mainframe.vcs.common.VcsHelper; import javax.swing.BorderFactory; import javax.swing.JDialog; @@ -111,6 +115,8 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt private DelFileAction delFileAction = new DelFileAction(); + private VcsAction vcsAction = new VcsAction(); + /** * 刷新 @@ -191,7 +197,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt if (WorkContext.getCurrent().isLocal()) { toolbarDef.addShortCut(showInExplorerAction); } - toolbarDef.addShortCut(renameAction, delFileAction); + toolbarDef.addShortCut(renameAction, delFileAction, vcsAction); Set extraShortCuts = ExtraDesignClassManager.getInstance().getExtraShortCuts(); for (ShortCut shortCut : extraShortCuts) { toolbarDef.addShortCut(shortCut); @@ -209,6 +215,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt showInExplorerAction.setEnabled(false); renameAction.setEnabled(false); delFileAction.setEnabled(false); + vcsAction.setEnabled(false); this.repaint(); } @@ -273,6 +280,62 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } + /** + * 版本管理 + */ + private class VcsAction extends UpdateAction { + public VcsAction() { + this.setName(Toolkit.i18nText("Fine-Design_Vcs_Title")); + this.setSmallIcon(VcsHelper.VCS_LIST_PNG); + } + + @Override + public void actionPerformed(ActionEvent e) { + String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + path = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, path); + + boolean isCurrentEditing = isCurrentEditing(path); + + // 如果模板正在编辑,保存后再打开版本管理 + if (isCurrentEditing) { + saveCurrentEditingTemplate(); + } + + // 如果模板已经打开了,关掉,避免出现2个同名tab(1个是模板,1个是版本) + closeOpenedTemplate(path, isCurrentEditing); + FileVersionsPanel fileVersionTablePanel = FileVersionsPanel.getInstance(); + fileVersionTablePanel.showFileVersionsPane(); + } + + private void closeOpenedTemplate(String path, boolean isCurrentEditing) { + for (JTemplate jTemplate : HistoryTemplateListCache.getInstance().getHistoryList()) { + if (ComparatorUtils.equals(jTemplate.getEditingFILE().getPath(), path)) { + if (isCurrentEditing) { + MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); + } + MutilTempalteTabPane.getInstance().closeFormat(jTemplate); + MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jTemplate); + return; + } + } + } + + + } + + private void saveCurrentEditingTemplate() { + JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + jt.stopEditing(); + jt.saveTemplate(); + jt.requestFocus(); + } + + private boolean isCurrentEditing(String path) { + JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + String editing = jt.getEditingFILE().getPath(); + return ComparatorUtils.equals(editing, path); + } + /** * 在系统资源管理器中打开 */ @@ -386,18 +449,45 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt newFolderAction.setEnabled(singleSelected); renameAction.setEnabled(singleSelected); showInExplorerAction.setEnabled(singleSelected); - // 删除操作在至少选中一个时可用 boolean selected = selectedPathNum > 0; delFileAction.setEnabled(selected); - // 刷新操作始终可用 refreshTreeAction.setEnabled(true); + handleVcsAction(); // 其他状态 otherStateChange(); } + private void handleVcsAction() { + if (!DesignerEnvManager.getEnvManager().isVcsEnable() || VcsHelper.isUnSelectedTemplate()) { + vcsAction.setEnabled(false); + return; + } + + if (WorkContext.getCurrent() != null) { + if (!WorkContext.getCurrent().isLocal()) { + //当前环境为远程环境时 + FileNode node = TemplateTreePane.getInstance().getTemplateFileTree().getSelectedFileNode(); + if (selectedOperation.getFilePath() != null) { + if (node.getLock() != null && !ComparatorUtils.equals(node.getUserID(), node.getLock())) { + vcsAction.setEnabled(false); + } else { + vcsAction.setEnabled(true); + } + } else { + vcsAction.setEnabled(false); + } + } else { + //当前环境为本地环境时 + vcsAction.setEnabled(selectedOperation.getFilePath() != null); + } + } + } + + + public FileOperations getSelectedOperation() { return selectedOperation; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java index 4c45ce823e..ffd9aaf3b4 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfo.java @@ -102,6 +102,10 @@ class TemplateInfo implements XMLReadable, XMLWriter { return templateID; } + String getOriginID() { + return originID; + } + int getTimeConsume() { return (int)consumingMap.get(ATTR_TIME_CONSUME); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java index 30bfb5e1d6..c16c6b6275 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/template/info/TemplateInfoCollector.java @@ -75,11 +75,8 @@ public class TemplateInfoCollector implements XMLReadable, XMLWriter { TemplateInfo templateInfo; if (this.contains(templateID)) { templateInfo = templateInfoMap.get(templateID); - } else if (!this.contains(originID)) { - templateInfo = TemplateInfo.newInstance(templateID); - templateInfoMap.put(templateID, templateInfo); } else { - int originTime = templateInfoMap.get(originID).getTimeConsume(); + int originTime = this.contains(originID) ? templateInfoMap.get(originID).getTimeConsume() : 0; templateInfo = TemplateInfo.newInstance(templateID, originID, originTime); templateInfoMap.put(templateID, templateInfo); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCacheFileNodeFile.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCacheFileNodeFile.java new file mode 100644 index 0000000000..9933fc0e74 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCacheFileNodeFile.java @@ -0,0 +1,71 @@ +package com.fr.design.mainframe.vcs.common; + +import com.fr.base.io.XMLEncryptUtils; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.general.ComparatorUtils; +import com.fr.stable.StableUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.resource.WorkResource; +import com.fr.workspace.resource.WorkResourceOutputStream; + +import java.io.InputStream; +import java.io.OutputStream; + + +public class VcsCacheFileNodeFile extends FileNodeFILE { + + private final FileNode node; + + public VcsCacheFileNodeFile(FileNode node) { + super(node); + this.node = node; + } + + /** + * 和FileNodeFILE中一样,只是去掉了必须以reportlets开头的限制,改为vcs开头 + * + * @return + * @throws Exception + */ + @Override + public InputStream asInputStream() { + if (node == null) { + return null; + } + + String envPath = node.getEnvPath(); + // envPath必须以vcs开头 + if (!envPath.startsWith(VcsHelper.VCS_CACHE_DIR)) { + return null; + } + + InputStream in = WorkContext.getCurrent().get(WorkResource.class) + .openStream(StableUtils.pathJoin(VcsHelper.VCS_CACHE_DIR, envPath.substring(VcsHelper.VCS_CACHE_DIR.length() + 1))); + + return envPath.endsWith(".cpt") || envPath.endsWith(".frm") + ? XMLEncryptUtils.decodeInputStream(in) : in; + } + + + /** + * 和FileNodeFILE中一样,只是去掉了必须以reportlets开头的限制,改为vcs开头 + * + * @return + * @throws Exception + */ + @Override + public OutputStream asOutputStream() { + if (ComparatorUtils.equals(node, null)) { + return null; + } + + String envPath = node.getEnvPath(); + // envPath必须以reportLets开头 + if (!envPath.startsWith(VcsHelper.VCS_CACHE_DIR)) { + return null; + } + + return new WorkResourceOutputStream(StableUtils.pathJoin(VcsHelper.VCS_CACHE_DIR, envPath.substring(VcsHelper.VCS_CACHE_DIR.length() + 1))); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java new file mode 100644 index 0000000000..27c606f4c3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java @@ -0,0 +1,100 @@ +package com.fr.design.mainframe.vcs.common; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.gui.itree.filetree.TemplateFileTree; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.JTemplate; +import com.fr.general.IOUtils; +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; + +import javax.swing.Icon; +import javax.swing.border.EmptyBorder; +import java.awt.Color; +import java.util.Date; + +import static com.fr.stable.StableUtils.pathJoin; + +/** + * Created by XiaXiang on 2019/4/17. + */ +public class VcsHelper { + + private final static String VCS_DIR = "vcs"; + public final static String VCS_CACHE_DIR = pathJoin(VCS_DIR, "cache"); + private static final int MINUTE = 60 * 1000; + + + public final static String CURRENT_USERNAME = WorkContext.getCurrent().isLocal() + ? Toolkit.i18nText("Fine-Design_Vcs_Local_User") + : WorkContext.getCurrent().getConnection().getUserName(); + + public final static Color TABLE_SELECT_BACKGROUND = new Color(0xD8F2FD); + + public final static EmptyBorder EMPTY_BORDER = new EmptyBorder(5, 10, 0, 10); + + public final static EmptyBorder EMPTY_BORDER_BOTTOM = new EmptyBorder(10, 10, 10, 10); + + + public final static Icon VCS_LIST_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/vcs_list.png"); + public final static Icon VCS_BACK_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/vcs_back.png"); + public final static Icon VCS_FILTER_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_filter@1x.png"); + public final static Icon VCS_EDIT_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_edit.png"); + public final static Icon VCS_DELETE_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_delete.png"); + public final static Icon VCS_USER_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_user@1x.png"); + public final static Icon VCS_REVERT = IOUtils.readIcon("/com/fr/design/images/vcs/icon_revert.png"); + + private static int containsFolderCounts() { + TemplateFileTree fileTree = TemplateTreePane.getInstance().getTemplateFileTree(); + if (fileTree.getSelectionPaths() == null) { + return 0; + } + + //选择的包含文件和文件夹的数目 + if (fileTree.getSelectionPaths().length == 0) { + return 0; + } + //所有的num减去模板的count,得到文件夹的count + return fileTree.getSelectionPaths().length - fileTree.getSelectedTemplatePaths().length; + } + + private static int selectedTemplateCounts() { + TemplateFileTree fileTree = TemplateTreePane.getInstance().getTemplateFileTree(); + if (fileTree.getSelectionPaths() == null) { + return 0; + } + + return fileTree.getSelectedTemplatePaths().length; + } + + public static boolean isUnSelectedTemplate() { + return VcsHelper.containsFolderCounts() + VcsHelper.selectedTemplateCounts() != 1; + } + + public static String getEditingFilename() { + JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + String editingFilePath = jt.getEditingFILE().getPath(); + if (editingFilePath.startsWith(ProjectConstants.REPORTLETS_NAME)) { + editingFilePath = editingFilePath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); + } else if (editingFilePath.startsWith(VcsHelper.VCS_CACHE_DIR)) { + editingFilePath = editingFilePath.replaceFirst(VcsHelper.VCS_CACHE_DIR, StringUtils.EMPTY); + } + if (editingFilePath.startsWith("/")) { + editingFilePath = editingFilePath.substring(1); + } + return editingFilePath; + } + + public static boolean needDeleteVersion(VcsEntity entity) { + if (entity == null) { + return false; + } + return new Date().getTime() - entity.getTime().getTime() < DesignerEnvManager.getEnvManager().getSaveInterval() * MINUTE && StringUtils.isBlank(entity.getCommitMsg()); + } + + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java new file mode 100644 index 0000000000..f6533de4df --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java @@ -0,0 +1,99 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.dialog.UIDialog; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextarea.UITextArea; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.locale.InterProviderFactory; +import com.fr.report.ReportContext; +import com.fr.report.entity.VcsEntity; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + + +/** + * 编辑版本信息面板 + */ +public class EditFileVersionDialog extends UIDialog { + + private final UITextArea msgTestArea = new UITextArea(); + private final UILabel versionLabel = new UILabel(); + private VcsEntity entity; + + public EditFileVersionDialog(VcsEntity entity) { + this(DesignerContext.getDesignerFrame()); + this.entity = entity; + msgTestArea.setText(entity.getCommitMsg()); + versionLabel.setText(String.valueOf(entity.getVersion())); + } + + private EditFileVersionDialog(Frame parent) { + super(parent); + + initComponents(); + setModal(true); + setTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Save_Version")); + setSize(300, 220); + setResizable(false); + GUICoreUtils.centerWindow(this); + + } + + private void initComponents() { + + JPanel fontPane = new JPanel(new BorderLayout()); + fontPane.add(new UILabel(" " + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Version_Message") + ":"), BorderLayout.NORTH); + + msgTestArea.setBorder(null); + UIScrollPane scrollPane = new UIScrollPane(msgTestArea); + + Component[][] components = new Component[][]{ + new Component[]{new UILabel(" " + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Version_Number") + ":"), versionLabel}, + new Component[]{fontPane, scrollPane} + }; + double[] rowSizes = new double[]{25, 100}; + double[] columnSizes = new double[]{70, 200}; + + add(TableLayoutHelper.createTableLayoutPane(components, rowSizes, columnSizes), BorderLayout.CENTER); + + JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + add(buttonPane, BorderLayout.SOUTH); + + UIButton ok = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_OK")); + UIButton cancel = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Design_Action_Cancel")); + + buttonPane.add(ok); + buttonPane.add(cancel); + + ok.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + entity.setCommitMsg(msgTestArea.getText()); + ReportContext.getInstance().getVcsController().saveOrUpdateFileVersion(entity); + setVisible(false); + } + }); + + cancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + doCancel(); + } + }); + } + + @Override + public void checkValid() throws Exception { + + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellEditor.java new file mode 100644 index 0000000000..bdb4bc1eea --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellEditor.java @@ -0,0 +1,74 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.design.mainframe.vcs.common.VcsCacheFileNodeFile; +import com.fr.file.filetree.FileNode; +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; + +import javax.swing.AbstractCellEditor; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellEditor; +import java.awt.Component; + + +public class FileVersionCellEditor extends AbstractCellEditor implements TableCellEditor { + private static final long serialVersionUID = -7299526575184810693L; + //第一行 + private final JPanel firstRowPanel; + //其余行 + private final FileVersionRowPanel renderAndEditor; + + public FileVersionCellEditor() { + this.firstRowPanel = new FileVersionFirstRowPanel(); + this.renderAndEditor = new FileVersionRowPanel(); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + String fileOfVersion; + Component editor = row == 0 ? firstRowPanel : renderAndEditor; + if (isSelected) { + return editor; + } else if (row == 0) { + String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + fileOfVersion = WorkContext.getCurrent().get(VcsOperator.class).getFileOfCurrent(path.replaceFirst("/", "")); + } else { + renderAndEditor.update((VcsEntity) value); + fileOfVersion = WorkContext.getCurrent().get(VcsOperator.class).getFileOfFileVersion(((VcsEntity) value).getFilename(), ((VcsEntity) value).getVersion()); + + } + + editor.setBackground(VcsHelper.TABLE_SELECT_BACKGROUND); + if (StringUtils.isNotEmpty(fileOfVersion)) { + //先关闭当前打开的模板版本 + JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + jt.stopEditing(); + MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); + MutilTempalteTabPane.getInstance().closeFormat(jt); + MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jt); + //再打开cache中的模板 + DesignerContext.getDesignerFrame().openTemplate(new VcsCacheFileNodeFile(new FileNode(fileOfVersion, false))); + + } + + double height = editor.getPreferredSize().getHeight(); + if (table.getRowHeight(row) != height) { + table.setRowHeight(row, (int) height); + } + return editor; + } + + @Override + public Object getCellEditorValue() { + return renderAndEditor.getVcsEntity(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellRender.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellRender.java new file mode 100644 index 0000000000..c1cc23fc45 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellRender.java @@ -0,0 +1,43 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.report.entity.VcsEntity; + +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; + +import static com.fr.design.constants.UIConstants.TREE_BACKGROUND; +import static com.fr.design.mainframe.vcs.common.VcsHelper.TABLE_SELECT_BACKGROUND; + + +public class FileVersionCellRender implements TableCellRenderer { + + //第一行 + private final JPanel firstRowPanel; + //其余行 + private final FileVersionRowPanel render; + + public FileVersionCellRender() { + this.render = new FileVersionRowPanel(); + this.firstRowPanel = new FileVersionFirstRowPanel(); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component editor = row == 0 ? firstRowPanel : render; + // https://stackoverflow.com/questions/3054775/jtable-strange-behavior-from-getaccessiblechild-method-resulting-in-null-point + if (value != null) { + render.update((VcsEntity) value); + } + editor.setBackground(isSelected ? TABLE_SELECT_BACKGROUND : TREE_BACKGROUND); + + double height = editor.getPreferredSize().getHeight(); + if (table.getRowHeight(row) != height) { + table.setRowHeight(row, (int) height); + } + return editor; + } + + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionDialog.java new file mode 100644 index 0000000000..6f6c925382 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionDialog.java @@ -0,0 +1,92 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.dialog.UIDialog; +import com.fr.design.editor.editor.DateEditor; +import com.fr.design.gui.date.UIDatePicker; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; + +import javax.swing.AbstractAction; +import javax.swing.Box; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Date; +import java.util.List; + +import static com.fr.design.mainframe.vcs.common.VcsHelper.EMPTY_BORDER; +import static com.fr.design.mainframe.vcs.common.VcsHelper.EMPTY_BORDER_BOTTOM; + + +public class FileVersionDialog extends UIDialog { + public static final long DELAY = 24 * 60 * 60 * 1000; + private UIButton okBtn = new UIButton(Toolkit.i18nText("Fine-Design_Report_OK")); + private UIButton cancelBtn = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Utils_Design_Action_Cancel")); + private DateEditor dateEditor; + private UITextField textField; + + + public FileVersionDialog(Frame frame) { + super(frame); + setUndecorated(true); + JPanel panel = new JPanel(new BorderLayout()); + Box upBox = Box.createHorizontalBox(); + upBox.setBorder(EMPTY_BORDER_BOTTOM); + upBox.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_buildTime"))); + upBox.add(Box.createHorizontalGlue()); + dateEditor = new DateEditor(new Date(), true, StringUtils.EMPTY, UIDatePicker.STYLE_CN_DATE1); + upBox.add(dateEditor); + Box downBox = Box.createHorizontalBox(); + downBox.setBorder(EMPTY_BORDER_BOTTOM); + downBox.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_CommitMsg"))); + textField = new UITextField(); + downBox.add(textField); + Box box2 = Box.createHorizontalBox(); + box2.add(Box.createHorizontalGlue()); + box2.setBorder(EMPTY_BORDER); + box2.add(okBtn); + box2.add(cancelBtn); + okBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + FileVersionDialog.this.setVisible(false); + Date date = dateEditor.getValue(); + List vcsEntities = WorkContext.getCurrent().get(VcsOperator.class).getFilterVersions(date, new Date(date.getTime() + DELAY), textField.getText()); + FileVersionTable.getInstance().updateModel(1, vcsEntities); + + } + }); + cancelBtn.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + FileVersionDialog.this.setVisible(false); + } + }); + panel.add(upBox, BorderLayout.NORTH); + panel.add(downBox, BorderLayout.CENTER); + panel.add(box2, BorderLayout.SOUTH); + add(panel); + setSize(new Dimension(220, 100)); + centerWindow(this); + } + + private void centerWindow(Window window) { + window.setLocation(0, 95); + + } + + @Override + public void checkValid() throws Exception { + + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionFirstRowPanel.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionFirstRowPanel.java new file mode 100644 index 0000000000..9d892ba535 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionFirstRowPanel.java @@ -0,0 +1,21 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; + +import javax.swing.Box; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import java.awt.BorderLayout; + + +public class FileVersionFirstRowPanel extends JPanel { + + public FileVersionFirstRowPanel() { + super(new BorderLayout()); + Box upPane = Box.createVerticalBox(); + upPane.setBorder(new EmptyBorder(5, 10, 5, 10)); + upPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Local_User"))); + add(upPane, BorderLayout.CENTER); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionRowPanel.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionRowPanel.java new file mode 100644 index 0000000000..78f8c62f44 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionRowPanel.java @@ -0,0 +1,149 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.gui.frpane.UITextPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.log.FineLoggerFactory; +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; + +import javax.swing.Box; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.text.BadLocationException; +import javax.swing.text.Style; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.text.SimpleDateFormat; +import java.util.Date; + + +public class FileVersionRowPanel extends JPanel { + + private VcsEntity vcsEntity; + private UILabel versionLabel = new UILabel(); + private UILabel usernameLabel = new UILabel(StringUtils.EMPTY, VcsHelper.VCS_USER_PNG, SwingConstants.LEFT); + private UITextPane timeAndMsgLabel = new UITextPane(); + private UILabel timeLabel = new UILabel(); + private EditFileVersionDialog editDialog; + + + public FileVersionRowPanel() { + setLayout(new BorderLayout()); + + // version + username + Box upPane = Box.createHorizontalBox(); + upPane.setBorder(VcsHelper.EMPTY_BORDER); + upPane.add(versionLabel); + upPane.add(Box.createHorizontalGlue()); + + + // msg + timeAndMsgLabel.setBorder(VcsHelper.EMPTY_BORDER); + timeAndMsgLabel.setOpaque(false); + timeAndMsgLabel.setBackground(new Color(0, 0, 0, 0)); + timeAndMsgLabel.setEditable(false); + + // confirm + delete + UIButton confirmBtn = new UIButton(VcsHelper.VCS_REVERT); + confirmBtn.set4ToolbarButton(); + confirmBtn.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Revert")); + confirmBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + if (JOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Vcs_Version_Revert_Confirm"), Toolkit.i18nText("Fine-Design_Vcs_Version_Revert_Title"), + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + WorkContext.getCurrent().get(VcsOperator.class).rollbackTo(vcsEntity); + FileVersionsPanel.getInstance().exitVcs(vcsEntity.getFilename()); + } + } + }); + UIButton deleteBtn = new UIButton(VcsHelper.VCS_DELETE_PNG); + deleteBtn.set4ToolbarButton(); + deleteBtn.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Delete")); + deleteBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + if (JOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Vcs_Delete-Confirm"), Toolkit.i18nText("Fine-Design_Vcs_Remove"), + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + try { + WorkContext.getCurrent().get(VcsOperator.class).deleteVersion(vcsEntity.getFilename(), vcsEntity.getVersion()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + FileVersionTable table = (FileVersionTable) (FileVersionRowPanel.this.getParent()); + String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + try { + table.updateModel(table.getSelectedRow() - 1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", ""))); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + } + }); + UIButton editBtn = new UIButton(VcsHelper.VCS_EDIT_PNG); + editBtn.set4ToolbarButton(); + editBtn.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Edit")); + editBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showEditDialog(); + + } + }); + upPane.add(editBtn); + upPane.add(confirmBtn); + upPane.add(deleteBtn); + Box downPane = Box.createHorizontalBox(); + downPane.add(usernameLabel); + downPane.setBorder(VcsHelper.EMPTY_BORDER_BOTTOM); + downPane.add(Box.createHorizontalGlue()); + downPane.add(timeLabel); + add(upPane, BorderLayout.NORTH); + add(timeAndMsgLabel, BorderLayout.CENTER); + add(downPane, BorderLayout.SOUTH); + } + + private void showEditDialog() { + this.editDialog = new EditFileVersionDialog(vcsEntity); + + editDialog.setVisible(true); + update(vcsEntity); + } + + + public void update(final VcsEntity fileVersion) { + this.vcsEntity = fileVersion; + versionLabel.setText(String.format("V.%s", fileVersion.getVersion())); + usernameLabel.setText(fileVersion.getUsername()); + timeAndMsgLabel.setText(StringUtils.EMPTY); + timeLabel.setText(timeStr(fileVersion.getTime())); + try { + StyledDocument doc = timeAndMsgLabel.getStyledDocument(); + Style style = timeAndMsgLabel.getLogicalStyle(); + StyleConstants.setForeground(style, Color.BLACK); + doc.insertString(doc.getLength(), " " + fileVersion.getCommitMsg(), style); + } catch (BadLocationException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + + private String timeStr(Date time) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return simpleDateFormat.format(time); + } + + public VcsEntity getVcsEntity() { + return vcsEntity; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionTable.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionTable.java new file mode 100644 index 0000000000..aa9c87ca01 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionTable.java @@ -0,0 +1,79 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.report.entity.VcsEntity; + +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; +import java.util.List; + + +public class FileVersionTable extends JTable { + private static volatile FileVersionTable instance; + + private FileVersionTable() { + super(new CellModel(new ArrayList())); + + setDefaultRenderer(VcsEntity.class, new FileVersionCellRender()); + setDefaultEditor(VcsEntity.class, new FileVersionCellEditor()); + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + setTableHeader(null); + setRowHeight(30); + } + + public static FileVersionTable getInstance() { + if (instance == null) { + synchronized (FileVersionTable.class) { + if (instance == null) { + instance = new FileVersionTable(); + } + } + } + return instance; + } + + public void updateModel(int selectedRow, List entities) { + if (selectedRow > entities.size()) { + selectedRow = entities.size(); + } + setModel(new CellModel(entities)); + editCellAt(selectedRow, 0); + setRowSelectionInterval(selectedRow, selectedRow); + } + + private static class CellModel extends AbstractTableModel { + private static final long serialVersionUID = -6078568799037607690L; + private List vcsEntities; + + + CellModel(List vcsEntities) { + this.vcsEntities = vcsEntities; + } + + public Class getColumnClass(int columnIndex) { + return VcsEntity.class; + } + + public int getColumnCount() { + return 1; + } + + public int getRowCount() { + return (vcsEntities == null) ? 0 : vcsEntities.size() + 1; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + if (rowIndex == 0) { + return null; + } + return (vcsEntities == null) ? null : vcsEntities.get(rowIndex - 1); + } + + public boolean isCellEditable(int columnIndex, int rowIndex) { + return true; + } + + + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionsPanel.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionsPanel.java new file mode 100644 index 0000000000..2e68e0e33c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionsPanel.java @@ -0,0 +1,200 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.base.GraphHelper; +import com.fr.design.base.mode.DesignModeContext; +import com.fr.design.dialog.BasicPane; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itoolbar.UIToolbar; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.ToolBarNewTemplatePane; +import com.fr.design.mainframe.WestRegionContainerPane; +import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.design.menu.ToolBarDef; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StableUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + + +public class FileVersionsPanel extends BasicPane { + private static final String ELLIPSIS = "..."; + private static volatile FileVersionsPanel instance; + + private UILabel titleLabel; + private String templatePath; + private UIButton filterBtn; + private FileVersionDialog versionDialog; + + + private FileVersionsPanel() { + initComponents(); + } + + public static FileVersionsPanel getInstance() { + if (instance == null) { + synchronized (FileVersionsPanel.class) { + if (instance == null) { + instance = new FileVersionsPanel(); + } + } + } + return instance; + } + + private void initComponents() { + setLayout(new BorderLayout()); + UIToolbar toolbar = ToolBarDef.createJToolBar(); + toolbar.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0)); + toolbar.setBorderPainted(true); + Box upPane = Box.createHorizontalBox(); + UIButton backBtn = new UIButton(VcsHelper.VCS_BACK_PNG); + backBtn.set4ToolbarButton(); + backBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + exitVcs(templatePath); + } + }); + toolbar.add(backBtn); + filterBtn = new UIButton(VcsHelper.VCS_FILTER_PNG); + filterBtn.set4ToolbarButton(); + filterBtn.setHorizontalAlignment(SwingConstants.RIGHT); + filterBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showFilterPane(); + } + }); + titleLabel = new UILabel() { + @Override + public Dimension getMaximumSize() { + return new Dimension(257, 21); + } + }; + upPane.add(titleLabel); + upPane.add(Box.createHorizontalGlue()); + upPane.add(filterBtn); + toolbar.add(Box.createHorizontalGlue()); + toolbar.add(upPane); + add(toolbar, BorderLayout.NORTH); + + UIScrollPane jScrollPane = new UIScrollPane(FileVersionTable.getInstance()); + add(jScrollPane, BorderLayout.CENTER); + } + + private void showFilterPane() { + versionDialog = new FileVersionDialog(DesignerContext.getDesignerFrame()); + versionDialog.setVisible(true); + } + + + /** + * 退出版本管理,并且打开模板 + * + * @param path 被管理的模板的名字 + */ + public void exitVcs(String path) { + + // 关闭当前打开的版本 + JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); + MutilTempalteTabPane.getInstance().closeFormat(jt); + MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jt); + + updateDesignerFrame(true); + + final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, path); + DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); + } + + private void refreshVersionTablePane() { + templatePath = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + String[] paths = StableUtils.pathSplit(templatePath); + String filename = paths[paths.length - 1]; + int width = FileVersionTable.getInstance().getWidth() - 40; + if (getStringWidth(filename) > width) { + filename = getEllipsisName(filename, width); + } + titleLabel.setText(filename); + String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", ""))); + } + + public void showFileVersionsPane() { + updateDesignerFrame(false); + refreshVersionTablePane(); + } + + @Override + protected String title4PopupWindow() { + return null; + } + + + private void updateDesignerFrame(boolean isExit) { + // 左上侧面板 + WestRegionContainerPane.getInstance().replaceUpPane( + isExit ? DesignerFrameFileDealerPane.getInstance() : this); + + DesignModeContext.switchTo(isExit ? com.fr.design.base.mode.DesignerMode.NORMAL : com.fr.design.base.mode.DesignerMode.VCS); + // MutilTempalteTabPane & NewTemplatePane 是否可点 + ToolBarNewTemplatePane.getInstance().setButtonGray(!isExit); + + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentEditingTemplate.isJWorkBook()) { + DesignerContext.getDesignerFrame().resetToolkitByPlus(currentEditingTemplate); + } + } + + + private int getStringWidth(String str) { + return GraphHelper.getFontMetrics(this.getFont()).stringWidth(str); + } + + + private String getEllipsisName(String name, int maxStringlength) { + + //若是名字长度大于能显示的长度,那能显示的文字的最大长度还要减去省略号的最大长度 +// int maxellipsislength = maxStringlength - ELLIPSIS.length(); + int ellipsisWidth = getStringWidth(ELLIPSIS); + int leftkeyPoint = 0; + int rightKeyPoint = name.length() - 1; + int leftStrWidth = 0; + int rightStrWidth = 0; + while (leftStrWidth + rightStrWidth + ellipsisWidth < maxStringlength) { + if (leftStrWidth <= rightStrWidth) { + leftkeyPoint++; + } else { + rightKeyPoint--; + } + leftStrWidth = getStringWidth(name.substring(0, leftkeyPoint)); + rightStrWidth = getStringWidth(name.substring(rightKeyPoint)); + + if (leftStrWidth + rightStrWidth + ellipsisWidth > maxStringlength) { + if (leftStrWidth <= rightStrWidth) { + rightKeyPoint++; + } + break; + } + } + + return name.substring(0, leftkeyPoint) + ELLIPSIS + name.substring(rightKeyPoint); + } +} diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_back_normal@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_back_normal@2x.png new file mode 100644 index 0000000000..bb3fd50cdc Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_back_normal@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_delete.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_delete.png new file mode 100755 index 0000000000..6fb2baac51 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_delete.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_delete@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_delete@2x.png new file mode 100755 index 0000000000..b98c9f4cd2 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_delete@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_edit.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_edit.png new file mode 100755 index 0000000000..7206039bf6 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_edit.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_edit@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_edit@2x.png new file mode 100755 index 0000000000..5993e43897 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_edit@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_filter@1x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_filter@1x.png new file mode 100755 index 0000000000..7a8ec6287b Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_filter@1x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_filter@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_filter@2x.png new file mode 100755 index 0000000000..9b3a132a77 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_filter@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_disabled.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_disabled.png new file mode 100644 index 0000000000..5325682ff8 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_disabled.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_disabled@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_disabled@2x.png new file mode 100644 index 0000000000..619551cc86 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_disabled@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_normal@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_normal@2x.png new file mode 100644 index 0000000000..a400bffeca Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_list_normal@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_revert.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_revert.png new file mode 100755 index 0000000000..993ba3c21b Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_revert.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_revert@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_revert@2x.png new file mode 100755 index 0000000000..5f26df54c0 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_revert@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_disabled.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_disabled.png new file mode 100644 index 0000000000..3e164a0ebf Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_disabled.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_disabled@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_disabled@2x.png new file mode 100644 index 0000000000..70db7bcc49 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_disabled@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_normal@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_normal@2x.png new file mode 100644 index 0000000000..34e94cb270 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_save_normal@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_user@1x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_user@1x.png new file mode 100755 index 0000000000..7af8db5727 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_user@1x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/icon_user@2x.png b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_user@2x.png new file mode 100755 index 0000000000..872351544a Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/icon_user@2x.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_back.png b/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_back.png new file mode 100644 index 0000000000..6b3a61b894 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_back.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_list.png b/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_list.png new file mode 100644 index 0000000000..df6cd02de6 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_list.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_save.png b/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_save.png new file mode 100644 index 0000000000..6783204cf8 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/vcs/vcs_save.png differ diff --git a/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java b/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java index 7b02f4bba2..e83a523fc4 100644 --- a/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java +++ b/designer-base/src/test/java/com/fr/design/mainframe/template/info/TemplateInfoCollectorTest.java @@ -66,9 +66,12 @@ public class TemplateInfoCollectorTest { @Test public void testReadXML() { + assertEquals(",,", DesignerOpenHistory.getInstance().toString()); + TemplateInfoCollector collector = TemplateInfoCollector.getInstance(); - assertEquals("2019-04-18", Reflect.on(collector).field("designerOpenDate").get()); assertEquals(7, ((Map) Reflect.on(collector).field("templateInfoMap").get()).size()); + + assertEquals("2019-04-08,2019-04-03,2019-03-29", DesignerOpenHistory.getInstance().toString()); } @Test @@ -151,6 +154,29 @@ public class TemplateInfoCollectorTest { assertEquals(129, consumingMap.get("originTime")); } + @Test + public void testCollectInfoWhenSaveAsWithNoTrackOriginID() throws Exception { + setUpMockForNewInstance(); + + TemplateInfoCollector collector = TemplateInfoCollector.getInstance(); + + String templateID = "423238d4-5223-22vj-vlsj-42jc49245iw3"; + String originID = "3kha8jcs-31xw-42f5-h2ww-2ee84935312z"; + int timeConsume = 200; + + collector.collectInfo(templateID, originID, mockProcessInfo, timeConsume); + + TemplateInfo templateInfo = collector.getOrCreateTemplateInfoByID(templateID); + assertEquals(templateID, templateInfo.getTemplateID()); + assertEquals(originID, templateInfo.getOriginID()); + + Map consumingMap = Reflect.on(templateInfo).field("consumingMap").get(); + assertEquals(templateID, consumingMap.get("templateID")); + assertEquals(originID, consumingMap.get("originID")); + assertEquals(200, consumingMap.get("time_consume")); + assertEquals(0, consumingMap.get("originTime")); + } + @Test public void testAddIdleDateCount() { String templateID = "16a988ce-8529-42f5-b17c-2ee849355071"; diff --git a/designer-base/src/test/resources/com/fr/design/mainframe/template/info/tpl.info b/designer-base/src/test/resources/com/fr/design/mainframe/template/info/tpl.info index 39bec00067..eae77630fa 100644 --- a/designer-base/src/test/resources/com/fr/design/mainframe/template/info/tpl.info +++ b/designer-base/src/test/resources/com/fr/design/mainframe/template/info/tpl.info @@ -1,7 +1,7 @@ - - + + diff --git a/designer-realize/src/main/java/com/fr/start/Designer.java b/designer-realize/src/main/java/com/fr/start/Designer.java index 23bf2f0ffe..a2f6c92c76 100644 --- a/designer-realize/src/main/java/com/fr/start/Designer.java +++ b/designer-realize/src/main/java/com/fr/start/Designer.java @@ -12,6 +12,7 @@ import com.fr.design.actions.server.ServerConfigManagerAction; import com.fr.design.actions.server.StyleListAction; import com.fr.design.actions.server.WidgetManagerAction; import com.fr.design.constants.UIConstants; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.file.MutilTempalteTabPane; import com.fr.design.fun.MenuHandler; @@ -22,6 +23,7 @@ import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.gui.itoolbar.UILargeToolbar; import com.fr.design.mainframe.ActiveKeyGenerator; import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.InformationCollector; import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JWorkBook; @@ -30,6 +32,8 @@ import com.fr.design.mainframe.bbs.UserInfoLabel; import com.fr.design.mainframe.bbs.UserInfoPane; import com.fr.design.mainframe.template.info.TemplateInfoCollector; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; +import com.fr.design.mainframe.vcs.common.VcsCacheFileNodeFile; +import com.fr.design.mainframe.vcs.ui.FileVersionTable; import com.fr.design.menu.KeySetUtils; import com.fr.design.menu.MenuDef; import com.fr.design.menu.SeparatorDef; @@ -42,6 +46,7 @@ import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.module.Module; import com.fr.module.ModuleContext; +import com.fr.report.entity.VcsEntity; import com.fr.runtime.FineRuntime; import com.fr.stable.BuildContext; import com.fr.stable.OperatingSystem; @@ -56,6 +61,8 @@ import com.fr.start.module.StartupArgs; import com.fr.start.preload.ImagePreLoader; import com.fr.start.server.ServerTray; import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; +import com.fr.design.mainframe.vcs.common.VcsHelper; import javax.swing.JComponent; import javax.swing.JOptionPane; @@ -107,7 +114,6 @@ public class Designer extends BaseDesigner { System.exit(0); return; } - RestartHelper.deleteRecordFilesWhenStart(); preloadResource(); @@ -270,15 +276,50 @@ public class Designer extends BaseDesigner { saveButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - JTemplate jt = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); + JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); jt.stopEditing(); jt.saveTemplate(); jt.requestFocus(); + if (DesignerEnvManager.getEnvManager().isVcsEnable()) { + dealWithVcs(jt); + } } }); return saveButton; } + /** + * 版本控制 + * @param jt + */ + private void dealWithVcs(final JTemplate jt) { + new Thread(new Runnable() { + @Override + public void run() { + String fileName = VcsHelper.getEditingFilename(); + VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); + VcsEntity entity = operator.getFileVersionByIndex(fileName, 0); + int latestFileVersion = 0; + if (entity != null) { + latestFileVersion = entity.getVersion(); + } + if (jt.getEditingFILE() instanceof VcsCacheFileNodeFile) { + operator.saveVersionFromCache(VcsHelper.CURRENT_USERNAME, fileName, StringUtils.EMPTY, latestFileVersion + 1); + String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", ""))); + } else { + operator.saveVersion(VcsHelper.CURRENT_USERNAME, fileName, StringUtils.EMPTY, latestFileVersion + 1); + } + VcsEntity oldEntity = WorkContext.getCurrent().get(VcsOperator.class).getFileVersionByIndex(fileName, 1); + if (VcsHelper.needDeleteVersion(oldEntity)) { + operator.deleteVersion(oldEntity.getFilename(), oldEntity.getVersion()); + } + + } + }).start(); + + } + private UIButton createUndoButton() { undo = new UIButton(BaseUtils.readIcon("/com/fr/design/images/buttonicon/undo.png")); undo.setToolTipText(KeySetUtils.UNDO.getMenuKeySetName());