diff --git a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java b/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java index 58d9b0e88..8da6b7a3b 100644 --- a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java +++ b/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java @@ -239,11 +239,7 @@ public class TemplateTreePane extends JPanel implements FileOperations { String reportPath = reportletsTree.getSelectedTemplatePath(); final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, reportPath); String lock = node.getLock(); - boolean showLockInfo = LockInfoUtils.isCompatibleOperator() - || LockInfoUtils.unableGetLockInfo() - || WorkContext.getCurrent().get(LockInfoOperator.class).isTplUnLocked(selectedFilePath) - ? (lock != null && !lock.equals(node.getUserID())) - : WorkContext.getCurrent().get(LockInfoOperator.class).isTplLocked(selectedFilePath); + boolean showLockInfo = needShowLockInfo(lock, selectedFilePath, node); if (showLockInfo) { UserInfo userInfo = WorkContext.getCurrent().get(LockInfoOperator.class).getUserInfo(selectedFilePath); node.setLock(UUID.randomUUID().toString()); @@ -257,6 +253,17 @@ public class TemplateTreePane extends JPanel implements FileOperations { DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); } + /** + * 是否需要展示锁定信息 + */ + public static boolean needShowLockInfo(String lock, String selectedFilePath, FileNode node) { + return LockInfoUtils.isCompatibleOperator() + || LockInfoUtils.unableGetLockInfo() + || WorkContext.getCurrent().get(LockInfoOperator.class).isTplUnLocked(selectedFilePath) + ? (lock != null && !lock.equals(node.getUserID())) + : WorkContext.getCurrent().get(LockInfoOperator.class).isTplLocked(selectedFilePath); + } + private void checkDevelopForBiddenTemplate(String selectedFilePath) { JTemplate template = getOpenedTemplate(selectedFilePath); if (template != null && template.isForbidden()) { diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java b/designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java index c843dfebd..654de0d72 100644 --- a/designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java @@ -83,21 +83,20 @@ public enum MimeType { * 如果没有,尝试使用 Files.probeContentType 检测 * 如果没有,默认返回 text/html * - * @param url url路径 + * @param resourcePath 资源路径 * @return MimeType */ - public static String parseMimeType(String url) { - if (StringUtils.isBlank(url)) { + public static String parseMimeType(String resourcePath) { + if (StringUtils.isBlank(resourcePath)) { return HTML.mimeType; } - String finalPath = url.split("\\?")[0]; Optional mimeType = Arrays.stream(values()) - .filter(type -> finalPath.endsWith(type.suffix)) + .filter(type -> resourcePath.endsWith(type.suffix)) .findFirst(); if (mimeType.isPresent()) { return mimeType.get().mimeType; } else { - return getFileMimeType(finalPath); + return getFileMimeType(resourcePath); } } diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java b/designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java index ada7b2fff..58d45a61f 100644 --- a/designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java @@ -20,6 +20,7 @@ import com.teamdev.jxbrowser.net.callback.InterceptUrlRequestCallback; import org.jetbrains.annotations.NotNull; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.Map; @@ -80,8 +81,9 @@ public class NxInterceptRequestCallback implements InterceptUrlRequestCallback { protected Optional generateFileProtocolUrlRequestJob(Params params, String path) { try { - InputStream inputStream = getResourceStream(path); - String mimeType = MimeType.parseMimeType(path); + String resourcePath = getResourcePath(path); + InputStream inputStream = getResourceStream(resourcePath); + String mimeType = MimeType.parseMimeType(resourcePath); byte[] bytes; if (isHtml(mimeType)) { String text = IOUtils.inputStream2String(inputStream, EncodeConstants.ENCODING_UTF_8); @@ -104,7 +106,11 @@ public class NxInterceptRequestCallback implements InterceptUrlRequestCallback { * @return 输入流 * @throws Exception IO异常 */ - private InputStream getResourceStream(String path) throws Exception { + private InputStream getResourceStream(String path) { + return IOUtils.readResource(path); + } + + private static String getResourcePath(String path) throws UnsupportedEncodingException { int index = path.indexOf("="); if (index > 0) { path = path.substring(index + 1); @@ -115,7 +121,7 @@ public class NxInterceptRequestCallback implements InterceptUrlRequestCallback { // 通过自定义协议之后的url会自动encode一些中文字符,这里做一个decode,否则会导致路径访问失败 path = URLDecoder.decode(path, StandardCharsets.UTF_8.name()); } - return IOUtils.readResource(path); + return path; } private boolean isHtml(String mimeType) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java b/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java index 51fe2f816..30ff6c891 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java @@ -3,6 +3,9 @@ package com.fr.design.mainframe.chart.mode; import com.fr.common.annotations.Open; import com.fr.design.base.mode.DesignModeContext; +import java.util.HashSet; +import java.util.Set; + /** * @author shine * @version 10.0 @@ -13,6 +16,19 @@ public class ChartEditContext { private static ChartEditMode current = ChartEditMode.NORMAL; + private static final Set features = new HashSet<>(); + + /** + * 功能点枚举 + */ + public enum DuchampFeature { + SUPPORT_REPORT_DATA + } + + /** + * 切换图表编辑模式 + * @param mode 图表编辑模式 + */ public static void switchTo(ChartEditMode mode) { current = mode; } @@ -33,4 +49,28 @@ public class ChartEditContext { public static boolean supportTheme() { return !DesignModeContext.isDuchampMode(); } + + /** + * 注册功能点 + */ + public static void addDuchampFeature(DuchampFeature feature) { + features.add(feature); + } + + /** + * 移除功能点 + */ + public static void removeDuchampFeature(DuchampFeature feature) { + features.remove(feature); + } + + /** + * 当前模式下是否支持单元格数据来源 + */ + public static boolean supportReportData() { + if (normalMode()) { + return true; + } + return features.contains(DuchampFeature.SUPPORT_REPORT_DATA); + } } 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 index 07007604d..15787348f 100644 --- 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 @@ -255,13 +255,17 @@ public class VcsHelper implements JTemplateActionListener { VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); String oldPath = oldName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY); List oldVcsEntities = operator.getVersions(oldPath); - + String replaceName = newName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY); for (VcsEntity oldVcsEntity : oldVcsEntities) { - operator.saveVersion(oldVcsEntity.getUsername(), newName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY), oldVcsEntity.getCommitMsg(), oldVcsEntity.getVersion()); - operator.deleteVersion(oldPath, oldVcsEntity.getVersion()); + if (!VcsHelper.getInstance().isLegacyMode()) { + operator.renameVersion(oldVcsEntity, replaceName); + } else { + operator.saveVersion(oldVcsEntity.getUsername(), replaceName, oldVcsEntity.getCommitMsg(), oldVcsEntity.getVersion()); + operator.deleteVersion(oldPath, oldVcsEntity.getVersion()); + } } - FineLoggerFactory.getLogger().debug("moveVcs success. from {} to {}", oldName, newName); - if (GcConfig.getInstance().isGcEnable()) { + FineLoggerFactory.getLogger().debug("moveVcs success. from {} to {}", oldName, replaceName); + if (GcConfig.getInstance().isGcEnable() && VcsHelper.getInstance().isLegacyMode()) { operator.gc(); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java index 9efb268a0..4ca132ea5 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java @@ -4,8 +4,10 @@ import com.fr.base.svg.IconUtils; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.TemplateTreePane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; +import com.fr.design.lock.LockInfoUtils; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.vcs.VcsOperatorWorker; @@ -15,6 +17,7 @@ import com.fr.design.mainframe.vcs.common.VcsCloseTemplateHelper; import com.fr.file.FileNodeFILE; import com.fr.file.filetree.FileNode; import com.fr.report.entity.VcsEntity; +import com.fr.report.lock.LockInfoOperator; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.project.ProjectConstants; @@ -25,10 +28,13 @@ import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.UIManager; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; /** @@ -148,12 +154,35 @@ public class VcsCenterPane extends VcsNewPane { if (o instanceof VcsTableEntity) { VcsEntity entity = ((VcsTableEntity) o).getEntity(); saveSettingAndCloseDialog(); - DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(getTemplateTruePath(entity.getFilename()), false))); + showTemplate(entity.getFilename(), new FileNode(getTemplateTruePath(entity.getFilename()), false)); } } }); } + private void showTemplate(String filename, FileNode node) { + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + String selectedFilePath = getTemplateTruePath(filename); + String lock = node.getLock(); + return TemplateTreePane.needShowLockInfo(lock, selectedFilePath, node); + } + @Override + protected void done() { + try { + if (!get()) { + DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(node)); + } else { + FineJOptionPane.showMessageDialog(VcsCenterPane.this, Toolkit.i18nText("Fine-Design_Vcs_Open_Lock_Tip"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + } + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }.execute(); + } + private void initManagerListener() { manager.addMouseListener(new MouseAdapter() { @Override @@ -212,12 +241,6 @@ public class VcsCenterPane extends VcsNewPane { return TITLE; } - - private String getTemplateTruePath(String filename) { - return StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, filename); - } - - @Override protected String getDeleteTip(int size) { return Toolkit.i18nText("Fine-Design_Vcs_Delete_Select_All_Version"); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java index b924228fd..8e5e22c47 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java @@ -4,6 +4,7 @@ import com.fr.base.svg.IconUtils; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.MultiTemplateTabPane; +import com.fr.design.file.TemplateTreePane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; @@ -16,10 +17,15 @@ import com.fr.design.mainframe.vcs.common.VcsCacheFileNodeFile; import com.fr.design.mainframe.vcs.common.VcsHelper; import com.fr.file.FileNodeFILE; import com.fr.file.filetree.FileNode; +import com.fr.file.filetree.FileNodes; import com.fr.io.utils.ResourceIOUtils; +import com.fr.report.InconsistentLockException; import com.fr.report.entity.VcsEntity; +import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; import com.fr.workspace.WorkContext; +import com.fr.workspace.resource.WorkResource; import com.fr.workspace.server.vcs.VcsFileUtils; import com.fr.workspace.server.vcs.VcsOperator; import com.fr.workspace.server.vcs.v2.VcsTaskResult; @@ -29,6 +35,7 @@ import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.SwingWorker; +import javax.swing.UIManager; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -179,9 +186,12 @@ public class VcsNewPane extends RecyclePane { @Override protected VcsTaskResult doInBackground() throws Exception { String path = VcsHelper.getInstance().getFilePath(entity); - if (!ResourceIOUtils.exist(path)) { + if (!WorkContext.getCurrent().get(WorkResource.class).exist(path)) { return new VcsTaskResult(false, new FileNotFoundException()); } + if (checkLock(entity.getFilename())) { + return new VcsTaskResult(false, new InconsistentLockException()); + } //step1.设置还原的用户名 entity.setUsername(VcsHelper.getInstance().getCurrentUsername()); //step2.rollback到指定版本 @@ -206,7 +216,11 @@ public class VcsNewPane extends RecyclePane { } DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(filePath, false))); } else { - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Warning_Template_Do_Not_Exsit")); + if (result.getException() instanceof FileNotFoundException) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Warning_Template_Do_Not_Exsit")); + } else { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Vcs_Open_Lock_Tip"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + } } } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); @@ -215,6 +229,19 @@ public class VcsNewPane extends RecyclePane { }.execute(); } + private boolean checkLock(String filename) { + String selectedFilePath = getTemplateTruePath(filename); + FileNode node = new FileNode(getTemplateTruePath(filename), false); + String lock = node.getLock(); + return TemplateTreePane.needShowLockInfo(lock, selectedFilePath, node); + } + + /** + * 获取模板的路径 + */ + public String getTemplateTruePath(String filename) { + return StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, filename); + } private void initDeleteListener() { delete.addMouseListener(new MouseAdapter() { diff --git a/designer-base/src/test/java/com/fr/design/jxbrowser/MimeTypeTest.java b/designer-base/src/test/java/com/fr/design/jxbrowser/MimeTypeTest.java index 6a5fcf7f4..abfdb6fcf 100644 --- a/designer-base/src/test/java/com/fr/design/jxbrowser/MimeTypeTest.java +++ b/designer-base/src/test/java/com/fr/design/jxbrowser/MimeTypeTest.java @@ -13,9 +13,10 @@ public class MimeTypeTest { @Test public void getMimeType() { Assert.assertEquals("text/html", MimeType.parseMimeType("http://a.html")); - Assert.assertEquals("text/html", MimeType.parseMimeType("http://a.html?a=ji")); - Assert.assertEquals("text/html", MimeType.parseMimeType("http://a.xml?a=ji")); - Assert.assertEquals("image/jpeg", MimeType.parseMimeType("http://a.jpg?a=ji")); - Assert.assertEquals("image/jpeg", MimeType.parseMimeType("http://a.jpeg?a=ji")); + Assert.assertEquals("truetype", + MimeType.parseMimeType("emb://com/fr/web/ui/resources?path=/com/fr/web/ui/font/iconfont.ttf")); + Assert.assertEquals("font/woff", + MimeType.parseMimeType("http://a.html?path=com/fr/ui/a.woff")); + // 对资源来说不存在http://a.jpg?a=ji这种情况,之前多虑了 } } \ No newline at end of file diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java index 86f7e4da8..ba1701710 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java @@ -68,7 +68,7 @@ public class NormalChartDataPane extends DataContentsPane { label1.setPreferredSize(new Dimension(ChartDataPane.LABEL_WIDTH,ChartDataPane.LABEL_HEIGHT)); northPane.add(GUICoreUtils.createBorderLayoutPane(new Component[]{jcb, null, null, label1, null})); northPane.setBorder(BorderFactory.createEmptyBorder(0,5,0,8)); - if (ChartEditContext.normalMode()) { + if (ChartEditContext.supportReportData()) { this.add(northPane, BorderLayout.NORTH); } this.add(cardPane, BorderLayout.CENTER); diff --git a/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java b/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java index b5419cf39..4d5fe8a62 100644 --- a/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java +++ b/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java @@ -815,10 +815,6 @@ public class CellSelection extends Selection { return cellElements; } - public Set getCellElements() { - return cellElements; - } - @Override public void populatePropertyPane(ElementCasePane ePane) { CellElementPropertyPane.getInstance().reInit(ePane); diff --git a/designer-realize/src/main/java/com/fr/quickeditor/CellQuickEditor.java b/designer-realize/src/main/java/com/fr/quickeditor/CellQuickEditor.java index 7c3c15876..4419392f9 100644 --- a/designer-realize/src/main/java/com/fr/quickeditor/CellQuickEditor.java +++ b/designer-realize/src/main/java/com/fr/quickeditor/CellQuickEditor.java @@ -442,7 +442,7 @@ public abstract class CellQuickEditor extends QuickEditor { CellSelection cs = (CellSelection) tc.getSelection(); TemplateElementCase editingElementCase = tc.getEditingElementCase(); - Set allCellElements = cs.getCellElements(); + Set allCellElements = cs.getAllCellElements(editingElementCase); Style oldStyle = cellElement == null ? Style.DEFAULT_STYLE : cellElement.getStyle(); Style style = formatPane.update(oldStyle); for (TemplateCellElement cellElement : allCellElements) { diff --git a/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java b/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java index e9917d2c2..f93cbfc3d 100644 --- a/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java +++ b/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java @@ -241,7 +241,7 @@ public class CellDSColumnEditor extends CellQuickEditor { dataPane.update(cellElement); CellSelection selection = (CellSelection) tc.getSelection(); - Set allCellElements = selection.getCellElements(); + Set allCellElements = selection.getAllCellElements(tc.getEditingElementCase()); groupPane.update(allCellElements); } @@ -319,7 +319,7 @@ public class CellDSColumnEditor extends CellQuickEditor { @Override public void itemStateChanged(ItemEvent e) { CellSelection selection = (CellSelection) tc.getSelection(); - Set allCellElements = selection.getCellElements(); + Set allCellElements = selection.getAllCellElements(tc.getEditingElementCase()); if (e == null || e.getStateChange() == ItemEvent.DESELECTED) { //分组-高级-自定义点确定的时候传进来null的e,但是这时候应该触发保存 groupPane.update(allCellElements); @@ -351,7 +351,7 @@ public class CellDSColumnEditor extends CellQuickEditor { if (!selectedOneCell) { // 只有在批量操作的时候才需要判断是否隐藏条件面板 CellSelection selection = (CellSelection) tc.getSelection(); - boolean sameDSName = checkSameDSName(selection.getCellElements()); + boolean sameDSName = checkSameDSName(selection.getAllCellElements(tc.getEditingElementCase())); conditionPane.setVisible(sameDSName); } else { conditionPane.setVisible(true);