Browse Source

Merge pull request #12561 in DESIGN/design from final/11.0 to persist/11.0

* commit 'c4b29946375991b997e8d46ed083d9b3d6d93093': (122 commits)
  无jira任务 单元测试
  REPORT-102243 修复图表富文本编辑器自定义样式图标异常
  REPORT-101409 【版本管理三期】删除无权限的版本没有失败提示
  REPORT-101409 【版本管理三期】删除无权限的版本没有失败提示
  REPORT-101740 【版本管理三期】版本中心打开被锁定的模板,没有提示
  REPORT-101800 修改单元格内容的格式,单元格内容会清空 【问题原因】编辑一个新的单元格时,对单元格属性进行修改,之前的方式 getCellElements 拿到的并不是实际正在编辑的单元格,拿到的是一个手动创建的对象(单元格内容为null),后续对单元格进行更新时,单元格的内容被覆盖更新为null。 【改动思路】获取当前编辑的所有单元格均使用 getAllCellElements
  REPORT-101740 【版本管理三期】版本中心打开被锁定的模板,没有提示
  REPORT-87551 对模板进行重命名后,版本管理仍存在,但是每个版本内容都是一样的
  REPORT-101409 【版本管理三期】删除无权限的版本没有失败提示
  REPORT-101608 【版本管理三期】通过版本中心入口进入版本详情,未保存的模板触发还原,选择保存还原会失败 代码规范
  REPORT-101773 【版本管理三期】版本详情页面选择版本删除,删完一个操作框的按钮就点不动了
  REPORT-101608 【版本管理三期】通过版本中心入口进入版本详情,未保存的模板触发还原,选择保存还原会失败
  REPORT-101482 【版本管理二期】迁移失败/成功的提示,都有个帮助文档的跳转
  REPORT-101608 【版本管理三期】通过版本中心入口进入版本详情,未保存的模板触发还原,选择保存还原会失败
  REPORT-101026 【版本管理三期】预览版本文件,有报错
  REPORT-99740 FRM报表块,get (-1,-1)类型的ColumnRow报错
  REPORT-101605 【版本管理三期】版本中心进入的版本详情入口,删除模板所有版本后,版本中心没有刷新
  REPORT-101590 【版本管理三期】版本中心触发删除模板所有版本的动作,为什么会打开模板
  REPORT-101578 【版本管理三期】删除文件夹失败
  REPORT-101480 【版本管理二期】自动保存后手动保存,版本管理逻辑会乱
  ...
fix-lag
superman 11 months ago
parent
commit
04a32b8e58
  1. 276
      designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java
  2. 6
      designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java
  3. 1
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/MultiTDTableDataPane.java
  4. 20
      designer-base/src/main/java/com/fr/design/dialog/BasicPane.java
  5. 10
      designer-base/src/main/java/com/fr/design/editor/editor/NumberEditor.java
  6. 2
      designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java
  7. 19
      designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java
  8. 98
      designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java
  9. 8
      designer-base/src/main/java/com/fr/design/gui/autocomplete/AbstractCompletionProvider.java
  10. 19
      designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaPaneAutoCompletion.java
  11. 15
      designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java
  12. 11
      designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java
  13. 14
      designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java
  14. 7
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  15. 47
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java
  16. 7
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  17. 8
      designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/AbstractChartStylePane.java
  18. 9
      designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java
  19. 31
      designer-base/src/main/java/com/fr/design/mainframe/vcs/RecycleAction.java
  20. 25
      designer-base/src/main/java/com/fr/design/mainframe/vcs/TableEntity.java
  21. 21
      designer-base/src/main/java/com/fr/design/mainframe/vcs/TableValueOperator.java
  22. 25
      designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsConfigManager.java
  23. 37
      designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsExceptionUtils.java
  24. 288
      designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsOperatorWorker.java
  25. 60
      designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsProcessFailedWrapper.java
  26. 49
      designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsRecycleSettingHelper.java
  27. 113
      designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableEntity.java
  28. 32
      designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableOperatorListener.java
  29. 113
      designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCloseTemplateHelper.java
  30. 253
      designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java
  31. 36
      designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsNewPaneWrapper.java
  32. 407
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/AbstractSupportSelectTablePane.java
  33. 26
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java
  34. 406
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecyclePane.java
  35. 103
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecycleSettingPane.java
  36. 32
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/ToolTipTableCellRenderer.java
  37. 59
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntEditor.java
  38. 39
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntSpinner.java
  39. 156
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsBatchProcessDetailPane.java
  40. 35
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellEditor.java
  41. 29
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellRender.java
  42. 268
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java
  43. 520
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovePanel.java
  44. 54
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovingExitOption.java
  45. 406
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java
  46. 40
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsOperatorPane.java
  47. 81
      designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsProgressDialog.java
  48. 13
      designer-base/src/main/java/com/fr/design/mainframe/widget/editors/DataBindingEditor.java
  49. 20
      designer-base/src/main/java/com/fr/design/mainframe/widget/editors/WidgetValueEditor.java
  50. 4
      designer-base/src/main/java/com/fr/design/style/color/ColorSelectDialog.java
  51. 4
      designer-base/src/main/resources/com/fr/design/images/buttonicon/new_other_normal.svg
  52. 5
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_center_manager_normal.svg
  53. 5
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_center_open_normal.svg
  54. 7
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_operator_delete_normal.svg
  55. 5
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_operator_preview_normal.svg
  56. 5
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_operator_restore_normal.svg
  57. 7
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_delete_disabled.svg
  58. 7
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_delete_normal.svg
  59. 8
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_normal.svg
  60. 5
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_restore_disabled.svg
  61. 5
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_restore_normal.svg
  62. 3
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_search_normal.svg
  63. 4
      designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_sort_normal.svg
  64. 5
      designer-base/src/main/resources/com/fr/design/vcs/move_failed.svg
  65. 5
      designer-base/src/main/resources/com/fr/design/vcs/move_success.svg
  66. 3
      designer-base/src/main/resources/com/fr/design/vcs/vcs_move_icon.svg
  67. 29
      designer-base/src/test/java/com/fr/base/ClassHelperTest.java
  68. 9
      designer-base/src/test/java/com/fr/design/jxbrowser/MimeTypeTest.java
  69. 2
      designer-base/src/test/java/com/fr/nx/app/designer/toolbar/TransformResultInfoTest.java
  70. 8
      designer-form/src/main/java/com/fr/design/actions/NewFormAction.java
  71. 27
      designer-form/src/main/java/com/fr/design/designer/creator/XEditorHolder.java
  72. 23
      designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
  73. 2
      designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
  74. 2
      designer-form/src/main/java/com/fr/design/widget/ui/designer/component/FormWidgetValuePane.java
  75. 40
      designer-form/src/test/java/com/fr/design/mainframe/template/info/JFormProcessInfoTest.java
  76. 14
      designer-realize/src/main/java/com/fr/design/report/ImageExportPane.java
  77. 22
      designer-realize/src/main/java/com/fr/design/sort/common/SortColumnRowPane.java
  78. 4
      designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java
  79. 2
      designer-realize/src/main/java/com/fr/quickeditor/CellQuickEditor.java
  80. 6
      designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java
  81. 8
      designer-realize/src/main/java/com/fr/start/MainDesigner.java
  82. BIN
      designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs1.png
  83. BIN
      designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs2.png
  84. BIN
      designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs3.png
  85. BIN
      designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs4.png
  86. 160
      designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/template_resource/local_templates.json
  87. 6
      designer-realize/src/test/java/com/fr/nx/app/designer/CptxAppTest.java

276
designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java

@ -36,6 +36,8 @@ import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.mainframe.vcs.VcsConfigManager;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.design.mainframe.vcs.ui.UIPositiveIntEditor;
import com.fr.design.mainframe.vcs.ui.VcsMovePanel;
import com.fr.design.os.impl.SupportOSImpl;
import com.fr.design.unit.UnitConvertUtil;
import com.fr.design.utils.gui.GUICoreUtils;
@ -49,14 +51,22 @@ import com.fr.io.attr.ImageExportAttr;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory;
import com.fr.report.ReportConfigManager;
import com.fr.scheduler.tool.FineScheduler;
import com.fr.stable.Constants;
import com.fr.stable.os.OperatingSystem;
import com.fr.third.apache.logging.log4j.Level;
import com.fr.third.guava.collect.BiMap;
import com.fr.third.guava.collect.HashBiMap;
import com.fr.transaction.Configurations;
import com.fr.transaction.Worker;
import com.fr.transaction.WorkerAdaptor;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.vcs.VcsConfig;
import com.fr.workspace.server.vcs.VcsOperator;
import com.fr.workspace.server.vcs.git.config.GcConfig;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanOperator;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanSchedule;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanService;
import org.jetbrains.annotations.NotNull;
import javax.swing.BorderFactory;
@ -77,14 +87,7 @@ import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Window;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
@ -95,6 +98,7 @@ import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@ -122,6 +126,7 @@ public class PreferencePane extends BasicPane {
private static final int PREFERENCE_LABEL_MAX_WIDTH = 460;
private static final int OFFSET_HEIGHT = 60;
private static final int VCS_FILL_TOTAL = 5;
private static final String TYPE = "pressed";
private static final String DISPLAY_TYPE = "+";
private static final String BACK_SLASH = "BACK_SLASH";
@ -149,6 +154,34 @@ public class PreferencePane extends BasicPane {
private static final Level[] LOG = {Level.FATAL, Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG};
private static final int ONE_DAY_INT = 1;
private static final int ONE_WEEK_INT = 7;
private static final int ONE_MONTH_INT = 30;
private static final int THREE_MONTH_INT = 90;
private static final int SIX_MONTH_INT = 180;
private static final int ONE_DAY_INDEX = 0;
private static final int ONE_WEEK_INDEX = 1;
private static final int ONE_MONTH_INDEX = 2;
private static final int THREE_MONTH_INDEX = 3;
private static final int SIX_MONTH_INDEX = 4;
private static final String ONE_DAY = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_ONE_DAY");
private static final String ONE_WEEK = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_ONE_WEEK");
private static final String ONE_MONTH = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_ONE_MONTH");
private static final String THREE_MONTH = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_THREE_MONTH");
private static final String SIX_MONTH = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_SIX_MONTH");
private static final String[] INTERVAL = {
ONE_DAY,
ONE_WEEK,
ONE_MONTH,
THREE_MONTH,
SIX_MONTH
};
private static final int DEFAULT_INDEX = 3;
private BasicDialog basicDialog;
private boolean languageChanged; // 是否修改了设计器语言设置
//设置是否支持undo
private UICheckBox supportUndoCheckBox;
@ -186,10 +219,24 @@ public class PreferencePane extends BasicPane {
private UICheckBox cloudAnalyticsDelayCheckBox;
private UICheckBox vcsEnableCheckBox;
private UICheckBox useVcsAutoSaveScheduleCheckBox;
private UICheckBox useVcsAutoCleanScheduleCheckBox;
private UIComboBox autoCleanIntervalComboBox;
private UIComboBox autoCleanRetainIntervalComboBox;
private UIPositiveIntEditor autoSaveIntervalEditor;
private UICheckBox saveCommitCheckBox;
private UICheckBox useIntervalCheckBox;
private VcsMovePanel movePanel;
private JPanel saveIntervalPane;
private JPanel autoCleanPane;
private JPanel gcControlPane;
private UICheckBox startupPageEnabledCheckBox;
private IntegerEditor saveIntervalEditor;
private UIPositiveIntEditor saveIntervalEditor;
private UICheckBox gcEnableCheckBox;
private UIButton gcButton;
private UILabel remindVcsLabel;
@ -209,7 +256,15 @@ public class PreferencePane extends BasicPane {
private UIRadioButton previewRenderQuality;
private static final int DPI_SCALE_S = 1;
private static final int DPI_SCALE_M = 2;
private static final BiMap<Integer, Integer> INDEX_DAY_MAP = HashBiMap.create(new HashMap<Integer, Integer>() {
{
put(ONE_DAY_INDEX, ONE_DAY_INT);
put(ONE_WEEK_INDEX, ONE_WEEK_INT);
put(ONE_MONTH_INDEX, ONE_MONTH_INT);
put(SIX_MONTH_INDEX, SIX_MONTH_INT);
put(THREE_MONTH_INDEX, THREE_MONTH_INT);
}
});
public PreferencePane() {
this.initComponents();
}
@ -227,13 +282,26 @@ public class PreferencePane extends BasicPane {
JPanel advancePane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
UIScrollPane adviceScrollPane = patchScroll(advancePane);
jtabPane.addTab(i18nText("Fine-Design_Basic_Advanced"), adviceScrollPane);
//初始化vcs总面板
JPanel vcsParentPane = new JPanel();
CardLayout cardLayout = new CardLayout();
vcsParentPane.setLayout(cardLayout);
//vcs配置面板
JPanel vcsPane = new JPanel(new BorderLayout());
//添加滚动条
UIScrollPane vcsScrollPane = patchScroll(vcsPane);
//配置面板作为vcs总面板的一张卡片
vcsParentPane.add(vcsScrollPane, VcsMovePanel.SETTING);
jtabPane.addTab(i18nText("Fine-Design_Vcs_Title"), vcsParentPane);
contentPane.add(jtabPane, BorderLayout.NORTH);
createFunctionPane(generalPane);
createEditPane(generalPane);
createColorSettingPane(generalPane);
createVcsSettingPane(generalPane);
// vcsPane
createVcsSettingPane(vcsPane, vcsParentPane, cardLayout);
// ConfPane
JPanel confLocationPane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane();
@ -345,21 +413,33 @@ public class PreferencePane extends BasicPane {
return generalPanelWithScroll;
}
private void createVcsSettingPane(JPanel generalPane) {
JPanel vcsPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Title"));
generalPane.add(vcsPane);
private void createVcsSettingPane(JPanel generalPane,JPanel parentPane, CardLayout cardLayout) {
//迁移面板
movePanel = createMovePane(cardLayout, parentPane);
generalPane.add(movePanel, BorderLayout.NORTH);
JPanel savePane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Save_Setting"));
JPanel vcsPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Clean_Setting"));
JPanel containPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
containPane.add(savePane);
containPane.add(vcsPane);
//填充一下面板
fillPane(containPane, VCS_FILL_TOTAL);
generalPane.add(containPane, BorderLayout.CENTER);
remindVcsLabel = new UILabel(i18nText("Fine-Design_Vcs_Remind"));
remindVcsLabel.setVisible(!VcsHelper.getInstance().needInit());
vcsEnableCheckBox = new UICheckBox(i18nText("Fine-Design_Vcs_SaveAuto"));
saveIntervalPane = createSaveIntervalPane();
saveCommitCheckBox = new UICheckBox(i18nText("Fine-Design_Vcs_No_Delete"));
saveIntervalEditor = new IntegerEditor(60);
saveIntervalEditor = new UIPositiveIntEditor(60);
useIntervalCheckBox = new UICheckBox();
savePane.add(vcsEnableCheckBox);
savePane.add(saveIntervalPane);
//gc面板
JPanel gcControlPane = createGcControlPane();
gcControlPane = createGcControlPane();
JPanel enableVcsPanel = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
enableVcsPanel.add(vcsEnableCheckBox);
enableVcsPanel.add(remindVcsLabel);
JPanel intervalPanel = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
final UILabel everyLabel = new UILabel(i18nText("Fine-Design_Vcs_Every"));
@ -368,6 +448,8 @@ public class PreferencePane extends BasicPane {
intervalPanel.add(everyLabel);
intervalPanel.add(saveIntervalEditor);
intervalPanel.add(delayLabel);
autoCleanPane = createAutoCleanPane();
checkAutoScheduleStartAndUpdateStatus();
vcsEnableCheckBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
@ -389,10 +471,104 @@ public class PreferencePane extends BasicPane {
});
vcsPane.add(enableVcsPanel);
vcsPane.add(intervalPanel);
vcsPane.add(saveCommitCheckBox);
vcsPane.add(gcControlPane);
if (VcsHelper.getInstance().isLegacyMode()) {
vcsPane.add(saveCommitCheckBox);
}
vcsPane.add(autoCleanPane);
boolean support = VcsHelper.getInstance().checkV2FunctionSupport();
saveIntervalPane.setVisible(support);
autoCleanPane.setVisible(support);
if (VcsHelper.getInstance().isLegacyMode()) {
// 老版本时才显示gc选项
vcsPane.add(gcControlPane);
}
}
private void fillPane(JPanel containPane, int total) {
for (int i = 0; i < total; i++) {
containPane.add(new JPanel());
}
}
private VcsMovePanel createMovePane(CardLayout cardLayout, JPanel parentPane) {
return new VcsMovePanel(cardLayout, parentPane, new VcsMovePanel.MoveCallBack(){
@Override
public void doCallBack(boolean useV2) {
saveIntervalPane.setVisible(useV2);
autoCleanPane.setVisible(useV2);
gcControlPane.setVisible(!useV2);
saveCommitCheckBox.setVisible(!useV2);
useVcsAutoCleanScheduleCheckBox.setSelected(useV2);
useVcsAutoSaveScheduleCheckBox.setSelected(useV2);
checkAutoScheduleStartAndUpdateStatus();
useVcsAutoSaveScheduleCheckBox.setEnabled(useV2);
}
}, basicDialog);
};
private JPanel createAutoCleanPane() {
JPanel autoCleanPane = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
useVcsAutoCleanScheduleCheckBox = new UICheckBox();
autoCleanIntervalComboBox = new UIComboBox(INTERVAL);
autoCleanIntervalComboBox.setSelectedIndex(DEFAULT_INDEX);
autoCleanRetainIntervalComboBox = new UIComboBox(INTERVAL);
autoCleanRetainIntervalComboBox.setSelectedIndex(DEFAULT_INDEX);
autoCleanPane.add(useVcsAutoCleanScheduleCheckBox);
autoCleanPane.add(new UILabel(i18nText("Fine-Design_Vcs_Auto_Clean_Every")));
autoCleanPane.add(autoCleanIntervalComboBox);
autoCleanPane.add(new UILabel(i18nText("Fine-Design_Vcs_Auto_Clean_Content")));
autoCleanPane.add(autoCleanRetainIntervalComboBox);
autoCleanPane.add(new UILabel(i18nText("Fine-Design_Vcs_Auto_Clean_Last")));
autoCleanPane.setVisible(false);
return autoCleanPane;
}
private void checkAutoScheduleStartAndUpdateStatus() {
if (!VcsHelper.getInstance().isLegacyMode()) {
new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
return WorkContext.getCurrent().get(VcsAutoCleanOperator.class).isSupport();
}
@Override
protected void done() {
try {
boolean useAutoClean = get();
updateAutoCleanEnabled(useAutoClean);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}.execute();
} else {
updateAutoCleanEnabled(false);
}
}
private void updateAutoCleanEnabled(boolean b) {
useVcsAutoCleanScheduleCheckBox.setEnabled(b);
autoCleanIntervalComboBox.setEnabled(b);
autoCleanRetainIntervalComboBox.setEnabled(b);
if (autoCleanPane != null) {
autoCleanPane.setToolTipText(b ? null : Toolkit.i18nText("Fine-Design_Vcs_Server_Start_Hover"));
}
}
private JPanel createSaveIntervalPane() {
JPanel saveIntervalPane = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
useVcsAutoSaveScheduleCheckBox = new UICheckBox();
autoSaveIntervalEditor = new UIPositiveIntEditor(60);
saveIntervalPane.add(useVcsAutoSaveScheduleCheckBox);
saveIntervalPane.add(new UILabel(i18nText("Fine-Design_Vcs_Every")));
saveIntervalPane.add(autoSaveIntervalEditor);
saveIntervalPane.add(new UILabel(i18nText("Fine-Design_Vcs_Save_Delay")));
useVcsAutoSaveScheduleCheckBox.setEnabled(!VcsHelper.getInstance().isLegacyMode());
saveIntervalPane.setVisible(false);
return saveIntervalPane;
}
/**
* 模创建板版本gc 配置操作面板
*
@ -773,7 +949,8 @@ public class PreferencePane extends BasicPane {
defaultStringToFormulaBox.setSelected(false);
}
VcsConfigManager vcsConfigManager = designerEnvManager.getVcsConfigManager();
if (WorkContext.getCurrent().isCluster()) {
//如果是集群并且是老版本则不可用
if (VcsHelper.getInstance().isLegacyMode() && WorkContext.getCurrent().isCluster()) {
vcsEnableCheckBox.setEnabled(false);
gcEnableCheckBox.setEnabled(false);
}
@ -796,6 +973,12 @@ public class PreferencePane extends BasicPane {
gcEnableCheckBox.setSelected(GcConfig.getInstance().isGcEnable());
gcButton.setEnabled(gcEnableCheckBox.isSelected());
useVcsAutoSaveScheduleCheckBox.setSelected(vcsConfigManager.isUseAutoSave());
useVcsAutoCleanScheduleCheckBox.setSelected(VcsConfig.getInstance().isUseV2AutoClean());
autoSaveIntervalEditor.setValue(vcsConfigManager.getAutoSaveInterval());
autoCleanIntervalComboBox.setSelectedIndex(getIndex(VcsConfig.getInstance().getV2CleanInterval()));
autoCleanRetainIntervalComboBox.setSelectedIndex(getIndex(VcsConfig.getInstance().getV2RetainInterval()));
gridLineColorTBButton.setColor(designerEnvManager.getGridLineColor());
paginationLineColorTBButton.setColor(designerEnvManager.getPaginationLineColor());
@ -883,6 +1066,14 @@ public class PreferencePane extends BasicPane {
}
}
private int getDay(int dateIndex) {
return INDEX_DAY_MAP.getOrDefault(dateIndex, THREE_MONTH_INT);
}
private int getIndex(int day) {
return INDEX_DAY_MAP.inverse().getOrDefault(day, THREE_MONTH_INDEX);
}
/**
* The method of update.
*/
@ -931,6 +1122,17 @@ public class PreferencePane extends BasicPane {
vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected());
vcsConfigManager.setSaveCommit(this.saveCommitCheckBox.isSelected());
vcsConfigManager.setUseInterval(this.useIntervalCheckBox.isSelected());
vcsConfigManager.setUseAutoSave(this.useVcsAutoSaveScheduleCheckBox.isSelected());
vcsConfigManager.setAutoSaveInterval(this.autoSaveIntervalEditor.getValue());
Configurations.update(new WorkerAdaptor(VcsConfig.class) {
@Override
public void run() {
VcsConfig.getInstance().setUseV2AutoClean(useVcsAutoCleanScheduleCheckBox.isSelected());
VcsConfig.getInstance().setV2CleanInterval(getDay(autoCleanIntervalComboBox.getSelectedIndex()));
VcsConfig.getInstance().setV2RetainInterval(getDay(autoCleanRetainIntervalComboBox.getSelectedIndex()));
}
});
dealWithSchedule();
designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected());
Configurations.update(new Worker() {
@Override
@ -1005,6 +1207,36 @@ public class PreferencePane extends BasicPane {
}
private void dealWithSchedule() {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
boolean v2FunctionSupport = VcsHelper.getInstance().checkV2FunctionSupport();
if (v2FunctionSupport) {
//如果支持V2
if (useVcsAutoSaveScheduleCheckBox.isSelected()) {
FineLoggerFactory.getLogger().info("[VcsV2] start auto save!");
VcsHelper.getInstance().startAutoSave(autoSaveIntervalEditor.getValue());
} else {
VcsHelper.getInstance().stopAutoSave();
}
if (useVcsAutoCleanScheduleCheckBox.isEnabled()) {
if (useVcsAutoCleanScheduleCheckBox.isSelected()) {
FineLoggerFactory.getLogger().info("[VcsV2] start auto clean!");
WorkContext.getCurrent().get(VcsAutoCleanOperator.class).addOrUpdateVcsAutoCleanJob(
VcsAutoCleanService.VCS_AUTO_CLEAN_JOB_NAME,
getDay(autoCleanIntervalComboBox.getSelectedIndex()),
VcsAutoCleanSchedule.class);
} else {
WorkContext.getCurrent().get(VcsAutoCleanOperator.class).stopVcsAutoCleanJob(VcsAutoCleanService.VCS_AUTO_CLEAN_JOB_NAME);
}
}
}
return null;
}
}.execute();
}
// 如果语言设置改变了,则显示重启对话框
public void showRestartDialog() {
if (!languageChanged) {
@ -1033,12 +1265,14 @@ public class PreferencePane extends BasicPane {
@Override
public BasicDialog showWindow(Window window) {
return showWindow(window, new DialogActionAdapter() {
basicDialog = showWindow(window, new DialogActionAdapter() {
@Override
public void doOk() {
languageChanged = !ComparatorUtils.equals(languageComboBox.getSelectedItem(), DesignerEnvManager.getEnvManager(false).getLanguage());
}
});
movePanel.setParentDialog(basicDialog);
return basicDialog;
}
@Override

6
designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java

@ -7,6 +7,7 @@ import com.fr.design.env.DesignerWorkspaceInfo;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.vcs.ui.VcsMovingExitOption;
import com.fr.design.menu.KeySetUtils;
import com.fr.design.menu.MenuDef;
import com.fr.design.menu.SeparatorDef;
@ -60,6 +61,11 @@ public class SwitchExistEnv extends MenuDef {
* @param e 事件
*/
public void actionPerformed(ActionEvent e) {
//检查是否正在迁移,如果正在迁移就弹出弹窗让用户选择
if (!VcsMovingExitOption.ShowDialogAndConfirmSwitch()) {
//如果用户选择取消切换环境则返回,不然说明用户就是想切换,则往下走
return;
}
final String envName = getName();
DesignerEnvManager envManager = DesignerEnvManager.getEnvManager();
DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName);

1
designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/MultiTDTableDataPane.java

@ -294,6 +294,7 @@ public class MultiTDTableDataPane extends AbstractTableDataPane<MultiTDTableData
tmp = tmp + "...";
tabledataName = new UILabel(tmp);
}
tabledataName.setToolTipText(name);
UILabel iconLabel = new UILabel(icon);
chekbox.addActionListener(tableDataCheckboxListener);
iconLabel.addMouseListener(chooseTableDataListener);

20
designer-base/src/main/java/com/fr/design/dialog/BasicPane.java

@ -75,6 +75,26 @@ public abstract class BasicPane extends JPanel {
return dg;
}
/**
* 显示小窗口并允许自定义需不需要按钮
*
* @param window 窗口
* @param isNeedButtonsPane 是否需要确定删除按钮
* @return 对话框
*/
public BasicDialog showSmallWindow(Window window, boolean isNeedButtonsPane) {
BasicDialog dg;
if (window instanceof Frame) {
dg = new DIALOG((Frame) window, isNeedButtonsPane);
} else {
dg = new DIALOG((Dialog) window, isNeedButtonsPane);
}
dg.setBasicDialogSize(BasicDialog.SMALL);
GUICoreUtils.centerWindow(dg);
dg.setResizable(false);
return dg;
}
/**
* 图表类型选择时 弹出的按钮大小, 不适合用最大最小, 因为图表大小 默认是规定好的, 那么界面大小也是必须配合.

10
designer-base/src/main/java/com/fr/design/editor/editor/NumberEditor.java

@ -38,7 +38,7 @@ public abstract class NumberEditor<T extends Number> extends Editor<T> {
*/
public NumberEditor(T value, String name) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
numberField = new UINumberField();
numberField = createNumberField();
this.add(numberField, BorderLayout.CENTER);
this.numberField.addKeyListener(textKeyListener);
this.numberField.setHorizontalAlignment(UITextField.RIGHT);
@ -46,6 +46,14 @@ public abstract class NumberEditor<T extends Number> extends Editor<T> {
this.setName(name);
}
/**
* 创建NumberField对象
*
*/
protected UINumberField createNumberField() {
return new UINumberField();
}
/**
* 给numberField加键盘事件
*

2
designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java

@ -419,7 +419,7 @@ public class MultiTemplateTabPane extends JComponent {
public void closeOtherByOperatorType(String operatorType){
JTemplate<?, ?> currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(false);
if (saveSomeTempaltePane.showSavePane()) {
if (saveSomeTempaltePane.showSavePane(null, false, true)) {
List<JTemplate<?, ?>> openedTemplate = HistoryTemplateListCache.getInstance().getHistoryList();
JTemplate<?, ?>[] templates = new JTemplate<?, ?>[openedTemplate.size()];

19
designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java

@ -183,7 +183,19 @@ public class SaveSomeTemplatePane extends BasicPane {
* @return
*/
public boolean showSavePane(@Nullable MultiTemplateTabPane.CloseCondition option, boolean judgeJTemplateMustSave) {
initAndPopulate(option, judgeJTemplateMustSave);
return showSavePane(option, judgeJTemplateMustSave, false);
}
/**
* 显示保存模板提醒面板
*
* @param option 具体关闭操作
* @param judgeJTemplateMustSave 模板是否必须保存
* @param judgeSameTabType 是否只包含当前编辑的模板类型
* @return
*/
public boolean showSavePane(@Nullable MultiTemplateTabPane.CloseCondition option, boolean judgeJTemplateMustSave, boolean judgeSameTabType) {
initAndPopulate(option, judgeJTemplateMustSave, judgeSameTabType);
//如果有未保存的文件 ,则跳出保存对话框,选择要存储的项目
if (!unSavedTemplate.isEmpty()) {
dialog.setVisible(true);
@ -197,13 +209,16 @@ public class SaveSomeTemplatePane extends BasicPane {
return HistoryTemplateListPane.getInstance().getHistoryList();
}
private void initAndPopulate(@Nullable MultiTemplateTabPane.CloseCondition option, boolean judgeJTemplateMustSave) {
private void initAndPopulate(@Nullable MultiTemplateTabPane.CloseCondition option, boolean judgeJTemplateMustSave, boolean judgeSameTabType) {
java.util.List<JTemplate<?, ?>> opendedTemplate = getOpenedTemplatesToProcess();
JTemplate<?, ?> currentTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate();
int currentIndex = opendedTemplate.indexOf(currentTemplate);
for (int i = 0; i < opendedTemplate.size(); i++) {
//满足关闭条件的才继续判断文件是否发生了改动
boolean needClose = option == null || option.shouldClose(opendedTemplate.get(i), currentIndex, i);
if (judgeSameTabType) {
needClose &= ComparatorUtils.equals(opendedTemplate.get(i).getTemplateTabOperatorType(), currentTemplate.getTemplateTabOperatorType());
}
if (needClose && isneedToAdd(opendedTemplate.get(i), currentTemplate)) {
unSavedTemplate.add(opendedTemplate.get(i));
}

98
designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java

@ -18,6 +18,7 @@ import com.fr.design.lock.LockInfoDialog;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateSearchRemindPane;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.file.FILE;
import com.fr.file.FileNodeFILE;
import com.fr.file.filetree.FileNode;
@ -38,6 +39,7 @@ import java.util.UUID;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.ToolTipManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
@ -59,8 +61,10 @@ import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import com.fr.workspace.server.vcs.VcsOperator;
import org.jetbrains.annotations.Nullable;
@ -235,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());
@ -253,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()) {
@ -346,13 +357,7 @@ public class TemplateTreePane extends JPanel implements FileOperations {
YES_NO_OPTION)
== JOptionPane.YES_OPTION) {
// 删除所有选中的即可
if (!deleteNodes(Arrays.asList(treeNodes))) {
FineJOptionPane.showConfirmDialog(null,
Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE);
}
deleteNodes(Arrays.asList(treeNodes));
}
} else {
@ -377,17 +382,9 @@ public class TemplateTreePane extends JPanel implements FileOperations {
YES_NO_OPTION)
== JOptionPane.YES_OPTION) {
// 删除其他
if (!deleteNodes(deletableNodes)) {
FineJOptionPane.showConfirmDialog(null,
Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE);
}
deleteNodes(deletableNodes);
}
}
Set<FileNode> deletedFileNode = deletableNodes.stream().map(treeNode -> (FileNode) treeNode.getUserObject()).collect(Collectors.toSet());
refreshAfterDelete(deletedFileNode);
}
private void refreshAfterDelete(Set<FileNode> deletedPaths) {
@ -407,23 +404,54 @@ public class TemplateTreePane extends JPanel implements FileOperations {
}
}
private boolean deleteNodes(Collection<ExpandMutableTreeNode> nodes) {
boolean success = true;
for (ExpandMutableTreeNode treeNode : nodes) {
Object node = treeNode.getUserObject();
if (node instanceof FileNode) {
FileNodeFILE nodeFILE = new FileNodeFILE((FileNode) node);
if (nodeFILE.exists()) {
if (TemplateResourceManager.getResource().delete(nodeFILE)) {
HistoryTemplateListCache.getInstance().deleteFile(nodeFILE);
} else {
success = false;
private void deleteNodes(Collection<ExpandMutableTreeNode> nodes) {
new SwingWorker<Boolean,Void>(){
@Override
protected Boolean doInBackground() throws Exception {
boolean success = true;
for (ExpandMutableTreeNode treeNode : nodes) {
Object node = treeNode.getUserObject();
if (node instanceof FileNode) {
FileNodeFILE nodeFILE = new FileNodeFILE((FileNode) node);
if (nodeFILE.exists()) {
if (!VcsHelper.getInstance().isLegacyMode()) {
try {
WorkContext.getCurrent().get(VcsOperator.class).recycleVersion(VcsHelper.getInstance().getCurrentUsername(), nodeFILE.getPath());
} catch (Exception e) {
FineLoggerFactory.getLogger().error("[VcsV2] recycle {} failed", nodeFILE.getName());
}
}
if (TemplateResourceManager.getResource().delete(nodeFILE)) {
HistoryTemplateListCache.getInstance().deleteFile(nodeFILE);
} else {
success = false;
}
}
}
}
return success;
}
}
return success;
@Override
protected void done() {
try {
if (!get()) {
showErrorDialog();
}
Set<FileNode> deletedFileNode = nodes.stream().map(treeNode -> (FileNode) treeNode.getUserObject()).collect(Collectors.toSet());
refreshAfterDelete(deletedFileNode);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}.execute();
}
private void showErrorDialog() {
FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE);
}

8
designer-base/src/main/java/com/fr/design/gui/autocomplete/AbstractCompletionProvider.java

@ -8,12 +8,14 @@
*/
package com.fr.design.gui.autocomplete;
import com.fr.stable.StringUtils;
import javax.swing.text.JTextComponent;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.text.JTextComponent;
/**
@ -186,7 +188,9 @@ public abstract class AbstractCompletionProvider
while (index<completions.size()) {
Completion c = completions.get(index);
if (Util.startsWithIgnoreCase(c.getInputText(), text)) {
String inputText = c.getInputText();
//当输入文本和补全项相等时,不再添加到补全项到窗口中
if (Util.startsWithIgnoreCase(inputText, text) && !StringUtils.equals(inputText, text)) {
retVal.add(c);
index++;
}

19
designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaPaneAutoCompletion.java

@ -1,12 +1,10 @@
package com.fr.design.gui.autocomplete;
import com.fr.design.formula.FormulaPane;
import com.fr.stable.StringUtils;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.text.Caret;
import javax.swing.text.JTextComponent;
import java.awt.Window;
/**
* @author Hoky
@ -70,9 +68,18 @@ public class FormulaPaneAutoCompletion extends AutoCompletionWithExtraRefresh {
caret.setDot(start);
caret.moveDot(dot);
if (FormulaPane.containsParam(replacement)) {
textComp.replaceSelection(FormulaPane.getParamPrefix(replacement) + replacement);
int caretPosition = textComp.getCaretPosition();
textComp.setCaretPosition(caretPosition);
String selectedText = textComp.getSelectedText();
//找到选择文本(光标输入位置dot)进行补全
String text = textComp.getText().substring(0, dot);
int index = text.lastIndexOf(selectedText);
//获取replacement的前缀,replacement是不带前缀的,例如变量$$page_number,获取到的replacement是page_number
String paramPrefix = FormulaPane.getParamPrefix(replacement);
//当选择文本之前有和param前缀相同大小的字符串时,截取对比一下,如果内容相同,则前缀已经存在,不用再拼接了
String prefix = (index >= paramPrefix.length()) ? text.substring(index - paramPrefix.length(), index) : StringUtils.EMPTY;
if (!FormulaPane.getParamPrefix(replacement).equals(prefix)) {
replacement = paramPrefix + replacement;
}
textComp.replaceSelection(replacement);
} else {
textComp.replaceSelection(replacement + "()");
int caretPosition = textComp.getCaretPosition();

15
designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java

@ -4,6 +4,7 @@ import com.fr.base.BaseUtils;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.mainframe.DesignerContext;
import com.fr.log.FineLoggerFactory;
import org.jetbrains.annotations.Nullable;
import javax.swing.JOptionPane;
import javax.swing.JTable;
@ -64,6 +65,20 @@ public abstract class UITableModelAdapter<T> extends AbstractTableModel implemen
return null;
}
/**
* 获取映射后的值
*
* @param row
* @return
*/
@Nullable
public T getConvertRowSelectedValue(int row) {
if (table.getSelectedRow() >= 0) {
return list.get(table.convertRowIndexToModel(row));
}
return null;
}
public void setColumnClass(Class<?>[] classes) {
this.classes = classes;
}

11
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> 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);
}
}

14
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<UrlRequestJob> 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) {

7
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java

@ -34,6 +34,7 @@ import com.fr.design.mainframe.share.mini.MiniShopDisposingChecker;
import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.design.mainframe.vcs.ui.VcsMovingExitOption;
import com.fr.design.menu.ShortCut;
import com.fr.design.os.impl.MacOsAddListenerAction;
import com.fr.design.os.impl.SupportOSImpl;
@ -161,6 +162,12 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
@Override
public void windowClosing(WindowEvent e) {
//检查是否正在迁移,如果正在迁移就弹出弹窗让用户选择
if (!VcsMovingExitOption.ShowDialogAndConfirmExit()) {
//如果用户选择取消退出则返回,不然说明用户就是想退出,则往下走
return;
}
// 检查mini商城是否存在未结束的后台任务
if (!MiniShopDisposingChecker.check()) {
return;

47
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java

@ -16,6 +16,7 @@ import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.tabledata.ResponseDataSourceChange;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.FileOperations;
import com.fr.design.file.FileToolbarStateChangeListener;
@ -34,6 +35,8 @@ import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateTreeSearchToolbarPane;
import com.fr.design.mainframe.vcs.RecycleAction;
import com.fr.design.mainframe.vcs.common.VcsCloseTemplateHelper;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.design.mainframe.vcs.ui.FileVersionsPanel;
import com.fr.design.menu.KeySetUtils;
@ -150,6 +153,8 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
private VcsAction vcsAction = new VcsAction();
private RecycleAction recycleAction = new RecycleAction();
//搜索
private SwitchAction switchAction = new SwitchAction();
private TemplateTreeSearchToolbarPane searchToolbarPane;
@ -325,13 +330,17 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
if (VcsHelper.getInstance().needInit()) {
vcsAction = new VcsAction();
if (!WorkContext.getCurrent().isCluster()) {
if (!isLegacyOnCluster()) {
vcsAction.setName(Toolkit.i18nText("Fine-Design_Vcs_Title"));
} else {
vcsAction.setName(Toolkit.i18nText("Fine-Design_Vcs_NotSupportRemote"));
}
toolbarDef.addShortCut(vcsAction);
//11.0.19及其之后加入回收站逻辑
if (VcsHelper.getInstance().checkV2FunctionSupport()) {
recycleAction = new RecycleAction();
toolbarDef.addShortCut(recycleAction);
}
}
}
@ -382,12 +391,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
}
private boolean isCurrentEditing(String path) {
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
String editing = jt.getEditingFILE().getPath();
return ComparatorUtils.equals(editing, path);
}
/**
* 按钮状态改变
*/
@ -492,24 +495,26 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
public void actionPerformed(ActionEvent e) {
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath();
path = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, path);
boolean isCurrentEditing = isCurrentEditing(path);
// 如果模板已经打开了,关掉,避免出现2个同名tab(1个是模板,1个是版本)
closeOpenedTemplate(path, isCurrentEditing);
FileVersionsPanel fileVersionTablePanel = FileVersionsPanel.getInstance();
fileVersionTablePanel.showFileVersionsPane();
stateChange();
boolean currentEditing = VcsCloseTemplateHelper.isCurrentEditing(path);
if (VcsHelper.getInstance().isLegacyMode()) {
// 如果模板已经打开了,关掉,避免出现2个同名tab(1个是模板,1个是版本)
closeOpenedTemplate(path, currentEditing);
FileVersionsPanel fileVersionTablePanel = FileVersionsPanel.getInstance();
fileVersionTablePanel.showFileVersionsPane();
stateChange();
} else {
VcsCloseTemplateHelper.checkTemplateSavedAndShowVcsNewPane(path, currentEditing);
}
}
/**
* 版本管理可用状态的监控
*/
private void fireVcsActionChange(boolean enable) {
if (!DesignerEnvManager.getEnvManager().getVcsConfigManager().isVcsEnable()
|| VcsHelper.getInstance().isUnSelectedTemplate()
|| WorkContext.getCurrent().isCluster()) {
|| isLegacyOnCluster()) {
setEnabled(false);
return;
}
@ -556,7 +561,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
}
}
/**
@ -810,6 +814,11 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
}
private boolean isLegacyOnCluster() {
// 老模式且为集群,用于代替之前的只判断集群逻辑
return WorkContext.getCurrent().isCluster() && VcsHelper.getInstance().isLegacyMode();
}
private String doCheck (String userInput, String suffix) {
String errorMsg = StringUtils.EMPTY;
if (selectedOperation.duplicated(userInput, suffix, true)) {

7
designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java

@ -114,6 +114,8 @@ import java.awt.Dimension;
import java.awt.FontMetrics;
import java.io.ByteArrayOutputStream;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
@ -1146,7 +1148,10 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
* @param l 模板Listener
*/
public void addJTemplateActionListener(JTemplateActionListener l) {
this.listenerList.add(JTemplateActionListener.class, l);
List<Object> list = Arrays.asList(this.listenerList.getListeners(JTemplateActionListener.class));
if (!list.contains(l)) {
this.listenerList.add(JTemplateActionListener.class, l);
}
}
/**

8
designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/AbstractChartStylePane.java

@ -29,11 +29,11 @@ public abstract class AbstractChartStylePane extends BasicPane {
protected void initPane() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
double e1 = 75;
double e = 155;
double labelWidth = 90;
double totalWidth = 155;
double p = TableLayout.PREFERRED;
double[] columnSize = {e1, e};
JPanel gapTableLayoutPane = TableLayoutHelper.createGapTableLayoutPane(getComponent(), getRows(p), columnSize, 20, LayoutConstants.VGAP_LARGE);
double[] columnSize = {labelWidth, totalWidth};
JPanel gapTableLayoutPane = TableLayoutHelper.createGapTableLayoutPane(getComponent(), getRows(p), columnSize, 5, LayoutConstants.VGAP_LARGE);
gapTableLayoutPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
UIScrollPane rightTopPane = new UIScrollPane(gapTableLayoutPane);
rightTopPane.setBorder(BorderFactory.createEmptyBorder());

9
designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java

@ -2,7 +2,6 @@ package com.fr.design.mainframe.theme.edit.chart;
import com.fr.base.BaseUtils;
import com.fr.base.FRContext;
import com.fr.base.Utils;
import com.fr.design.constants.LayoutConstants;
import com.fr.design.dialog.BasicPane;
import com.fr.design.event.UIObserverListener;
@ -79,11 +78,11 @@ public class ChartFontPane extends BasicPane {
}
protected JPanel getContentPane(JPanel buttonPane) {
double e1 = 75;
double e = 155;
double labelWidth = 90;
double totalWidth = 155;
double p = TableLayout.PREFERRED;
double[] rows = {p, p, p};
double[] columnSize = {e1, e};
double[] columnSize = {labelWidth, totalWidth};
UILabel text = new UILabel(getUILabelText(), SwingConstants.LEFT);
Component[][] components = {
new Component[]{null, null},
@ -91,7 +90,7 @@ public class ChartFontPane extends BasicPane {
new Component[]{null, buttonPane}
};
return TableLayoutHelper.createGapTableLayoutPane(components, rows, columnSize, 20, LayoutConstants.VGAP_LARGE);
return TableLayoutHelper.createGapTableLayoutPane(components, rows, columnSize, 5, LayoutConstants.VGAP_LARGE);
}
public String getUILabelText() {

31
designer-base/src/main/java/com/fr/design/mainframe/vcs/RecycleAction.java

@ -0,0 +1,31 @@
package com.fr.design.mainframe.vcs;
import com.fr.design.actions.UpdateAction;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.vcs.ui.RecycleSettingPane;
import java.awt.event.ActionEvent;
/**
* 回收站
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/4
*/
public class RecycleAction extends UpdateAction {
public RecycleAction() {
this.setSmallIcon("/com/fr/design/standard/vcslist/vcs_recycle", false);
this.setName(Toolkit.i18nText("Fine-Design_Vcs_Recycle"));
}
@Override
public void actionPerformed(ActionEvent e) {
RecycleSettingPane pane = new RecycleSettingPane();
BasicDialog dialog = pane.showWindow(DesignerContext.getDesignerFrame(), false);
dialog.setVisible(true);
}
}

25
designer-base/src/main/java/com/fr/design/mainframe/vcs/TableEntity.java

@ -0,0 +1,25 @@
package com.fr.design.mainframe.vcs;
/**
* 表格选中包装类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/11
*/
public interface TableEntity {
/**
* 是否选中
*
* @return
*/
boolean isSelect();
/**
* 设置选中属性
*
* @param select
*/
void setSelect(boolean select);
}

21
designer-base/src/main/java/com/fr/design/mainframe/vcs/TableValueOperator.java

@ -0,0 +1,21 @@
package com.fr.design.mainframe.vcs;
/**
* 表格操作
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/11
*/
public interface TableValueOperator<T> {
/**
* 获取对应列的值
*
* @param o 表格内容
* @param columnIndex 列数
* @return 对应列的值
*/
Object getValue(T o, int columnIndex);
}

25
designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsConfigManager.java

@ -16,6 +16,10 @@ public class VcsConfigManager implements XMLReadable, XMLWriter {
private boolean useInterval = true;
private int saveInterval = 60;
private boolean useAutoSave = false;
private int autoSaveInterval = 15;
public static VcsConfigManager getInstance() {
return instance;
}
@ -48,6 +52,23 @@ public class VcsConfigManager implements XMLReadable, XMLWriter {
return saveInterval;
}
public int getAutoSaveInterval() {
return autoSaveInterval;
}
public void setAutoSaveInterval(int autoSaveInterval) {
this.autoSaveInterval = autoSaveInterval;
}
public boolean isUseAutoSave() {
return useAutoSave;
}
public void setUseAutoSave(boolean useAutoSave) {
this.useAutoSave = useAutoSave;
}
public void setSaveInterval(int saveInterval) {
this.saveInterval = saveInterval;
}
@ -59,6 +80,8 @@ public class VcsConfigManager implements XMLReadable, XMLWriter {
this.setSaveInterval(reader.getAttrAsInt("saveInterval", 60));
this.setUseInterval(reader.getAttrAsBoolean("useInterval", true));
this.setVcsEnable(reader.getAttrAsBoolean("vcsEnable", true));
this.setAutoSaveInterval(reader.getAttrAsInt("autoSaveInterval", 15));
this.setUseAutoSave(reader.getAttrAsBoolean("useAutoSave", true));
}
}
@ -69,6 +92,8 @@ public class VcsConfigManager implements XMLReadable, XMLWriter {
writer.attr("saveInterval", this.getSaveInterval());
writer.attr("useInterval", this.isUseInterval());
writer.attr("vcsEnable", this.isVcsEnable());
writer.attr("autoSaveInterval", this.getAutoSaveInterval());
writer.attr("useAutoSave", this.isUseAutoSave());
writer.end();
}
}

37
designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsExceptionUtils.java

@ -0,0 +1,37 @@
package com.fr.design.mainframe.vcs;
import com.fr.design.i18n.Toolkit;
import java.io.IOException;
import java.util.HashMap;
/**
* 版本管理异常处理工具类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/24
*/
public class VcsExceptionUtils {
public static final HashMap<Class, String> EXCEPTION_MAP = new HashMap<Class, String>() {
{
put(IOException.class, Toolkit.i18nText("Fine-Design_Vcs_Exception_IO"));
put(UnsupportedOperationException.class, Toolkit.i18nText("Fine-Design_Vcs_Exception_Un_Support"));
}
};
/**
* 根据异常返回结果描述文案
*/
public static String createDetailByException(Exception e) {
for (Class key : EXCEPTION_MAP.keySet()) {
if (key.isAssignableFrom(e.getClass())) {
return EXCEPTION_MAP.get(key);
}
}
return Toolkit.i18nText("Fine-Design_Vcs_Exception_Unknown");
}
}

288
designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsOperatorWorker.java

@ -0,0 +1,288 @@
package com.fr.design.mainframe.vcs;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.vcs.ui.VcsBatchProcessDetailPane;
import com.fr.design.mainframe.vcs.ui.VcsProgressDialog;
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 com.fr.workspace.server.vcs.v2.VcsTaskResult;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* 为版本中心回收站版本详情提供带进度条与结算面板的操作的worker
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/18
*/
public class VcsOperatorWorker {
private int count = 0;
private static final int FREQ = 6;
private String successStr;
private String title;
private String failedStr;
private String everyFailedStr;
private VcsProgressDialog dialog;
private static final String PREFIX = "(v.";
private static final String TAIL = ")";
public VcsOperatorWorker(String title, String dealingStr, String successStr, String failedStr, String everyFailedStr) {
this.title = title;
this.successStr = successStr;
this.failedStr = failedStr;
this.everyFailedStr = everyFailedStr;
dialog = new VcsProgressDialog(title, dealingStr);
}
public VcsOperatorWorker(String everyFailedStr) {
this.title = StringUtils.EMPTY;
this.successStr = StringUtils.EMPTY;
this.failedStr = StringUtils.EMPTY;
this.everyFailedStr = everyFailedStr;
}
/**
* 快速创建用于删除的worker
*
* @return
*/
public static VcsOperatorWorker createDeleteWorker() {
return new VcsOperatorWorker(
Toolkit.i18nText("Fine-Design_Vcs_Delete_Progress_Title"),
Toolkit.i18nText("Fine-Design_Vcs_Delete_Progress_Tips"),
Toolkit.i18nText("Fine-Design_Vcs_Delete_Progress_Success"),
"Fine-Design_Vcs_Delete_Progress_Failed",
Toolkit.i18nText("Fine-Design_Vcs_Delete_Every_Failed"));
}
/**
* 快速创建用于还原的worker
*
* @return
*/
public static VcsOperatorWorker createRestoreWorker() {
return new VcsOperatorWorker(
Toolkit.i18nText("Fine-Design_Vcs_Restore_Progress_Title"),
Toolkit.i18nText("Fine-Design_Vcs_Restore_Progress_Tips"),
Toolkit.i18nText("Fine-Design_Vcs_Restore_Progress_Success"),
"Fine-Design_Vcs_Restore_Progress_Failed",
Toolkit.i18nText("Fine-Design_Vcs_Restore_Every_Failed"));
}
/**
* 快速创建用于还原的worker
*
* @return
*/
public static VcsOperatorWorker createUpdateWorker() {
return new VcsOperatorWorker(Toolkit.i18nText("Fine-Design_Vcs_Update_Every_Failed"));
}
/**
* 批量还原
*
* @param vcsEntities 需要还原的版本
*/
public void batchRestore(List<VcsEntity> vcsEntities, VcsTableOperatorListener listener) {
VcsProcessFailedWrapper wrapper = new VcsProcessFailedWrapper();
startProcess(vcsEntities, wrapper, (vcsEntity, operator) -> {
String fileName = vcsEntity.getFilename();
VcsTaskResult result = operator.restoreVersion(fileName);
if (!result.isSuccess()) {
wrapper.addFailedEntity(vcsEntity);
}
return result;
}, listener);
}
/**
* 批量删除
*
* @param vcsEntities 需要删除的版本
* @param all 是否需要删除所有版本
*/
public void batchDelete(List<VcsEntity> vcsEntities, boolean all, VcsTableOperatorListener listener) {
VcsProcessFailedWrapper wrapper = new VcsProcessFailedWrapper();
startProcess(vcsEntities, wrapper, (vcsEntity, operator) -> {
String fileName = vcsEntity.getFilename();
VcsTaskResult result;
if (all) {
result = operator.deleteVersionForRecycle(fileName);
} else {
result = operator.deleteVersion(fileName, vcsEntity.getVersion(), VcsEntity.CommitType.TYPE_DEFAULT);
}
if (!result.isSuccess()) {
wrapper.addFailedEntity(vcsEntity);
}
return result;
}, listener);
}
/**
* 删除指定模板的全部历史版本
*
* @param entity VcsEntity
*/
public void doDelete(VcsEntity entity, VcsTableOperatorListener listener) {
String fileName = entity.getFilename();
start4Single(entity, (vcsEntity, operator) -> operator.deleteVersionForRecycle(fileName), fileName + everyFailedStr, listener);
}
/**
* 删除指定模板的指定版本
*
* @param entity 版本
*/
public void deleteTargetVersion(VcsEntity entity, VcsTableOperatorListener listener) {
String fileName = entity.getFilename();
int version = entity.getVersion();
VcsEntity.CommitType commitType = entity.getCommitType();
start4Single(entity, (vcsEntity, operator) -> operator.deleteVersion(fileName, version, commitType), fileName + everyFailedStr, listener);
}
/**
* 更新版本
*
* @param entity 版本
*/
public void updateEntityAnnotation(VcsEntity entity, VcsTableOperatorListener listener) {
start4Single(entity, (vcsEntity, operator) -> {
operator.updateVersion(entity);
return new VcsTaskResult(true);
}, everyFailedStr, listener);
}
private void startProcess(List<VcsEntity> vcsEntities, VcsProcessFailedWrapper wrapper, VcsWorkerOperator workerOperator, VcsTableOperatorListener listener) {
try {
dialog.getProgressBar().setMaximum(vcsEntities.size());
start4Batch(vcsEntities, wrapper, workerOperator, listener);
dialog.showDialog();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
/**
* 控制更新频率
*
* @return 是否需要更新进度
*/
private boolean needPublish() {
return (count > FREQ && count % FREQ == 0) || count < FREQ;
}
private void start4Single(VcsEntity entity, VcsWorkerOperator vcsWorkerOperator, String failedTip, VcsTableOperatorListener listener) {
new SwingWorker<Boolean, Void>() {
@Override
protected void done() {
try {
if (!get()) {
FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(DesignerContext.getDesignerFrame()), failedTip);
} else {
listener.updateUI();
}
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
protected Boolean doInBackground() throws Exception {
try {
VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class);
VcsTaskResult result = vcsWorkerOperator.process(entity, operator);
return result.isSuccess();
} catch (Exception e) {
return false;
}
}
}.execute();
}
private void start4Batch(List<VcsEntity> vcsEntities, VcsProcessFailedWrapper wrapper, VcsWorkerOperator workerOperator, VcsTableOperatorListener listener) {
new SwingWorker<Boolean, Integer>() {
@Override
protected Boolean doInBackground() throws Exception {
VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class);
for (VcsEntity vcsEntity : vcsEntities) {
workerOperator.process(vcsEntity, operator);
count++;
if (needPublish()) {
publish(count);
}
}
return wrapper.isAllSuccess();
}
@Override
protected void process(List<Integer> chunks) {
dialog.getProgressBar().setValue(chunks.get(chunks.size() - 1));
}
@Override
protected void done() {
dialog.closeDialog();
try {
List<String> failedList = wrapper.getDetailFailedList();
showErrorDetailPane(get(), failedList, failedList.size(), vcsEntities.size() - failedList.size());
listener.updateUI(wrapper);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}.execute();
}
private void showErrorDetailPane(boolean result, List<String> failedList, int failed, int success) {
if (result) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), successStr);
} else {
VcsBatchProcessDetailPane pane = new VcsBatchProcessDetailPane(
DesignerContext.getDesignerFrame(),
title,
Toolkit.i18nText(failedStr, failed, success)
);
for (String msg : failedList) {
pane.updateDetailArea(msg + everyFailedStr);
}
pane.show();
}
}
/**
* Vcs面板操作处理接口
*
*/
private interface VcsWorkerOperator {
/**
* 处理
*
* @param vcsEntity 版本
* @param operator 操作类
*/
VcsTaskResult process(VcsEntity vcsEntity, VcsOperator operator) throws Exception;
}
}

60
designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsProcessFailedWrapper.java

@ -0,0 +1,60 @@
package com.fr.design.mainframe.vcs;
import com.fr.report.entity.VcsEntity;
import java.util.ArrayList;
import java.util.List;
/**
* 版本管理处理失败列表的包装类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/28
*/
public class VcsProcessFailedWrapper {
private static final String PREFIX = "(v.";
private static final String TAIL = ")";
private List<VcsEntity> failedList = new ArrayList<>();
/**
* 添加处理失败的VcsEntity
*
* @param entity entity
*/
public void addFailedEntity(VcsEntity entity) {
failedList.add(entity);
}
/**
* 获取用于展示的详细失败信息列表
*/
public List<String> getDetailFailedList() {
List<String> detailList = new ArrayList<>();
for (VcsEntity entity : failedList) {
detailList.add(entity.getFilename()+PREFIX+entity.getVersion()+TAIL);
}
return detailList;
}
/**
* 获取处理失败的vcsEntity的名称列表
*/
public List<String> getFailedNameList() {
List<String> detailList = new ArrayList<>();
for (VcsEntity entity : failedList) {
detailList.add(entity.getFilename());
}
return detailList;
}
/**
* 处理是否全部成功
*/
public boolean isAllSuccess() {
return failedList.isEmpty();
}
}

49
designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsRecycleSettingHelper.java

@ -0,0 +1,49 @@
package com.fr.design.mainframe.vcs;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.transaction.Configurations;
import com.fr.transaction.WorkerAdaptor;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.vcs.VcsConfig;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanOperator;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanService;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoRecycleSchedule;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 版本管理界面配置回收事件的处理类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/21
*/
public class VcsRecycleSettingHelper {
private static ExecutorService executorService = Executors.newSingleThreadExecutor(new NamedThreadFactory("VcsRecycle"));
/**
* 更新任务
*
* @param day
*/
public static void updateJob(int day) {
executorService.execute(new Runnable() {
@Override
public void run() {
Configurations.update(new WorkerAdaptor(VcsConfig.class) {
@Override
public void run() {
VcsConfig.getInstance().setV2CleanRecycleInterval(day);
}
});
WorkContext.getCurrent().get(VcsAutoCleanOperator.class).addOrUpdateVcsAutoCleanJob(
VcsAutoCleanService.VCS_AUTO_CLEAN_RECYCLE_JOB_NAME,
1,
VcsAutoRecycleSchedule.class);
}
});
}
}

113
designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableEntity.java

@ -0,0 +1,113 @@
package com.fr.design.mainframe.vcs;
import com.fr.report.entity.VcsEntity;
import com.fr.stable.StringUtils;
/**
* 包装VcsEntity的用于表格展示与处理的类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/10
*/
public class VcsTableEntity implements TableEntity{
private boolean select = false;
private static final String MB = "MB";
private static final String VERSION = "V.";
private static final double MB_SIZE = 1024.0 * 1024;
private VcsEntity entity;
public VcsTableEntity(VcsEntity entity) {
this.entity = entity;
}
/**
* 获取模板名
*
* @return 模板名
*/
public String getFilename() {
return entity.getFilename();
}
/**
* 获取版本大小
*
* @return 版本大小
*/
public String getSize() {
double size = entity.getSize()/MB_SIZE;
if (size == 0) {
return StringUtils.EMPTY;
}
return String.format("%.3f", size) + MB;
}
/**
* 获取修改时间
*
* @return 修改时间
*/
public String getTime() {
return entity.getTime().toLocaleString();
}
/**
* 获取用户名
*
* @return 用户名
*/
public String getUserName() {
return entity.getUsername();
}
/**
* 获取备注
*
* @return 备注
*/
public String getCommitMsg() {
return entity.getCommitMsg();
}
/**
* 获取版本号
*
* @return 版本号
*/
public String getVersion() {
return VERSION + entity.getVersion();
}
/**
* 获取删除时间
*
* @return 删除时间
*/
public String getDeleteTime() {
return entity.getDeleteTime().toLocaleString();
}
@Override
public boolean isSelect() {
return select;
}
@Override
public void setSelect(boolean select) {
this.select = select;
}
public VcsEntity getEntity() {
return entity;
}
public void setEntity(VcsEntity entity) {
this.entity = entity;
}
}

32
designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableOperatorListener.java

@ -0,0 +1,32 @@
package com.fr.design.mainframe.vcs;
import java.util.List;
/**
* 版本管理表格操作事件
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/27
*/
public interface VcsTableOperatorListener {
/**
* 处理操作
*/
default void doOperator(List<VcsTableEntity> entityList){}
/**
* 更新界面
*/
default void updateUI(){}
/**
* 根据处理失败的内容来更新界面
*
* @param wrapper 失败内容
*/
default void updateUI(VcsProcessFailedWrapper wrapper){}
}

113
designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCloseTemplateHelper.java

@ -0,0 +1,113 @@
package com.fr.design.mainframe.vcs.common;
import com.fr.base.vcs.DesignerMode;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.MultiTemplateTabPane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.vcs.ui.VcsNewPane;
import com.fr.design.worker.save.CallbackSaveWorker;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
/**
* 版本管理关闭模板辅助类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/27
*/
public class VcsCloseTemplateHelper {
/**
* 根据传入的pane与dialog生成指定面板的Vcs模板关闭的处理方法
* 如果指定模板已经打开
* <p>1.如果该模板已保存则正常打开新版本管理弹窗
* <p>2.如果该模板未保存触发保存逻辑
* <li>a.如果用户选择保存则保存并不关闭模板弹出新版本管理弹窗
* <li>b.如果用户选择不保存则关闭当前模板弹出新版本管理弹窗
* <li>c.如果用户选择取消, 则啥操作都不做
*
* @param path 对应模板路径
* @param isCurrentEditing 是否是正在编辑的模板
* @param parent 生成的新版本管理的详情面板的父面板
*/
public static void checkTemplateSavedAndShowVcsNewPane(String path, boolean isCurrentEditing, BasicDialog parent, VcsNewPane pane) {
VcsNewPaneWrapper wrapper = new VcsNewPaneWrapper(path, parent, pane);
for (JTemplate jTemplate : HistoryTemplateListCache.getInstance().getHistoryList()) {
if (ComparatorUtils.equals(jTemplate.getEditingFILE().getPath(), path)) {
if (!jTemplate.isALLSaved()) {
MultiTemplateTabPane.getInstance().setIsCloseCurrent(isCurrentEditing);
MultiTemplateTabPane.getInstance().closeFormat(jTemplate);
confirmCloseAndShowVcsNewPane(jTemplate, wrapper);
return;
}
}
}
wrapper.show();
}
/**
* 自己生成新的VcsNewPane的Vcs模板关闭的处理方法
*/
public static void checkTemplateSavedAndShowVcsNewPane(String path, boolean isCurrentEditing) {
checkTemplateSavedAndShowVcsNewPane(path, isCurrentEditing, null, null);
}
/**
* 是否是当前编辑的模板
*
* @param path 对应模板路径
* @return 是则返回true
*/
public static boolean isCurrentEditing(String path) {
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (JTemplate.isValid(jt)) {
String editing = jt.getEditingFILE().getPath();
return ComparatorUtils.equals(editing, path);
}
return false;
}
private static void confirmCloseAndShowVcsNewPane(JTemplate<?, ?> specifiedTemplate, VcsNewPaneWrapper wrapper) {
if (specifiedTemplate == null) {
return;
}
if (!specifiedTemplate.isALLSaved() && !DesignerMode.isVcsMode()) {
specifiedTemplate.stopEditing();
int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
String.format("%s\"%s\" ?",Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save"), specifiedTemplate.getEditingFILE()),
Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if (returnVal == JOptionPane.YES_OPTION) {
CallbackSaveWorker worker = specifiedTemplate.save();
worker.addSuccessCallback(() -> {
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName()));
SwingUtilities.invokeLater(wrapper::show);
});
worker.start(specifiedTemplate.getRuntimeId());
} else if (returnVal == JOptionPane.NO_OPTION) {
closeTpl(specifiedTemplate);
wrapper.show();
}
} else {
wrapper.show();
}
}
private static void closeTpl(JTemplate<?, ?> specifiedTemplate) {
HistoryTemplateListCache.getInstance().closeSelectedReport(specifiedTemplate);
MultiTemplateTabPane.getInstance().closeAndFreeLock(specifiedTemplate);
MultiTemplateTabPane.getInstance().activePrevTemplateAfterClose();
}
}

253
designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java

@ -2,6 +2,7 @@ package com.fr.design.mainframe.vcs.common;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.config.ConfigEvent;
import com.fr.design.DesignerEnvManager;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.TemplateTreePane;
@ -12,24 +13,35 @@ import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.JTemplateActionListener;
import com.fr.design.mainframe.vcs.VcsConfigManager;
import com.fr.design.mainframe.vcs.ui.FileVersionTable;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.event.ListenerAdaptor;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.manage.PluginManager;
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.Workspace;
import com.fr.workspace.WorkspaceEvent;
import com.fr.workspace.server.vcs.VcsFileUtils;
import com.fr.workspace.server.vcs.VcsOperator;
import com.fr.workspace.server.vcs.filesystem.VcsFileSystem;
import com.fr.workspace.server.vcs.git.config.GcConfig;
import javax.swing.Icon;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created by XiaXiang on 2019/4/17.
@ -53,12 +65,90 @@ public class VcsHelper implements JTemplateActionListener {
private final static String VCS_PLUGIN_ID = "com.fr.plugin.vcs.v10";
private final static String VCS_FILE_SLASH = "/";
private final static String SERVICE_NAME_MOVE = "moveVcs";
private static final String VCS_VERSIONS = "reportlets_versions";
private static final String VERSION_MARK = ".v";
private static final VcsHelper INSTANCE = new VcsHelper();
private static ScheduledExecutorService saveSchedule;
private volatile boolean legacyMode;
private volatile boolean root;
public static VcsHelper getInstance() {
return INSTANCE;
}
private VcsHelper() {
VcsOperator op = WorkContext.getCurrent().get(VcsOperator.class);
// 开了设计器启动页面时一开始取不到VcsOperator,通过下面的切换环境事件再取,这边判断下
if (op != null) {
try {
legacyMode = op.isLegacyMode();
root = WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot();
} catch (Exception e) {
legacyMode = true;
root = false;
FineLoggerFactory.getLogger().error("[VcsHelper] init first failed ", e.getMessage());
}
}
EventDispatcher.listen(ConfigEvent.READY, new ListenerAdaptor() {
@Override
protected void on(Event event) {
try {
legacyMode = WorkContext.getCurrent().get(VcsOperator.class).isLegacyMode();
FineLoggerFactory.getLogger().info("[VcsHelper] legacyMode:{}", legacyMode);
} catch (Exception e) {
//保险起见走老逻辑
legacyMode = true;
FineLoggerFactory.getLogger().error("[VcsHelper] get legacy failed", e.getMessage());
}
}
});
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener<Workspace>() {
@Override
public void on(Event event, Workspace param) {
try {
root = WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot() ;
} catch (Exception e) {
root = false;
FineLoggerFactory.getLogger().error("[VcsHelper] get root failed", e.getMessage());
}
}
});
}
/**
* 开始自动保存任务
*
* @param interval 时间间隔
*/
public void startAutoSave(int interval) {
stopAutoSave();
saveSchedule = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("VcsAutoSaveSchedule"));
saveSchedule.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
FineLoggerFactory.getLogger().info("[VcsV2] start to run auto save schedule");
JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (DesignerEnvManager.getEnvManager().getVcsConfigManager().isVcsEnable() && JTemplate.isValid(template)) {
fireAutoSaveVcs(template);
}
}
}, interval, interval, TimeUnit.MINUTES);
}
/**
* 停止任务
*/
public void stopAutoSave() {
if (saveSchedule != null && !saveSchedule.isShutdown()) {
saveSchedule.shutdown();
}
}
private int containsFolderCounts() {
TemplateFileTree fileTree = TemplateTreePane.getInstance().getTemplateFileTree();
if (fileTree.getSelectionPaths() == null) {
@ -93,20 +183,12 @@ public class VcsHelper implements JTemplateActionListener {
}
private String getEditingFilename() {
String vcsCacheDir = VcsFileSystem.getInstance().getVcsCacheRelativePath();
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(vcsCacheDir)) {
editingFilePath = editingFilePath.replaceFirst(vcsCacheDir, StringUtils.EMPTY);
}
if (editingFilePath.startsWith(VCS_FILE_SLASH)) {
editingFilePath = editingFilePath.substring(1);
}
return editingFilePath;
return VcsFileUtils.dealWithFilePath(editingFilePath);
}
private boolean needDeleteVersion(VcsEntity entity) {
VcsConfigManager configManager = DesignerEnvManager.getEnvManager().getVcsConfigManager();
if (entity == null || !configManager.isUseInterval()) {
@ -133,24 +215,21 @@ public class VcsHelper implements JTemplateActionListener {
fireVcs.execute(new Runnable() {
@Override
public void run() {
String fileName = getEditingFilename();
VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class);
VcsEntity entity = operator.getFileVersionByIndex(fileName, 0);
boolean replace = needDeleteVersion(entity);
int latestFileVersion = 0;
if (entity != null) {
latestFileVersion = entity.getVersion();
}
if (jt.getEditingFILE() instanceof VcsCacheFileNodeFile) {
operator.saveVersionFromCache(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1);
operator.saveVersionFromCache(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1, replace);
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath();
FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY)));
List<VcsEntity> updatedList = WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY));
SwingUtilities.invokeLater(() -> FileVersionTable.getInstance().updateModel(1, updatedList));
} else {
operator.saveVersion(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1);
}
VcsEntity oldEntity = WorkContext.getCurrent().get(VcsOperator.class).getFileVersionByIndexAndUsername(fileName, getCurrentUsername(), 1);
if (needDeleteVersion(oldEntity)) {
operator.deleteVersion(oldEntity.getFilename(), oldEntity.getVersion());
operator.saveVersion(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1, replace);
}
if (GcConfig.getInstance().isGcEnable()) {
operator.gc();
@ -158,7 +237,9 @@ public class VcsHelper implements JTemplateActionListener {
}
});
fireVcs.shutdown();
if (!fireVcs.isShutdown()) {
fireVcs.shutdown();
}
}
/**
@ -174,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<VcsEntity> 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();
}
}
@ -188,12 +273,85 @@ public class VcsHelper implements JTemplateActionListener {
moveVcs.shutdown();
}
/**
* 判断是否为老模式
* @return 是否为老模式
*/
public boolean isLegacyMode() {
return legacyMode;
}
/**
* 更新当前的legacyMode状态
* <li>目前用在迁移结束后更新模式为新模式</li>
*
*/
public void updateLegacyMode() {
this.legacyMode = !legacyMode;
}
@Override
public void templateOpened(JTemplate<?, ?> jt) {
try {
if (checkAutoSaveSupport()) {
startAutoSave(VcsConfigManager.getInstance().getAutoSaveInterval());
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage());
}
}
/**
* 响应版本管理自动保存
*
* <li>直接用template的file来保存的话相当于拿源文件来保存模板这样用户做的改动会丢失</li>
* <li>因此需要自己实现一下自动保存的逻辑将当前模板的数据导出,再拿这个Byte[]去做我们需要的保存处理</li>
* <li>保存后需要触发清理逻辑</li>
*
* @param jt 模板
*/
public void fireAutoSaveVcs(final JTemplate jt) {
String fileName = getEditingFilename();
VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class);
VcsEntity entity = operator.getFileVersionByIndex(fileName, 0);
boolean replace = needDeleteVersion(entity);
int latestFileVersion = 0;
if (entity != null) {
latestFileVersion = entity.getVersion();
}
if (JTemplate.isValid(jt)) {
doSave(jt, fileName, latestFileVersion, replace, operator);
}
}
private void doSave(JTemplate jt, String fileName, int latestFileVersion, boolean replace, VcsOperator operator) {
if (jt.getEditingFILE() instanceof VcsCacheFileNodeFile) {
operator.saveVersionFromCache(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1, replace);
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath();
List<VcsEntity> updatedList = WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY));
SwingUtilities.invokeLater(() -> FileVersionTable.getInstance().updateModel(1, updatedList));
} else {
autoSave(jt, getCurrentUsername(), fileName, latestFileVersion + 1, replace, operator);
}
if (GcConfig.getInstance().isGcEnable()) {
operator.gc();
}
}
private void autoSave(JTemplate jt, String currentUsername, String fileName, int nowVersion, boolean replace, VcsOperator operator) {
try {
if (JTemplate.isValid(jt) && !jt.isALLSaved()) {
operator.autoSave(currentUsername, fileName, StringUtils.EMPTY, nowVersion, jt.exportData(), replace);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage());
}
}
/**
* 模板保存时 处理.
*
@ -203,13 +361,58 @@ public class VcsHelper implements JTemplateActionListener {
public void templateSaved(JTemplate<?, ?> jt) {
if (needInit()
&& DesignerEnvManager.getEnvManager().getVcsConfigManager().isVcsEnable()
&& !WorkContext.getCurrent().isCluster()) {
// 如果是集群,在新版本下才生效
&& (!WorkContext.getCurrent().isCluster() || !VcsHelper.getInstance().isLegacyMode())) {
fireVcs(jt);
}
}
@Override
public void templateClosed(JTemplate<?, ?> jt) {
try {
if (checkAutoSaveSupport()) {
stopAutoSave();
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage());
}
}
/**
* 判断是否支持V2功能
*
* @return 支持返回true
*/
public boolean checkV2FunctionSupport() {
return !VcsHelper.getInstance().isLegacyMode() && root;
}
/**
* 判断是否支持迁移功能
*
* @return 支持返回true
*/
public boolean checkMoveFunctionSupport() {
return WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot();
}
/**
* 是否支持自动保存
*
* @return 支持返回true
*/
public boolean checkAutoSaveSupport() {
return VcsConfigManager.getInstance().isUseAutoSave() && !VcsHelper.getInstance().isLegacyMode();
}
/**
* 获取文件路径
*
* @param entity
* @return
*/
public String getFilePath(VcsEntity entity) {
return StableUtils.pathJoin(VCS_VERSIONS, entity.getFilename() + VERSION_MARK + entity.getVersion());
}
}

36
designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsNewPaneWrapper.java

@ -0,0 +1,36 @@
package com.fr.design.mainframe.vcs.common;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.mainframe.vcs.ui.VcsNewPane;
/**
* 构建VcsNewPane的包装类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/27
*/
public class VcsNewPaneWrapper {
private String path;
private BasicDialog dialog;
private VcsNewPane pane;
public VcsNewPaneWrapper(String path, BasicDialog dialog, VcsNewPane pane) {
this.path = path;
this.dialog = dialog;
this.pane = pane;
}
/**
* 显示面板
*/
public void show() {
if (pane != null) {
pane.showDialog(dialog);
} else {
VcsNewPane newPane = new VcsNewPane(path);
newPane.showDialog(dialog);
}
}
}

407
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/AbstractSupportSelectTablePane.java

@ -0,0 +1,407 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.base.svg.IconUtils;
import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.icheckbox.UICheckBox;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itableeditorpane.UITableEditAction;
import com.fr.design.gui.itableeditorpane.UITableEditorPane;
import com.fr.design.gui.itableeditorpane.UITableModelAdapter;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.vcs.TableEntity;
import com.fr.design.mainframe.vcs.TableValueOperator;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.UIResource;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* 比较通用的带全选功能的表格面板
*
* <p>整体划分为north与center两个面板参考BorderLayout的布局,center部分用于置放表格表格部分支持全选north部分支持自定义用于展示各种标签按钮输入框</p>
* <p>获取数据的时候不需要用SwingWorker(内部已经实现)考虑到大部分表格内容的展现需要去获取数据而获取数据大部分都需要一定时间因此为了防止UI冻结在加载数据结束之前先展示进度条面板</p>
* <p>使用该面板你可能需要:</p>
* <li>自己封装一个实现TableEntity接口(该接口用于提供(选中/全选)功能)内部存放你要放入表格的类例如VcsEntity,参考VcsTableEntity</li>
* <li>初始化的时候赋予变量model值(如果有需要的话)该变量用于控制表格的数据类型,默认DefaultModel分为5列第一列为勾选框</li>
* <li>(一定要干的)初始化的时候赋予变量model内operators值,用于确认表格每一列getValueAt返回的值</li>
* <li>上面板也允许自定义重写initTableTopPane即可</li>
* <li>要使用该面板可以参考:RecyclePane</li>
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/11
*/
public abstract class AbstractSupportSelectTablePane<T extends TableEntity> extends BasicPane {
public static final Color DEFAULT_HEADER_COLOR = new Color(232, 232, 233);
public static final Color DEFAULT_SELECT_TABLE_ROW_COLOR = new ColorUIResource(200, 221, 233);
private CardLayout layout;
protected JPanel contentPane;
protected UITextField searchTextField = new UITextField();;
protected UILabel deleteLabel = new UILabel();
/**
* 整体面板的center部分,用来放表格
*/
protected UITableEditorPane<T> tableContentPane;
protected UITableModelAdapter<T> model;
/**
* 整体面板的north部分
*/
protected JPanel tableTopPane = new JPanel();
/**
* 整体面板
*/
protected JPanel tablePane = new JPanel();
private int selectCount = 0;
private static final String LOADING = "loading";
private static final String TABLE ="table";
protected List<T> entities;
protected TableValueOperator<T> operator;
public AbstractSupportSelectTablePane(String title, TableValueOperator<T> operators, String[] tableNames, boolean needBorder) {
this.operator = operators;
this.model = new DefaultModel(tableNames, new Class[]{
Boolean.class,
UILabel.class,
UILabel.class,
UILabel.class,
UILabel.class
});
init(title, needBorder);
}
public AbstractSupportSelectTablePane(String title, TableValueOperator<T> operators, boolean needBorder) {
this.operator = operators;
init(title, needBorder);
}
/**
* 初始化
*
*/
private void init(String title, boolean needBorder) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
contentPane = new JPanel();
layout = new CardLayout();
contentPane.setLayout(layout);
contentPane.add(new TipsPane(true), LOADING);
this.add(contentPane);
new SwingWorker<List<T>, Void>(){
@Override
protected List<T> doInBackground() {
return getTableList();
}
@Override
protected void done() {
try {
entities = get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
contentPane.add(createTablePane(title, needBorder), TABLE);
layout.show(contentPane, TABLE);
}
}.execute();
}
/**
* 获取表格数据
*
* @return 表格数据
*/
abstract protected List<T> getTableList();
private JPanel createTablePane(String title, boolean needBorder) {
tablePane = needBorder ? FRGUIPaneFactory.createTopVerticalTitledBorderPane(title) : new JPanel();
if (isNeedTopPane()) {
initTableTopPane();
initTopPaneListener();
}
initTableContentPane(entities);
tablePane.setLayout(new BorderLayout());
tablePane.add(tableTopPane, BorderLayout.NORTH);
tablePane.add(tableContentPane, BorderLayout.CENTER);
tableContentPane.getEditTable().getColumnModel().getColumn(0).setMaxWidth(50);
RowSorter<UITableModelAdapter<T>> sorter = new TableRowSorter<UITableModelAdapter<T>>(model) {
@Override
public boolean isSortable(int column) {
return column != 0;
}
};
tableContentPane.getEditTable().setRowSorter(sorter);
return tablePane;
}
/**
* 初始化表格面板
*
* @param entities 表格数据
*/
protected void initTableContentPane(List<T> entities) {
tableContentPane = new UITableEditorPane<>(model);
model.setList(entities);
JTable table = tableContentPane.getEditTable();
table.getTableHeader().setBackground(DEFAULT_HEADER_COLOR);
table.getTableHeader().setDefaultRenderer(new HeaderRenderer(tableContentPane.getEditTable()));
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int row = ((JTable) e.getSource()).rowAtPoint(e.getPoint());
int col = ((JTable) e.getSource()).columnAtPoint(e.getPoint());
if (col == 0) {
T entity = model.getConvertRowSelectedValue(row);
//改变面板的各个状态
changeComponentStatus(entity, row, col, table);
}
}
});
initExtraListener4Table(table);
}
/**
* 设定额外的表格事件
*
* @param table 表格
*/
protected void initExtraListener4Table(JTable table) {
//do nothing
}
/**
* 是否需要上面板
*
* @return
*/
protected boolean isNeedTopPane() {
return true;
}
private void changeComponentStatus(T entity, int row, int col, JTable table) {
boolean select = entity.isSelect();
entity.setSelect(!select);
table.setValueAt(entity.isSelect(), row, col);
if (select) {
selectCount--;
} else {
selectCount++;
}
//更新表头的勾选框状态
HeaderRenderer renderer = (HeaderRenderer) table.getTableHeader().getDefaultRenderer();
renderer.refreshHeader(table, selectCount >= table.getRowCount());
changeExtraComponentStatus();
}
/**
* 更新额外组件的状态
*/
protected void changeExtraComponentStatus() {
}
public int getSelectCount() {
return selectCount;
}
/**
* 初始化上面板
*/
abstract protected void initTableTopPane();
/**
* 初始化上面板事件
*/
abstract protected void initTopPaneListener();
/**
* 表头渲染
*/
public class HeaderRenderer implements TableCellRenderer {
JTableHeader tableHeader;
final UICheckBox selectBox;
public HeaderRenderer(JTable table) {
this.tableHeader = table.getTableHeader();
tableHeader.setCursor(new Cursor(Cursor.HAND_CURSOR));
selectBox = new UICheckBox();
selectBox.setSelected(false);
tableHeader.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() > 0) {
//获得选中列
int selectColumn = tableHeader.columnAtPoint(e.getPoint());
if (selectColumn == 0) {
boolean value = !selectBox.isSelected();
selectBox.setSelected(value);
selectAllOrNull(value);
selectCount = value ? table.getRowCount() : 0;
changeExtraComponentStatus();
tableHeader.repaint();
model.fireTableDataChanged();
}
}
}
private void selectAllOrNull(boolean value) {
int len = table.getRowCount();
for (T entity : model.getList()) {
entity.setSelect(value);
}
}
});
}
/**
* 刷新表头
*
* @param table
*/
public void refreshHeader(JTable table, boolean value) {
selectBox.setSelected(value);
int rowHeight = table.getRowHeight();
table.updateUI();
table.setRowHeight(rowHeight);
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int column) {
tableHeader = table.getTableHeader();
tableHeader.setReorderingAllowed(false);
String valueStr = (String) value;
UILabel label = new UILabel(valueStr);
if (needIcon4Head(column)) {
label.setIcon(IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_sort"));
label.setHorizontalTextPosition(JLabel.LEFT);
label.setHorizontalAlignment(SwingConstants.LEFT);
}
selectBox.setHorizontalAlignment(SwingConstants.CENTER);
selectBox.setBorderPainted(true);
JComponent component = (column == 0) ? selectBox : label;
component.setForeground(tableHeader.getForeground());
component.setBackground(tableHeader.getBackground());
component.setFont(tableHeader.getFont());
component.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return component;
}
}
@Override
protected String title4PopupWindow() {
return StringUtils.EMPTY;
}
/**
* 默认的数据model
*/
public class DefaultModel extends UITableModelAdapter<T> {
public DefaultModel(String[] tableNames, Class[] classes) {
super(tableNames);
setColumnClass(classes);
this.setDefaultEditor(Boolean.class, new BooleanEditor());
this.setDefaultRenderer(Boolean.class, new BooleanRenderer());
this.setDefaultRenderer(UILabel.class, new ToolTipTableCellRenderer());
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
T vcsEntity = this.getList().get(rowIndex);
return operator.getValue(vcsEntity, columnIndex);
}
@Override
public boolean isCellEditable(int row, int col) {
return col == 0;
}
@Override
public UITableEditAction[] createAction() {
return new UITableEditAction[0];
}
}
/**
* 用于展示指定风格的checkbox的Editor
*/
public class BooleanEditor extends DefaultCellEditor {
public BooleanEditor() {
super(new UICheckBox());
UICheckBox checkBox = (UICheckBox) getComponent();
checkBox.setHorizontalAlignment(UICheckBox.CENTER);
}
}
/**
* 用于展示指定风格的checkbox的渲染器
*/
public class BooleanRenderer extends UICheckBox implements TableCellRenderer, UIResource {
public BooleanRenderer() {
super();
setHorizontalAlignment(JLabel.CENTER);
setBorderPainted(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setSelected((Boolean) table.getValueAt(row, 0));
setUI(getUICheckBoxUI());
setBorder(BorderFactory.createEmptyBorder());
setBackground(isSelected ? DEFAULT_SELECT_TABLE_ROW_COLOR : Color.WHITE);
return this;
}
}
/**
* 表头的某列是否需要icon
*
* @param col
* @return
*/
protected boolean needIcon4Head(int col) {
return col != 0;
}
}

26
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java

@ -81,12 +81,7 @@ public class EditFileVersionDialog extends UIDialog {
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
entity.setCommitMsg(msgTestArea.getText());
WorkContext.getCurrent().get(VcsOperator.class).updateVersion(entity);
setVisible(false);
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath();
FileVersionTable table = FileVersionTable.getInstance();
table.updateModel(table.getSelectedRow(), WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", StringUtils.EMPTY)));
doOK();
}
});
@ -101,4 +96,23 @@ public class EditFileVersionDialog extends UIDialog {
public void checkValid() throws Exception {
}
/**
* 确定事件
*
*/
public void doOK() {
entity.setCommitMsg(msgTestArea.getText());
WorkContext.getCurrent().get(VcsOperator.class).updateVersion(entity);
setVisible(false);
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath();
FileVersionTable table = FileVersionTable.getInstance();
table.updateModel(table.getSelectedRow(), WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", StringUtils.EMPTY)));
}
public UITextArea getMsgTestArea() {
return msgTestArea;
}
}

406
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecyclePane.java

@ -0,0 +1,406 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.base.svg.IconUtils;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.vcs.VcsOperatorWorker;
import com.fr.design.mainframe.vcs.TableEntity;
import com.fr.design.mainframe.vcs.TableValueOperator;
import com.fr.design.mainframe.vcs.VcsProcessFailedWrapper;
import com.fr.design.mainframe.vcs.VcsTableEntity;
import com.fr.design.mainframe.vcs.VcsTableOperatorListener;
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.Icon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.fr.design.i18n.Toolkit.i18nText;
/**
* 回收面板
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/5
*/
public class RecyclePane extends AbstractSupportSelectTablePane<VcsTableEntity> {
public static final Icon ICON_SEARCH = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_recycle_search");
public static final Icon ICON_REFRESH = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_restore", IconUtils.ICON_TYPE_NORMAL);
public static final Icon ICON_REFRESH_DISABLE = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_restore", IconUtils.ICON_TYPE_DISABLED);
public static final Icon ICON_DELETE = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_delete", IconUtils.ICON_TYPE_NORMAL);
public static final Icon ICON_DELETE_DISABLE = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_delete", IconUtils.ICON_TYPE_DISABLED);
private Set<VcsTableOperatorListener> listenerSet = new HashSet<>();
protected UITextField searchTextField;
protected UILabel deleteLabel;
protected UILabel restoreLabel;
private static final int COLUMNS_COUNT = 15;
private BasicDialog dialog;
private BasicDialog parentDialog;
private List<VcsTableEntity> tableEntities;
public RecyclePane() {
super(i18nText("Fine-Design_Vcs_Recycle"), (o, columnIndex) -> {
switch (columnIndex) {
case 0:
return o.isSelect();
case 1:
return o.getFilename();
case 2:
return o.getSize();
case 3:
return o.getDeleteTime();
case 4:
return o.getTime();
default:
return o;
}
}, new String[]{
StringUtils.EMPTY,
Toolkit.i18nText("Fine-Design_Vcs_Template"),
Toolkit.i18nText("Fine-Design_Vcs_Recycle_Size"),
Toolkit.i18nText("Fine-Design_Vcs_Delete_Time"),
Toolkit.i18nText("Fine-Design_Vcs_Time")
}, false);
}
public RecyclePane(String title, TableValueOperator<VcsTableEntity> operators, boolean needBorder) {
super(title, operators, needBorder);
}
@Override
protected List<VcsTableEntity> getTableList() {
List<VcsEntity> entityList = WorkContext.getCurrent().get(VcsOperator.class).getRecycleEntities();
List<VcsTableEntity> tableEntities = new ArrayList<>();
for (VcsEntity entity : entityList) {
tableEntities.add(new VcsTableEntity(entity));
}
updateTableList(tableEntities);
return tableEntities;
}
@Override
protected void initTableTopPane() {
tableTopPane = new JPanel();
tableTopPane.setLayout(new BorderLayout());
JPanel leftPane = new JPanel();
JPanel rightPane = new JPanel();
//左边面板,包含搜索icon+搜索框
if (isNeedSearch()) {
searchTextField = new UITextField();
searchTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Vcs_Start_Search"));
searchTextField.setColumns(COLUMNS_COUNT);
leftPane.add(new UILabel(ICON_SEARCH));
leftPane.add(searchTextField);
}
//右边面板,包括还原按钮+删除按钮
if (isNeedRestore()) {
restoreLabel = new UILabel(ICON_REFRESH);
restoreLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
restoreLabel.setDisabledIcon(ICON_REFRESH_DISABLE);
restoreLabel.setEnabled(false);
rightPane.add(restoreLabel);
}
if (isNeedDelete()) {
deleteLabel = new UILabel(ICON_DELETE);
deleteLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
deleteLabel.setDisabledIcon(ICON_DELETE_DISABLE);
deleteLabel.setEnabled(false);
rightPane.add(deleteLabel);
}
tableTopPane.add(leftPane, BorderLayout.EAST);
tableTopPane.add(rightPane, BorderLayout.WEST);
}
@Override
protected void changeExtraComponentStatus() {
boolean canUseLabel = getSelectCount() > 0;
if (restoreLabel != null) {
restoreLabel.setEnabled(canUseLabel);
}
if (deleteLabel != null) {
deleteLabel.setEnabled(canUseLabel);
}
}
@Override
protected void initTopPaneListener() {
initSearchTextFiledListener();
initRestoreListener();
initDeleteLabelListener();
}
private void initDeleteLabelListener() {
if (isNeedDelete()) {
deleteLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Delete"));
deleteLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
fireListener(new VcsResponseListener() {
@Override
public void doAfterChooseYes(List<VcsEntity> selectList) {
VcsOperatorWorker.createDeleteWorker(). batchDelete(selectList, isNeedDeleteAllVersion(), new VcsTableOperatorListener() {
@Override
public void updateUI(VcsProcessFailedWrapper wrapper) {
updateVcsUI(wrapper);
}
});
}
}, true);
}
});
}
}
private void initRestoreListener() {
if (isNeedRestore()) {
restoreLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Restore"));
restoreLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
fireListener(new VcsResponseListener() {
@Override
public void doAfterChooseYes(List<VcsEntity> selectList) {
VcsOperatorWorker.createRestoreWorker().batchRestore(selectList, new VcsTableOperatorListener() {
@Override
public void updateUI(VcsProcessFailedWrapper wrapper) {
updateVcsUI(wrapper);
}
});
}
}, false);
}
});
}
}
private void initSearchTextFiledListener() {
if (isNeedSearch()) {
searchTextField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String str = searchTextField.getText();
model.setList(tableEntities.stream().filter(entity -> entity.getEntity().getFilename().contains(str)).collect(Collectors.toList()));
model.fireTableDataChanged();
}
});
}
}
private void fireListener(VcsResponseListener listener, boolean isDelete) {
List<VcsEntity> selectList = model.getList().stream().filter(TableEntity::isSelect).map(VcsTableEntity::getEntity).collect(Collectors.toList());
if (selectList.size() > 0) {
int selVal = FineJOptionPane.showConfirmDialog(
RecyclePane.this,
isDelete ? getDeleteTip(selectList.size()) : getRestoreTip(selectList.size()),
Toolkit.i18nText("Fine-Design_Basic_Confirm"),
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (selVal == JOptionPane.YES_OPTION) {
listener.doAfterChooseYes(selectList);
}
}
}
private void updateVcsUI(VcsProcessFailedWrapper wrapper) {
tableEntities = model.getList().stream().filter(tableEntity -> !tableEntity.isSelect() || wrapper.getFailedNameList().contains(tableEntity.getFilename())).collect(Collectors.toList());
model.setList(new ArrayList<>(tableEntities));
model.fireTableDataChanged();
fireVcsListener(model.getList());
}
/**
* 显示弹窗
*
*/
public void showDialog() {
dialog = this.showWindow(DesignerContext.getDesignerFrame(), false);
dialog.setVisible(true);
}
/**
* 依据父弹窗显示弹窗
*
* @param parent 父弹窗
*/
public void showDialog(BasicDialog parent) {
this.parentDialog = parent;
dialog = this.showWindow(parent, false);
initDialogListener(dialog);
dialog.setVisible(true);
}
protected void initDialogListener(BasicDialog dialog) {
}
/**
* 关闭弹窗,如果有父弹窗,则一起关闭,如果有属性配置的弹窗面板要保存再关闭
*
*/
public void saveSettingAndCloseDialog() {
if (dialog != null) {
dialog.doOK();
dialog.dispose();
}
if (parentDialog != null) {
parentDialog.doOK();
parentDialog.dispose();
}
}
public BasicDialog getDialog() {
return dialog;
}
public void setDialog(BasicDialog dialog) {
this.dialog = dialog;
}
public BasicDialog getParentDialog() {
return parentDialog;
}
public void setParentDialog(BasicDialog parentDialog) {
this.parentDialog = parentDialog;
}
/**
* 添加版本管理表格操作事件
*
* @param listener 版本管理表格操作事件
*/
public void addVcsListener(VcsTableOperatorListener listener) {
listenerSet.add(listener);
}
/**
* 触发版本管理表格操作事件
*/
public void fireVcsListener(List<VcsTableEntity> tableEntities) {
for (VcsTableOperatorListener listener : listenerSet) {
listener.doOperator(tableEntities);
}
}
/**
* 删除范围
*
* @return 默认删除全部版本
*/
protected boolean isNeedDeleteAllVersion() {
return true;
}
@Override
protected String title4PopupWindow() {
return i18nText("Fine-Design_Vcs_Recycle");
}
/**
* 删除提示
*
* @return 默认需要
*/
protected String getDeleteTip(int size) {
return Toolkit.i18nText("Fine-Design_Vcs_Delete_Select_All_Version_Forever", size);
}
/**
* 还原提示
*
* @return 默认需要
*/
protected String getRestoreTip(int size) {
return Toolkit.i18nText("Fine-Design_Vcs_Restore_Select_All_Version", size);
}
/**
* 是否需要还原功能
*
* @return 默认需要
*/
protected boolean isNeedRestore() {
return true;
}
/**
* 是否需要搜索功能
*
* @return 默认需要
*/
protected boolean isNeedSearch() {
return true;
}
/**
* 是否需要删除功能
*
* @return 默认需要
*/
protected boolean isNeedDelete() {
return true;
}
/**
* 更新数据列表
*
* @param entities
*/
public void updateTableList(List<VcsTableEntity> entities) {
tableEntities = new ArrayList<>(entities);
}
/**
* 移除指定元素
*
* @param entity
*/
public void removeTarget(VcsTableEntity entity) {
tableEntities.remove(entity);
}
/**
* 版本管理按钮事件响应
*/
public interface VcsResponseListener {
/**
* 选择确认之后要做的事情
*
* @param selectList 所选上的内容
*/
void doAfterChooseYes(List<VcsEntity> selectList);
}
}

103
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecycleSettingPane.java

@ -0,0 +1,103 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.frpane.UITabbedPane;
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.ispinner.UISpinner;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.mainframe.vcs.VcsRecycleSettingHelper;
import com.fr.workspace.server.vcs.VcsConfig;
import javax.swing.JPanel;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* 回收站配置面板
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/21
*/
public class RecycleSettingPane extends BasicPane {
private static final int MIN_VALUE = 1;
private static final int MAX_VALUE = 999;
private static final int STEP = 1;
private static final int DEFAULT_VALUE = 30;
private UISpinner spinner;
private UIButton button;
public RecycleSettingPane() {
init();
}
private void init() {
this.setLayout(new BorderLayout());
UITabbedPane tabbedPane = new UITabbedPane();
//回收站内容
JPanel recyclePane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
UIScrollPane recycleScrollPane = patchScroll(recyclePane);
tabbedPane.addTab(Toolkit.i18nText("Fine-Design_Vcs_Recycle_Content"), recycleScrollPane);
recyclePane.add(new RecyclePane());
//通用设置
JPanel settingPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
UIScrollPane settingScrollPane = patchScroll(settingPane);
tabbedPane.addTab(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings"), settingScrollPane);
settingPane.add(createSchedulePane());
this.add(tabbedPane, BorderLayout.CENTER);
}
private JPanel createSchedulePane() {
JPanel schedulePane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 0);
JPanel spinnerPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
JPanel buttonPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
spinnerPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Recycle_Schedule")));
spinner = new UISpinner(MIN_VALUE, MAX_VALUE, STEP, DEFAULT_VALUE);
spinner.setValue(VcsConfig.getInstance().getV2CleanRecycleInterval());
spinnerPane.add(spinner);
spinnerPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Recycle_Schedule_Day")));
schedulePane.add(spinnerPane);
button = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Save"));
initButtonListener();
buttonPane.add(button);
schedulePane.add(buttonPane);
return schedulePane;
}
private void initButtonListener() {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
VcsRecycleSettingHelper.updateJob((int) spinner.getValue());
}
});
}
private UIScrollPane patchScroll(JPanel generalPane) {
UIScrollPane generalPanelWithScroll = new UIScrollPane(generalPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
generalPanelWithScroll.setBorder(new EmptyBorder(0, 0, 0, 0));
return generalPanelWithScroll;
}
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Vcs_Recycle");
}
}

32
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/ToolTipTableCellRenderer.java

@ -0,0 +1,32 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.general.GeneralUtils;
import com.fr.stable.StringUtils;
import javax.swing.JTable;
import javax.swing.JLabel;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
/**
* 带ToolTip的UILabel的表格渲染类
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/21
*/
public class ToolTipTableCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if(component instanceof JLabel) {
String toolTipText = GeneralUtils.objectToString(value);
if (StringUtils.isNotEmpty(toolTipText)) {
((JLabel) component).setToolTipText(toolTipText);
}
}
return component;
}
}

59
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntEditor.java

@ -0,0 +1,59 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.design.editor.editor.IntegerEditor;
import com.fr.design.gui.itextfield.UIIntNumberField;
import com.fr.design.gui.itextfield.UINumberField;
import com.fr.stable.StringUtils;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
/**
* 正整数输入框
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/25
*/
public class UIPositiveIntEditor extends IntegerEditor {
private static final int DEFAULT_COLUMNS = 4;
private static final int MIN = 1;
private static final int MAX = 99999;
private static final int DEFAULT_VALUE = 60;
public UIPositiveIntEditor(Integer value) {
super(value);
numberField.setMaxValue(MAX);
numberField.setMinValue(MIN);
initNumberFieldListener();
}
public UIPositiveIntEditor(Integer value, Integer min, Integer max) {
super(value);
numberField.setMaxValue(max);
numberField.setMinValue(min);
initNumberFieldListener();
}
private void initNumberFieldListener() {
numberField.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
if (StringUtils.isEmpty(numberField.getTextValue())) {
numberField.setValue(DEFAULT_VALUE);
}
}
});
}
@Override
protected UINumberField createNumberField() {
UIIntNumberField field = new UIIntNumberField();
field.setColumns(DEFAULT_COLUMNS);
return field;
}
}

39
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntSpinner.java

@ -0,0 +1,39 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.design.gui.ispinner.UISpinner;
import com.fr.design.gui.itextfield.UIIntNumberField;
import com.fr.design.gui.itextfield.UINumberField;
/**
* 只允许输入正整数的Spinner
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/25
*/
public class UIPositiveIntSpinner extends UISpinner {
private static final int DEFAULT_COLUMNS = 5;
public UIPositiveIntSpinner() {
}
public UIPositiveIntSpinner(double minValue, double maxValue, double dierta) {
super(minValue, maxValue, dierta);
}
public UIPositiveIntSpinner(double minValue, double maxValue, double dierta, double defaultValue) {
super(minValue, maxValue, dierta, defaultValue);
}
public UIPositiveIntSpinner(double minValue, double maxValue, double dierta, double defaultValue, boolean fillNegativeNumber) {
super(minValue, maxValue, dierta, defaultValue, fillNegativeNumber);
}
@Override
protected UINumberField initNumberField() {
UIIntNumberField field = new UIIntNumberField();
field.setColumns(DEFAULT_COLUMNS);
return field;
}
}

156
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsBatchProcessDetailPane.java

@ -0,0 +1,156 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* 处理结果详细面板
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/19
*/
public class VcsBatchProcessDetailPane {
private UILabel message = new UILabel();
private UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Report_OK"));
private UILabel uiLabel = new UILabel();
private UILabel directUiLabel = new UILabel();
private UILabel detailLabel = new UILabel();
private JPanel upPane;
private JPanel midPane;
private JPanel downPane;
private JPanel hiddenPanel;
private JTextArea jta;
private JDialog dialog;
public static final Dimension DEFAULT = new Dimension(380, 150);
public static final Dimension DEFAULT_PRO = new Dimension(380, 270);
public VcsBatchProcessDetailPane(Frame parent, String title, String msg) {
init(parent, title, msg);
}
private void init(Frame parent, String title, String msg) {
message.setBorder(BorderFactory.createEmptyBorder(8, 5, 0, 0));
message.setText(msg);
dialog = new JDialog(parent, title, true);
dialog.setSize(DEFAULT);
JPanel jp = new JPanel();
initUpPane();
initDownPane();
initMidPane();
initHiddenPanel();
initListener();
jp.setLayout(new BoxLayout(jp, BoxLayout.Y_AXIS));
jp.add(upPane);
jp.add(midPane);
jp.add(hiddenPanel);
jp.add(downPane);
hiddenPanel.setVisible(false);
dialog.add(jp);
dialog.setResizable(false);
dialog.setLocationRelativeTo(SwingUtilities.getWindowAncestor(parent));
}
private void initDownPane() {
downPane = new JPanel();
downPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 15, 9));
downPane.add(cancelButton);
}
private void initUpPane() {
upPane = new JPanel();
uiLabel = new UILabel(UIManager.getIcon("OptionPane.errorIcon"));
upPane.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10));
upPane.add(uiLabel);
upPane.add(message);
}
private void initMidPane() {
midPane = new JPanel();
midPane.add(directUiLabel);
midPane.add(detailLabel);
midPane.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0));
detailLabel.setText(Toolkit.i18nText("Fine_Designer_Look_Detail"));
detailLabel.setForeground(Color.BLUE);
detailLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.right"));
}
private void initHiddenPanel() {
hiddenPanel = new JPanel();
hiddenPanel.setLayout(new BorderLayout(2, 0));
hiddenPanel.add(new JPanel(), BorderLayout.WEST);
hiddenPanel.add(new JPanel(), BorderLayout.EAST);
JPanel borderPanel = new JPanel();
borderPanel.setLayout(new BorderLayout());
jta = new JTextArea();
JScrollPane jsp = new JScrollPane(jta);
jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jta.setEditable(false);
borderPanel.add(jsp, BorderLayout.CENTER);
hiddenPanel.add(borderPanel);
}
/**
* 补充更详细的报错信息
*
* @param message 信息
*/
public void updateDetailArea(String message) {
jta.append(message + "\n");
}
private void initListener() {
detailLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (hiddenPanel.isVisible()) {
hiddenPanel.setVisible(false);
dialog.setSize(DEFAULT);
detailLabel.setText(Toolkit.i18nText("Fine_Designer_Look_Detail"));
directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.right"));
} else {
dialog.setSize(DEFAULT_PRO);
hiddenPanel.setVisible(true);
detailLabel.setText(Toolkit.i18nText("Fine_Designer_Hide_Detail"));
directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.down"));
}
}
});
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
hiddenPanel.removeAll();
dialog.dispose();
}
});
}
/**
* 显示面板
*/
public void show() {
dialog.setVisible(true);
}
}

35
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellEditor.java

@ -0,0 +1,35 @@
package com.fr.design.mainframe.vcs.ui;
import javax.swing.AbstractCellEditor;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
import java.awt.*;
import static com.fr.design.mainframe.vcs.ui.AbstractSupportSelectTablePane.DEFAULT_SELECT_TABLE_ROW_COLOR;
/**
* Vcs的表格Editor
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/20
*/
public class VcsCellEditor extends AbstractCellEditor implements TableCellEditor {
private final VcsOperatorPane vcsPanel;
public VcsCellEditor(VcsOperatorPane vcsPanel) {
this.vcsPanel = vcsPanel;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
vcsPanel.setBackground(isSelected ? DEFAULT_SELECT_TABLE_ROW_COLOR : Color.WHITE);
return vcsPanel;
}
@Override
public Object getCellEditorValue() {
return vcsPanel;
}
}

29
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellRender.java

@ -0,0 +1,29 @@
package com.fr.design.mainframe.vcs.ui;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import static com.fr.design.mainframe.vcs.ui.AbstractSupportSelectTablePane.DEFAULT_SELECT_TABLE_ROW_COLOR;
/**
* Vcs的表格Render
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/20
*/
public class VcsCellRender implements TableCellRenderer {
private final VcsOperatorPane vcsPanel;
public VcsCellRender(VcsOperatorPane vcsPanel) {
this.vcsPanel = vcsPanel;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
vcsPanel.setBackground(isSelected ? DEFAULT_SELECT_TABLE_ROW_COLOR : Color.WHITE);
return vcsPanel;
}
}

268
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java

@ -0,0 +1,268 @@
package com.fr.design.mainframe.vcs.ui;
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;
import com.fr.design.mainframe.vcs.VcsTableEntity;
import com.fr.design.mainframe.vcs.VcsTableOperatorListener;
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;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.vcs.VcsOperator;
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;
/**
* 版本中心面板
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/13
*/
public class VcsCenterPane extends VcsNewPane {
private UILabel manager;
private UILabel open;
private UILabel delete;
private static final Icon MANAGER_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_center_manager");
private static final Icon DELETE_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_delete");
private static final Icon OPEN_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_center_open");
private static final Class[] CLASSES = new Class[]{
Boolean.class,
UILabel.class,
UILabel.class,
UILabel.class,
VcsOperatorPane.class
};
private static final int OPERATOR_COL = 4;
private static final String[] COLUMN_NAMES = new String[]{
StringUtils.EMPTY,
Toolkit.i18nText("Fine-Design_Vcs_Template"),
Toolkit.i18nText("Fine-Design_Vcs_Time"),
Toolkit.i18nText("Fine-Design_Vcs_Size"),
Toolkit.i18nText("Fine-Design_Vcs_Operator")
};
private static final String TITLE = Toolkit.i18nText("Fine-Design_Vcs_Center");
public VcsCenterPane() {
super(TITLE, (o, columnIndex) -> {
switch (columnIndex) {
case 0:
return o.isSelect();
case 1:
return o.getFilename();
case 2:
return o.getTime();
case 3:
return o.getSize();
default:
return o;
}
}, false, COLUMN_NAMES, CLASSES, OPERATOR_COL);
}
@Override
public VcsOperatorPane createOperatorPane() {
manager = new UILabel(MANAGER_ICON);
manager.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Manager"));
open = new UILabel(OPEN_ICON);
open.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Open"));
delete = new UILabel(DELETE_ICON);
delete.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Delete"));
initManagerListener();
initOpenListener();
initDeleteListener();
List<JComponent> components = new ArrayList<>();
components.add(manager);
components.add(open);
components.add(delete);
return new VcsOperatorPane(components);
}
private void initDeleteListener() {
delete.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JTable table = tableContentPane.getEditTable();
int row = table.getEditingRow();
Object o = table.getValueAt(row, table.getEditingColumn());
if (o instanceof VcsTableEntity) {
VcsEntity entity = ((VcsTableEntity) o).getEntity();
String fileName = entity.getFilename();
int selVal = FineJOptionPane.showConfirmDialog(
VcsCenterPane.this,
Toolkit.i18nText("Fine-Design_Vcs_Center_Delete", fileName),
Toolkit.i18nText("Fine-Design_Basic_Confirm"),
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (selVal == JOptionPane.YES_OPTION) {
VcsOperatorWorker.createDeleteWorker().doDelete(entity, new VcsTableOperatorListener() {
@Override
public void updateUI() {
removeTarget((VcsTableEntity) o);
model.fireTableRowsDeleted(row, row);
model.removeRow(row);
model.fireTableDataChanged();
}
});
}
}
}
});
}
@Override
protected boolean needIcon4Head(int col) {
return col != 0 && col != OPERATOR_COL;
}
private void initOpenListener() {
open.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JTable table = tableContentPane.getEditTable();
Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn());
if (o instanceof VcsTableEntity) {
VcsEntity entity = ((VcsTableEntity) o).getEntity();
saveSettingAndCloseDialog();
showTemplate(entity.getFilename(), new FileNode(getTemplateTruePath(entity.getFilename()), false));
}
}
});
}
private void showTemplate(String filename, FileNode node) {
new SwingWorker<Boolean, Void>() {
@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
public void mouseClicked(MouseEvent e) {
JTable table = tableContentPane.getEditTable();
Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn());
if (o instanceof VcsTableEntity) {
VcsEntity entity = ((VcsTableEntity) o).getEntity();
String path = getTemplateTruePath(entity.getFilename());
VcsNewPane pane = new VcsNewPane(path) {
@Override
protected String title4PopupWindow() {
return entity.getFilename()+Toolkit.i18nText("Fine-Design_Vcs_Version_Tips");
}
};
pane.addVcsListener(new VcsTableOperatorListener() {
@Override
public void doOperator(List<VcsTableEntity> entityList) {
if (entities.size() == 0) {
model.getList().remove(o);
model.fireTableDataChanged();
}
}
});
VcsCloseTemplateHelper.checkTemplateSavedAndShowVcsNewPane(path, VcsCloseTemplateHelper.isCurrentEditing(path), getDialog(), pane);
}
}
});
}
@Override
protected List<VcsTableEntity> getTableList() {
List<VcsEntity> entities = WorkContext.getCurrent().get(VcsOperator.class).getEveryVersion();
List<VcsTableEntity> tableEntities = new ArrayList<>();
for (VcsEntity entity : entities) {
tableEntities.add(new VcsTableEntity(entity));
}
updateTableList(tableEntities);
return tableEntities;
}
@Override
protected void initDialogListener(BasicDialog dialog) {
dialog.addDialogActionListener(new DialogActionAdapter() {
@Override
public void doOk() {
BasicDialog parent = getParentDialog();
parent.doOK();
parent.dispose();
}
});
}
@Override
protected String title4PopupWindow() {
return TITLE;
}
@Override
protected String getDeleteTip(int size) {
return Toolkit.i18nText("Fine-Design_Vcs_Delete_Select_All_Version");
}
@Override
protected boolean isNeedTopPane() {
return true;
}
@Override
protected boolean isNeedRestore() {
return false;
}
@Override
protected boolean isNeedSearch() {
return true;
}
@Override
protected boolean isNeedDeleteAllVersion() {
return true;
}
}

520
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovePanel.java

@ -0,0 +1,520 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.base.svg.IconUtils;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ibutton.UIRadioButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.iprogressbar.ModernUIProgressBarUI;
import com.fr.design.gui.ispinner.UISpinner;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.vcs.VcsExceptionUtils;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.design.utils.BrowseUtils;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.ThemeUtils;
import com.fr.design.widget.FRWidgetFactory;
import com.fr.general.FRFont;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.workspace.server.vcs.v2.move.VcsMoveService;
import com.fr.workspace.server.vcs.v2.move.VcsMoveStrategy;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
import static javax.swing.JOptionPane.YES_OPTION;
/**
* 迁移面板
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/6/13
*/
public class VcsMovePanel extends BasicPane {
private static final FRFont FONT = DesignUtils
.getDefaultGUIFont()
.applySize(14)
.applyStyle(FRFont.BOLD);
private static final Color BACK_GROUND_COLOR = new Color(202,232,255);
//提示字体的颜色,直接模仿其他面板的写法
private static final Color TIP_COLOR = new Color(51, 51, 52, (int)Math.round(0.5 * 255));
private static final Color LABEL_COLOR = new Color(34,149,233);
private static final int MIN_VALUE = 1;
private static final int MAX_VALUE = 999;
private static final int STEP = 1;
private static final int DEFAULT_VALUE = 5;
private static final String HELP_KEY = "Fine-Design_Vcs_Move_Help_Link";
private static final String HELP_KEY_DEFAULT = "Fine-Design_Vcs_Move_Help_Link_Default";
private static final String HELP_URL = LocaleLinkProvider.getInstance().getLink(HELP_KEY, HELP_KEY_DEFAULT);
public static final String SETTING = "SETTING";
public static final String PROCESS = "PROCESS";
public static final String SUCCESS = "SUCCESS";
public static final String FAILED = "FAILED";
public static boolean moving = false;
private BasicDialog parentDialog;
private UILabel vcsUpdateExistLabel = new UILabel();
private UILabel vcsUpdateFireLabel = new UILabel();
private UIButton centerButton;
private BasicPane choosePane;
private CardLayout parentCard;
private JPanel parentPane;
private static final JProgressBar PROGRESS_BAR = new JProgressBar();
private JPanel progressPanel;
private UILabel tipLabel;
private UIButton successButton;
private UILabel iconLabel;
private UILabel successLabel;
private UILabel successTipLabel;
private UIButton failedButton;
private UILabel failedIconLabel;
private UILabel failedLabel;
private UILabel failedTipLabel;
//保留全部
private UIRadioButton moveAllButton;
//默认选项,保留部分
private UIRadioButton moveDefaultButton;
//全部放弃
private UIRadioButton moveNothingButton;
private UIPositiveIntSpinner spinner;
private MoveCallBack callBack;
private JPanel updatePane;
private boolean visible = false;
private UILabel seeLabel;
private UILabel helpLabel;
public VcsMovePanel(CardLayout cardLayout, JPanel parentPane, MoveCallBack callBack, BasicDialog parentDialog) {
this.parentCard = cardLayout;
this.parentPane = parentPane;
this.callBack = callBack;
this.setLayout(new BorderLayout());
this.parentDialog = parentDialog;
updatePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane();
updatePane.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 0));
//初始化顶部的面板
initVcsLabel(updatePane);
//initVcsChoosePane
initVcsChoosePane();
//初始化listener
initListener();
this.add(updatePane);
checkVisible();
//如果已经在迁移
if (VcsMoveService.getInstance().isMoving()) {
initProcessPane();
VcsMovePanel.this.getParentCard().show(getParentPane(), PROCESS);
}
}
private void checkVisible() {
new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
return VcsHelper.getInstance().checkMoveFunctionSupport();
}
@Override
protected void done() {
try {
boolean useMove = get();
VcsMovePanel.this.setVisible(useMove);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}.execute();
}
private void initProcessPane() {
JPanel processPane = new JPanel();
JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
PROGRESS_BAR.setStringPainted(true);
PROGRESS_BAR.setUI(new ModernUIProgressBarUI());
PROGRESS_BAR.setBorderPainted(false);
PROGRESS_BAR.setOpaque(false);
PROGRESS_BAR.setBorder(null);
PROGRESS_BAR.setSize(BasicDialog.MEDIUM);
body.add(PROGRESS_BAR);
body.add(new UILabel(StringUtils.BLANK));
tipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_While_Moving"));
tipLabel.setAlignmentX(CENTER_ALIGNMENT);
body.add(tipLabel);
processPane.add(body);
processPane.setLayout(FRGUIPaneFactory.createCenterLayout(body, 0.5f, 0.5f));
parentPane.add(processPane, PROCESS);
}
private void initVcsChoosePane() {
choosePane = new BasicPane() {
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Vcs_Deal_With_Entry");
}
};
VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP);
layout.setAlignLeft(true);
choosePane.setLayout(layout);
//初始化上方的文字板块
initTopDesc();
//初始化中间区域的单选框
initRadioButton();
//初始化下方的Tip描述
initTipDesc();
}
private void initTopDesc() {
UILabel label = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_How_To_Deal_With_Entry"));
choosePane.add(label);
}
private void initTipDesc() {
UILabel descLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Desc"));
UILabel firstLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tips_First"));
UILabel secondLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tips_Second"));
descLabel.setForeground(TIP_COLOR);
firstLabel.setForeground(TIP_COLOR);
secondLabel.setForeground(TIP_COLOR);
choosePane.add(descLabel);
choosePane.add(firstLabel);
choosePane.add(secondLabel);
}
private void initRadioButton() {
//保留全部
moveAllButton = new UIRadioButton(Toolkit.i18nText("Fine-Design_Vcs_Move_All"));
//默认选项,保留部分
moveDefaultButton = new UIRadioButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Default"));
//全部放弃
moveNothingButton = new UIRadioButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Nothing"));
// 将按钮"保留部分"设置为选中状态
moveDefaultButton.setSelected(true);
// 创建一个按钮组,添加三个按钮
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(moveAllButton);
buttonGroup.add(moveDefaultButton);
buttonGroup.add(moveNothingButton);
JPanel moveDefaultPanel = new JPanel();
JPanel moveAllPane = new JPanel();
JPanel moveNothingPane = new JPanel();
moveAllPane.add(moveAllButton);
moveDefaultPanel.add(moveDefaultButton);
moveDefaultPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Default_Text_Left")));
spinner = new UIPositiveIntSpinner(MIN_VALUE, MAX_VALUE, STEP, DEFAULT_VALUE);
moveDefaultPanel.add(spinner);
moveDefaultPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Default_Text_Right")));
moveNothingPane.add(moveNothingButton);
choosePane.add(moveAllPane);
choosePane.add(moveDefaultPanel);
choosePane.add(moveNothingPane);
}
private void initVcsLabel(JPanel parent) {
parent.removeAll();
if (!VcsHelper.getInstance().isLegacyMode()) {
parent.setBackground(ThemeUtils.BACK_COLOR);
centerButton = new UIButton(Toolkit.i18nText("Fine-Design_Vcs_Center"));
parent.add(centerButton);
initVcsCenterListener();
} else {
parent.setBackground(BACK_GROUND_COLOR);
vcsUpdateExistLabel = new UILabel(IconUtils.readIcon("/com/fr/design/vcs/vcs_move_icon.svg"));
vcsUpdateExistLabel.setText(Toolkit.i18nText("Fine-Design_Vcs_Can_Update"));
vcsUpdateFireLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Update"));
vcsUpdateFireLabel.setForeground(LABEL_COLOR);
vcsUpdateFireLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
parent.add(vcsUpdateExistLabel);
parent.add(vcsUpdateFireLabel);
}
}
private void initVcsCenterListener() {
centerButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
VcsCenterPane vcsCenterPane = new VcsCenterPane();
vcsCenterPane.showDialog(parentDialog);
}
});
}
private void initListener() {
vcsUpdateFireLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
BasicDialog dlg = choosePane.showMediumWindow(SwingUtilities.getWindowAncestor(VcsMovePanel.this), new DialogActionAdapter() {
@Override
public void doOk() {
createConfirmPane();
}
});
dlg.setVisible(true);
}
});
}
private void createConfirmPane() {
VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP);
layout.setAlignLeft(true);
JPanel panel = new JPanel();
panel.setLayout(layout);
UILabel titleLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tip_Title"));
UILabel firstLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tip_First"));
UILabel secondLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tip_Second"));
titleLabel.setForeground(TIP_COLOR);
firstLabel.setForeground(TIP_COLOR);
secondLabel.setForeground(TIP_COLOR);
panel.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Right_Now")));
panel.add(titleLabel);
panel.add(firstLabel);
panel.add(secondLabel);
int value = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(DesignerContext.getDesignerFrame()), panel, Toolkit.i18nText("Fine-Design_Vcs_Move_Title"), JOptionPane.YES_NO_OPTION);
processMove(value);
}
private void processMove(int value) {
if (value == YES_OPTION) {
//进度条面板
initProcessPane();
VcsMovePanel.this.getParentCard().next(getParentPane());
VcsMoveStrategy strategy;
if (moveDefaultButton.isSelected()) {
strategy = VcsMoveStrategy.createStrategy((int) spinner.getValue());
} else if (moveNothingButton.isSelected()) {
strategy = VcsMoveStrategy.createStrategy(0);
} else {
strategy = VcsMoveStrategy.createStrategy(Integer.MAX_VALUE);
}
new MoveWorker(strategy).execute();
}
}
private void initSuccessPane() {
JPanel successPane = new JPanel();
JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
successButton = new UIButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Success_Go"));
initSuccessButtonListener();
iconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/vcs/move_success.svg"));
successLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Success"));
successLabel.setFont(FONT);
successTipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Success_Tip"));
initStatusPane(successTipLabel, iconLabel, successLabel, successButton, body, SUCCESS, successPane);
}
private void initSuccessButtonListener() {
successButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doAfterMove();
}
});
}
private void initFailedButtonListener() {
failedButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doAfterMove();
}
});
}
private void doAfterMove() {
visible = !VcsHelper.getInstance().isLegacyMode();
initVcsLabel(updatePane);
updatePane.setVisible(visible);
callBack.doCallBack(visible);
parentCard.show(parentPane, SETTING);
}
public BasicDialog getParentDialog() {
return parentDialog;
}
public void setParentDialog(BasicDialog parentDialog) {
this.parentDialog = parentDialog;
}
@Override
protected String title4PopupWindow() {
return StringUtils.EMPTY;
}
public CardLayout getParentCard() {
return parentCard;
}
public JPanel getParentPane() {
return parentPane;
}
private void initFailedPane(String detail) {
JPanel failedPane = new JPanel();
JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
failedButton = new UIButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Failed_Go"));
initFailedButtonListener();
failedIconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/vcs/move_failed.svg"));
failedLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Failed"));
failedLabel.setFont(FONT);
failedTipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Failed_Tip", detail));
initStatusPane(failedTipLabel, failedIconLabel, failedLabel, failedButton, body, FAILED, failedPane);
}
private void initStatusPane(UILabel tipLabel, UILabel iconLabel, UILabel label, UIButton button, JPanel body, String tag,JPanel statusPane) {
tipLabel.setForeground(TIP_COLOR);
body.add(iconLabel);
body.add(new UILabel(StringUtils.BLANK));
body.add(label);
body.add(new UILabel(StringUtils.BLANK));
body.add(tipLabel);
body.add(new UILabel(StringUtils.BLANK));
JPanel panel = createHelpPane();
body.add(panel);
body.add(new UILabel(StringUtils.BLANK));
body.add(button);
statusPane.add(body);
statusPane.setLayout(FRGUIPaneFactory.createCenterLayout(body, 0.5f, 0.5f));
parentPane.add(statusPane, tag);
iconLabel.setAlignmentX(CENTER_ALIGNMENT);
label.setAlignmentX(CENTER_ALIGNMENT);
button.setAlignmentX(CENTER_ALIGNMENT);
tipLabel.setAlignmentX(CENTER_ALIGNMENT);
}
private JPanel createHelpPane() {
JPanel panel = new JPanel();
seeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_See"));
seeLabel.setForeground(TIP_COLOR);
helpLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Help"));
helpLabel.setForeground(LABEL_COLOR);
helpLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
helpLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
BrowseUtils.browser(HELP_URL);
}
});
panel.add(seeLabel);
panel.add(helpLabel);
return panel;
}
private class MoveWorker extends SwingWorker<Boolean, Integer> {
private VcsMoveStrategy strategy;
private String detail = StringUtils.EMPTY;
public MoveWorker(VcsMoveStrategy strategy) {
this.strategy = strategy;
}
@Override
protected Boolean doInBackground() throws Exception {
try {
//开始迁移
VcsMoveService.getInstance().startMove(new VcsMoveService.BaseMoveServiceWhileMoving() {
@Override
public void publishProgress() {
int num = VcsMoveService.getInstance().getCurrentMove();
publish(num);
}
@Override
public void prepare4Move() {
PROGRESS_BAR.setMaximum(VcsMoveService.getInstance().getTotal());
}
}, strategy);
} catch (Exception e) {
VcsMoveService.getInstance().stopMoving();
detail = VcsExceptionUtils.createDetailByException(e);
return false;
}
return true;
}
@Override
protected void process(List<Integer> chunks) {
PROGRESS_BAR.setValue(chunks.get(chunks.size() - 1));
}
@Override
protected void done() {
VcsMoveService.getInstance().stopMoving();
try {
if (get()) {
initSuccessPane();
VcsMovePanel.this.getParentCard().show(getParentPane(), SUCCESS);
VcsHelper.getInstance().updateLegacyMode();
DesignerFrameFileDealerPane.getInstance().refreshDockingView();
} else {
initFailedPane(detail);
VcsMovePanel.this.getParentCard().show(getParentPane(), FAILED);
FineLoggerFactory.getLogger().error("[VcsV2] Vcs move failed!");
}
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}
/**
* 迁移回调事件
*
*/
public static class MoveCallBack {
/**
* 处理回调
*/
public void doCallBack(boolean visible){}
}
}

54
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovingExitOption.java

@ -0,0 +1,54 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.workspace.server.vcs.v2.move.VcsMoveService;
import javax.swing.JOptionPane;
/**
* 版本管理迁移检查
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/18
*/
public class VcsMovingExitOption {
/**
* 关闭前的检查
*
* @return
*/
public static boolean ShowDialogAndConfirmExit() {
return showDialogAndChoose(Toolkit.i18nText("Fine-Design_Vcs_Close_Tips"));
}
/**
* 切换环境前的检查
*
* @return
*/
public static boolean ShowDialogAndConfirmSwitch() {
return showDialogAndChoose(Toolkit.i18nText("Fine-Design_Vcs_Switch_Tips"));
}
private static boolean showDialogAndChoose(String msg) {
if (VcsMoveService.getInstance().isMoving()) {
int result = FineJOptionPane.showConfirmDialog(
DesignerContext.getDesignerFrame(),
msg,
Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"),
FineJOptionPane.YES_NO_OPTION
);
return result == JOptionPane.YES_OPTION;
}
return true;
}
}

406
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java

@ -0,0 +1,406 @@
package com.fr.design.mainframe.vcs.ui;
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;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.vcs.TableValueOperator;
import com.fr.design.mainframe.vcs.VcsOperatorWorker;
import com.fr.design.mainframe.vcs.VcsTableEntity;
import com.fr.design.mainframe.vcs.VcsTableOperatorListener;
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;
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.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* 版本管理交互优化新面板
* <li>采用表格的形式展现</li>
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/11
*/
public class VcsNewPane extends RecyclePane {
private String filePath = StringUtils.EMPTY;
protected static int OPERATOR_COL = 5;
protected static int EDIT_COL = 4;
private static final String PATH = "path";
private static final int DOUBLE_CLICK_COUNT = 2;
protected VcsOperatorPane operatorPane;
private static final Icon PREVIEW_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_preview");
private static final Icon DELETE_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_delete");
private static final Icon RESTORE_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_restore");
private UILabel restore;
private UILabel delete;
private UILabel preview;
private static final String TITLE = Toolkit.i18nText("Fine-Design_Vcs_Title");
private static final String[] COLUMN_NAMES = new String[]{
StringUtils.EMPTY,
Toolkit.i18nText("Fine-Design_Vcs_Version"),
Toolkit.i18nText("Fine-Design_Vcs_Time"),
Toolkit.i18nText("Fine-Design_Vcs_User"),
Toolkit.i18nText("Fine-Design_Vcs_Annotation"),
Toolkit.i18nText("Fine-Design_Vcs_Operator")
};
private static final Class[] CLASSES = new Class[]{
Boolean.class,
UILabel.class,
UILabel.class,
UILabel.class,
UILabel.class,
VcsOperatorPane.class
};
public VcsNewPane(String filePath) {
super(TITLE, (o, columnIndex) -> {
switch (columnIndex) {
case 0:
return o.isSelect();
case 1:
return o.getVersion();
case 2:
return o.getTime();
case 3:
return o.getUserName();
case 4:
return o.getCommitMsg();
default:
return o;
}
}, false);
this.filePath = filePath;
initModel(COLUMN_NAMES, CLASSES, OPERATOR_COL);
}
private void initModel(String[] columns, Class[] classes, int operatorCol) {
this.model = new DefaultModel(columns, classes) {
@Override
public boolean isCellEditable(int row, int col) {
return col == 0 || col == operatorCol;
}
};
this.operatorPane = createOperatorPane();
this.model.setDefaultEditor(VcsOperatorPane.class, new VcsCellEditor(createOperatorPane()));
this.model.setDefaultRenderer(VcsOperatorPane.class, new VcsCellRender(createOperatorPane()));
this.model.setDefaultRenderer(UILabel.class, new ToolTipTableCellRenderer());
}
public VcsNewPane(String title, TableValueOperator<VcsTableEntity> operators, boolean needBorder, String[] columns, Class[] classes, int operatorCol) {
super(title, operators, needBorder);
initModel(columns, classes, operatorCol);
}
/**
* 创建操作面板
*
* @return 操作面板
*/
public VcsOperatorPane createOperatorPane() {
restore = new UILabel(RESTORE_ICON);
restore.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Restore"));
delete = new UILabel(DELETE_ICON);
delete.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Delete"));
preview = new UILabel(PREVIEW_ICON);
preview.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Preview"));
initPreviewListener();
initDeleteListener();
initRestoreListener();
List<JComponent> list = new ArrayList<>();
list.add(restore);
list.add(delete);
list.add(preview);
return new VcsOperatorPane(list);
}
private void initRestoreListener() {
restore.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JTable table = tableContentPane.getEditTable();
Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn());
if (o instanceof VcsTableEntity) {
VcsEntity entity = ((VcsTableEntity) o).getEntity();
int selVal = FineJOptionPane.showConfirmDialog(
VcsNewPane.this,
Toolkit.i18nText("Fine-Design_Vcs_Restore_This_Version_Tips"),
Toolkit.i18nText("Fine-Design_Basic_Confirm"),
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (selVal == JOptionPane.YES_OPTION) {
restoreEntity(entity);
VcsNewPane.this.saveSettingAndCloseDialog();
}
}
}
});
}
private void restoreEntity(VcsEntity entity) {
new SwingWorker<VcsTaskResult, Void>() {
@Override
protected VcsTaskResult doInBackground() throws Exception {
String path = VcsHelper.getInstance().getFilePath(entity);
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到指定版本
WorkContext.getCurrent().get(VcsOperator.class).rollbackTo(entity);
//最里面的文件系统的write会吞异常,这边就一直默认成功吧,日志里会体现失败的情况
return new VcsTaskResult(true);
}
@Override
protected void done() {
try {
VcsTaskResult result = get();
if (result.isSuccess()) {
//step3.如果原来原模板已经打开则关闭原模板,打开rollback后的新模板
List<JTemplate<?, ?>> templateList = HistoryTemplateListCache.getInstance().getHistoryList();
for (JTemplate<?, ?> template : templateList) {
if (StringUtils.equals(filePath, template.getPath())) {
MultiTemplateTabPane.getInstance().setIsCloseCurrent(HistoryTemplateListCache.getInstance().isCurrentEditingFile(filePath));
MultiTemplateTabPane.getInstance().closeFormat(template);
MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(template);
break;
}
}
DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(filePath, false)));
} else {
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);
}
}
}.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() {
@Override
public void mouseClicked(MouseEvent e) {
JTable table = tableContentPane.getEditTable();
int row = table.getEditingRow();
Object o = table.getValueAt(row, table.getEditingColumn());
if (o instanceof VcsTableEntity) {
VcsEntity entity = ((VcsTableEntity) o).getEntity();
int selVal = FineJOptionPane.showConfirmDialog(
VcsNewPane.this,
Toolkit.i18nText("Fine-Design_Vcs_Delete_This_Version_Tips"),
Toolkit.i18nText("Fine-Design_Basic_Confirm"),
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (selVal == JOptionPane.YES_OPTION) {
VcsOperatorWorker.createDeleteWorker().deleteTargetVersion(entity, new VcsTableOperatorListener() {
@Override
public void updateUI() {
model.fireTableRowsDeleted(row, row);
model.removeRow(row);
model.fireTableDataChanged();
}
});
fireVcsListener(model.getList());
}
}
}
});
}
private void initPreviewListener() {
preview.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JTable table = tableContentPane.getEditTable();
Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn());
if (o instanceof VcsTableEntity) {
VcsEntity entity = ((VcsTableEntity) o).getEntity();
previewEntity(entity);
}
}
});
}
private void previewEntity(VcsEntity entity) {
new SwingWorker<String, Void>() {
@Override
protected String doInBackground() throws Exception {
//step1.将指定版本的历史文件读取出来,加上前缀放到cache中
VcsOperator vcsOperator = WorkContext.getCurrent().get(VcsOperator.class);
String fileOfVersion = vcsOperator.getFileOfFileVersion(
entity.getFilename(),
entity.getVersion(),
Toolkit.i18nText("Fine-Design_Vcs_Prefix", entity.getVersion()));
return fileOfVersion;
}
@Override
protected void done() {
try {
//step2.再打开cache中的模板
DesignerContext.getDesignerFrame().openTemplate(new VcsCacheFileNodeFile(new FileNode(get(), false)));
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}.execute();
}
@Override
protected boolean isNeedDeleteAllVersion() {
return false;
}
@Override
protected List<VcsTableEntity> getTableList() {
List<VcsEntity> entityList = WorkContext.getCurrent().get(VcsOperator.class).getVersions(VcsFileUtils.dealWithFilePath(filePath));
List<VcsTableEntity> tableEntities = new ArrayList<>();
for (VcsEntity entity : entityList) {
tableEntities.add(new VcsTableEntity(entity));
}
return tableEntities;
}
@Override
protected String title4PopupWindow() {
return TITLE;
}
@Override
protected String getDeleteTip(int size) {
return Toolkit.i18nText("Fine-Design_Vcs_Delete_Versions_Tips", size);
}
@Override
protected boolean isNeedRestore() {
return false;
}
@Override
protected boolean isNeedSearch() {
return false;
}
@Override
protected void initExtraListener4Table(JTable table) {
table.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
Point point = e.getPoint();
int row = table.rowAtPoint(point);
int col = table.columnAtPoint(point);
if (col != 0) {
table.editCellAt(row, col);
}
}
});
initEditListener(table);
}
private void initEditListener(JTable table) {
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == DOUBLE_CLICK_COUNT) {
Point point = e.getPoint();
int row = table.rowAtPoint(point);
int col = table.columnAtPoint(point);
if (col == EDIT_COL) {
Object o = table.getValueAt(row, OPERATOR_COL);
if (o instanceof VcsTableEntity) {
showDialog(((VcsTableEntity) o).getEntity());
}
}
}
}
});
}
private void showDialog(VcsEntity entity) {
EditFileVersionDialog dialog = new EditFileVersionDialog(entity) {
@Override
public void doOK() {
entity.setCommitMsg(getMsgTestArea().getText());
VcsOperatorWorker.createUpdateWorker().updateEntityAnnotation(entity, new VcsTableOperatorListener() {
@Override
public void updateUI() {
setVisible(false);
model.fireTableDataChanged();
}
});
}
};
dialog.setVisible(true);
}
@Override
protected boolean needIcon4Head(int col) {
return col != 0 && col != OPERATOR_COL;
}
}

40
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsOperatorPane.java

@ -0,0 +1,40 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import java.awt.*;
import java.util.List;
/**
* 操作面板用于置放常用的操作label
* <p>例如 删除还原预览打开模板等</p>
* <li>负责表格渲染 操作按钮置蓝+设定cursor</li>
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/13
*/
public class VcsOperatorPane extends JPanel {
public VcsOperatorPane(List<JComponent> iconJComponentMap) {
init(iconJComponentMap);
}
private void init(List<JComponent> iconJComponentMap) {
this.setLayout(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout());
for (JComponent value : iconJComponentMap) {
value.setCursor(new Cursor(Cursor.HAND_CURSOR));
this.add(value);
}
}
}

81
designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsProgressDialog.java

@ -0,0 +1,81 @@
package com.fr.design.mainframe.vcs.ui;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.iprogressbar.ModernUIProgressBarUI;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.DesignerContext;
import com.fr.stable.StringUtils;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import static java.awt.Component.CENTER_ALIGNMENT;
/**
* Vcs操作进度条面板
*
* @author Destiny.Lin
* @since 11.0
* Created on 2023/7/18
*/
public class VcsProgressDialog{
private JProgressBar progressBar = new JProgressBar();
private UILabel tipLabel;
private BasicPane processPane;
private BasicDialog dialog;
public VcsProgressDialog(String title, String dealingStr) {
processPane = new BasicPane() {
@Override
protected String title4PopupWindow() {
return title;
}
};
JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
progressBar.setStringPainted(true);
progressBar.setUI(new ModernUIProgressBarUI());
progressBar.setBorderPainted(false);
progressBar.setOpaque(false);
progressBar.setBorder(null);
progressBar.setSize(BasicDialog.MEDIUM);
progressBar.setValue(0);
body.add(progressBar);
body.add(new UILabel(StringUtils.BLANK));
tipLabel = new UILabel(dealingStr);
tipLabel.setAlignmentX(CENTER_ALIGNMENT);
body.add(tipLabel);
processPane.add(body);
processPane.setLayout(FRGUIPaneFactory.createCenterLayout(body, 0.5f, 0.5f));
}
/**
* 展示面板
*
*/
public void showDialog() {
dialog = processPane.showSmallWindow(DesignerContext.getDesignerFrame(), false);
dialog.setVisible(true);
}
/**
* 关闭面板
*
*/
public void closeDialog() {
dialog.setVisible(false);
}
public JProgressBar getProgressBar() {
return progressBar;
}
public void setProgressBar(JProgressBar progressBar) {
this.progressBar = progressBar;
}
}

13
designer-base/src/main/java/com/fr/design/mainframe/widget/editors/DataBindingEditor.java

@ -29,8 +29,8 @@ public class DataBindingEditor extends Editor<DataBinding> {
private final static int HORI_GAP = 1;
private final static int VER_GAP = 7;
private TableDataComboBox tableDataComboBox;
private LazyComboBox columnNameComboBox;
protected TableDataComboBox tableDataComboBox;
protected LazyComboBox columnNameComboBox;
private ItemListener tableDataComboBoxListener = new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
boolean isInit = columnNameComboBox.getSelectedIndex() == -1;
@ -87,9 +87,16 @@ public class DataBindingEditor extends Editor<DataBinding> {
}
});
columnNameComboBox.setEditable(true);
addComboBoxesAndSetPosition();
columnNameComboBox.addItemListener(columnNameComboboxListener);
}
/**
* 根据需求不同调整下拉框的位置
*/
protected void addComboBoxesAndSetPosition() {
this.add(tableDataComboBox, BorderLayout.NORTH);
this.add(columnNameComboBox, BorderLayout.CENTER);
columnNameComboBox.addItemListener(columnNameComboboxListener);
}
protected TableDataSource getTableDataSource() {

20
designer-base/src/main/java/com/fr/design/mainframe/widget/editors/WidgetValueEditor.java

@ -5,6 +5,7 @@
package com.fr.design.mainframe.widget.editors;
import java.awt.Component;
import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@ -30,6 +31,7 @@ public class WidgetValueEditor extends AbstractPropertyEditor {
/**
* 根据类型创建
* 服务器 - 控件管理
* @param type 类型
* @param onlyServer 是否是服务器
* @return 编辑器
@ -41,7 +43,7 @@ public class WidgetValueEditor extends AbstractPropertyEditor {
case DataControl.TYPE_FORMULA:
return new FormulaEditor(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Parameter_Formula"));
case DataControl.TYPE_DATABINDING:
return onlyServer ? new ServerDataBindingEditor() : new DataBindingEditor();
return onlyServer ? new WidgetValueServerDataBindingEditor() : new WidgetValueDataBindingEditor();
case DataControl.TYPE_STRING:
return new TextEditor();
case DataControl.TYPE_BOOLEAN:
@ -70,6 +72,22 @@ public class WidgetValueEditor extends AbstractPropertyEditor {
}
return editor;
}
private static class WidgetValueDataBindingEditor extends DataBindingEditor {
@Override
protected void addComboBoxesAndSetPosition() {
this.add(tableDataComboBox, BorderLayout.CENTER);
this.add(columnNameComboBox, BorderLayout.EAST);
}
}
private static class WidgetValueServerDataBindingEditor extends ServerDataBindingEditor {
@Override
protected void addComboBoxesAndSetPosition() {
this.add(tableDataComboBox, BorderLayout.CENTER);
this.add(columnNameComboBox, BorderLayout.EAST);
}
}
public WidgetValueEditor(Object o) {
this(o, false);

4
designer-base/src/main/java/com/fr/design/style/color/ColorSelectDialog.java

@ -79,6 +79,7 @@ public class ColorSelectDialog extends MiddleChartDialog{
this.seletePane = seletePane;
initComponent();
this.pane.populate(initialColor);
this.setLocationRelativeTo(null);
}
private void initComponent() {
@ -87,7 +88,8 @@ public class ColorSelectDialog extends MiddleChartDialog{
this.setBasicDialogSize(545,500);
this.setResizable(false);
this.applyClosingAction();
this.applyEscapeAction();
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));

4
designer-base/src/main/resources/com/fr/design/images/buttonicon/new_other_normal.svg

@ -0,0 +1,4 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 15.6727V0.672668H11.2731L14.5 4.36054V15.6727H0.5Z" stroke="#333334"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 5.17267H6V7.17267H4V5.17267ZM3 4.17267H4H6H7V5.17267V7.17267V8.17267H6H4H3V7.17267V5.17267V4.17267ZM4 10.1727H6V12.1727H4V10.1727ZM3 9.17267H4H6H7V10.1727V12.1727V13.1727H6H4H3V12.1727V10.1727V9.17267ZM9 6.17267C9 6.72495 9.44772 7.17267 10 7.17267C10.5523 7.17267 11 6.72495 11 6.17267C11 5.62038 10.5523 5.17267 10 5.17267C9.44772 5.17267 9 5.62038 9 6.17267ZM10 4.17267C8.89543 4.17267 8 5.0681 8 6.17267C8 7.27724 8.89543 8.17267 10 8.17267C11.1046 8.17267 12 7.27724 12 6.17267C12 5.0681 11.1046 4.17267 10 4.17267ZM9 12.1727V10.1727H11V12.1727H9ZM8 9.17267H9H11H12V10.1727V12.1727V13.1727H11H9H8V12.1727V10.1727V9.17267Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 885 B

5
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_center_manager_normal.svg

@ -0,0 +1,5 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#231;&#137;&#136;&#230;&#156;&#172;&#231;&#174;&#161;&#231;&#144;&#134;">
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M2 2.5H14V14.5H2V2.5ZM1 15.5V1.5H15V15.5H1ZM5.75 4.5H4.25L7.25 10.5H8.75L11.75 4.5H10.25L8 9L5.75 4.5ZM12 11.5V12.5H4V11.5H12Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 400 B

5
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_center_open_normal.svg

@ -0,0 +1,5 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="&#230;&#137;&#147;&#229;&#188;&#128;&#230;&#168;&#161;&#230;&#157;&#191;">
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M8.55349 5.73077L8.25543 5.39831L6.55349 3.5H2V11.2333L2.875 7.5H9.90625H13V5.73077H9H8.55349ZM14 7.5H14.9729H16L15.7656 8.5L14.125 15.5H2.0271H1V14.5V3.5V2.5H2H7L9 4.73077H13H14V5.73077V7.5ZM2.26147 14.5L3.66772 8.5H9.90625H14.7385L13.3323 14.5H2.26147Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 523 B

7
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_operator_delete_normal.svg

@ -0,0 +1,7 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#229;&#136;&#160;&#233;&#153;&#164;">
<g id="icon/delete">
<path id="Combined-Shape" d="M11 1.5V3.5H15V4.5H13V15.5H3V4.5H1V3.5H5V1.5H11ZM12 4.5H4V14.5H12V4.5ZM7 6.5V12.5H6V6.5H7ZM10 6.5V12.5H9V6.5H10ZM10 2.5H6V3.5H10V2.5Z" fill="#333334"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 366 B

5
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_operator_preview_normal.svg

@ -0,0 +1,5 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#233;&#162;&#132;&#232;&#167;&#136;">
<path id="Combined Shape" fill-rule="evenodd" clip-rule="evenodd" d="M3 14.5H7V15.5H2V1.5H9H10L14 5.5V8.5H13V6.5H10H9V5.5V2.5H3V14.5ZM10 2.914V5.5H12.586L10 2.914ZM9.5 7.5C11.4329 7.5 13 9.06712 13 11C13 11.6067 12.8456 12.1774 12.5739 12.6749C12.6206 12.7078 12.6651 12.7452 12.7069 12.787L13.7129 13.793C14.1039 14.184 14.1039 14.816 13.7129 15.207C13.5179 15.402 13.2619 15.5 13.0059 15.5C12.7499 15.5 12.4939 15.402 12.2989 15.207L11.2929 14.201C11.2516 14.1599 11.2147 14.116 11.1821 14.07C10.6829 14.3441 10.1097 14.5 9.5 14.5C7.56712 14.5 6 12.9329 6 11C6 9.06712 7.56712 7.5 9.5 7.5ZM7 11.0006C7 9.62232 8.12167 8.50065 9.5 8.50065C10.8783 8.50065 12 9.62232 12 11.0006C12 12.379 10.8783 13.5006 9.5 13.5006C8.12167 13.5006 7 12.379 7 11.0006Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 929 B

5
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_operator_restore_normal.svg

@ -0,0 +1,5 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#229;&#136;&#183;&#230;&#150;&#176;">
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M13.924 2.15774C13.924 1.82637 13.6553 1.55774 13.324 1.55774C12.9926 1.55774 12.724 1.82637 12.724 2.15774V4.59914C11.6284 3.54744 10.1397 2.90004 8.50002 2.90004C5.13109 2.90004 2.40002 5.6311 2.40002 9.00004C2.40002 12.369 5.13109 15.1 8.50002 15.1C11.1941 15.1 13.4787 13.354 14.2871 10.9335C14.3921 10.6191 14.2223 10.2793 13.908 10.1743C13.5937 10.0693 13.2538 10.239 13.1489 10.5533C12.4991 12.4989 10.6624 13.9 8.50002 13.9C5.79383 13.9 3.60002 11.7062 3.60002 9.00004C3.60002 6.29384 5.79383 4.10004 8.50002 4.10004C9.8643 4.10004 11.0983 4.65709 11.9873 5.55774H9.32397C8.9926 5.55774 8.72397 5.82637 8.72397 6.15774C8.72397 6.48911 8.9926 6.75774 9.32397 6.75774H13.324C13.6553 6.75774 13.924 6.48911 13.924 6.15774V2.15774Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 973 B

7
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_delete_disabled.svg

@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#229;&#136;&#160;&#233;&#153;&#164;" opacity="0.3">
<g id="icon/delete">
<path id="Combined-Shape" d="M11 1V3H15V4H13V15H3V4H1V3H5V1H11ZM12 4H4V14H12V4ZM7 6V12H6V6H7ZM10 6V12H9V6H10ZM10 2H6V3H10V2Z" fill="#333334"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 342 B

7
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_delete_normal.svg

@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="&#231;&#138;&#182;&#230;&#128;&#129;=&#230;&#173;&#163;&#229;&#184;&#184;">
<g id="icon/delete">
<path id="Combined-Shape" d="M11 1V3H15V4H13V15H3V4H1V3H5V1H11ZM12 4H4V14H12V4ZM7 6V12H6V6H7ZM10 6V12H9V6H10ZM10 2H6V3H10V2Z" fill="#333334"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 360 B

8
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_normal.svg

@ -0,0 +1,8 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#229;&#155;&#158;&#230;&#148;&#182;&#231;&#171;&#153;">
<g id="icon/delete">
<path id="Combined-Shape" d="M11 1V3H15V4H13V15H3V4H1V3H5V1H11ZM12 4H4V14H12V4ZM10 2H6V3H10V2Z" fill="#333334"/>
</g>
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M9.4255 7.5425L8.5 6H7.5L5.93265 8.61225L6.79415 8.84308L8 6.83333L8.8005 8.1675L9.4255 7.5425ZM9.95583 8.42638L9.33083 9.05138L10.5 11H8.86391L9.09598 11.8661L11 11.8661L11.5 11L9.95583 8.42638ZM8.06071 11.8661L7.82864 11H5.5L6.25902 9.73497L5.39752 9.50413L4.5 11L5 11.8672L5.00064 11.8661L8.06071 11.8661Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 706 B

5
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_restore_disabled.svg

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#232;&#191;&#152;&#229;&#142;&#159;" opacity="0.3">
<path id="Union" d="M2.39418 1.6C2.39418 1.26863 2.66281 1 2.99418 1C3.32555 1 3.59418 1.26863 3.59418 1.6V4.0414C4.68979 2.9897 6.17846 2.3423 7.81813 2.3423C11.1871 2.3423 13.9181 5.07336 13.9181 8.4423C13.9181 11.8112 11.1871 14.5423 7.81813 14.5423C5.12408 14.5423 2.83941 12.7962 2.03106 10.3757C1.92609 10.0614 2.0958 9.72152 2.41011 9.61655C2.72441 9.51159 3.0643 9.68129 3.16927 9.9956C3.81901 11.9412 5.65572 13.3423 7.81813 13.3423C10.5243 13.3423 12.7181 11.1485 12.7181 8.4423C12.7181 5.7361 10.5243 3.5423 7.81813 3.5423C6.45385 3.5423 5.2199 4.09935 4.33089 5H6.99418C7.32555 5 7.59418 5.26863 7.59418 5.6C7.59418 5.93137 7.32555 6.2 6.99418 6.2H2.99418C2.66281 6.2 2.39418 5.93137 2.39418 5.6V1.6Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 904 B

5
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_restore_normal.svg

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon &#232;&#191;&#152;&#229;&#142;&#159;">
<path id="Union" d="M2.39418 1.6C2.39418 1.26863 2.66281 1 2.99418 1C3.32555 1 3.59418 1.26863 3.59418 1.6V4.0414C4.68979 2.9897 6.17846 2.3423 7.81813 2.3423C11.1871 2.3423 13.9181 5.07336 13.9181 8.4423C13.9181 11.8112 11.1871 14.5423 7.81813 14.5423C5.12408 14.5423 2.83941 12.7962 2.03106 10.3757C1.92609 10.0614 2.0958 9.72152 2.41011 9.61655C2.72441 9.51159 3.0643 9.68129 3.16927 9.9956C3.81901 11.9412 5.65572 13.3423 7.81813 13.3423C10.5243 13.3423 12.7181 11.1485 12.7181 8.4423C12.7181 5.7361 10.5243 3.5423 7.81813 3.5423C6.45385 3.5423 5.2199 4.09935 4.33089 5H6.99418C7.32555 5 7.59418 5.26863 7.59418 5.6C7.59418 5.93137 7.32555 6.2 6.99418 6.2H2.99418C2.66281 6.2 2.39418 5.93137 2.39418 5.6V1.6Z" fill="#333334"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 890 B

3
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_recycle_search_normal.svg

@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Combined Shape" fill-rule="evenodd" clip-rule="evenodd" d="M5.5 11C2.46243 11 0 8.53757 0 5.5C0 2.46243 2.46243 0 5.5 0C8.53757 0 11 2.46243 11 5.5C11 6.75785 10.5778 7.91707 9.86726 8.84367L13.7881 12.7645C14.0707 13.0471 14.0707 13.5054 13.7881 13.7881C13.5054 14.0707 13.0471 14.0707 12.7645 13.7881L8.84367 9.86726C7.91707 10.5778 6.75785 11 5.5 11ZM10 5.5C10 7.98528 7.98528 10 5.5 10C3.01472 10 1 7.98528 1 5.5C1 3.01472 3.01472 1 5.5 1C7.98528 1 10 3.01472 10 5.5Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 603 B

4
designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_sort_normal.svg

@ -0,0 +1,4 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.2462 6.17654C14.3492 6.30778 14.2557 6.5 14.0889 6.5H11.9999V13.9768C11.9999 14.0873 11.9104 14.1768 11.7999 14.1768H11.1999C11.0895 14.1768 10.9999 14.0873 10.9999 13.9768V6.5H8.91119C8.74436 6.5 8.65086 6.30779 8.75384 6.17654L11.3426 2.87732C11.4227 2.77527 11.5772 2.77527 11.6573 2.87731L14.2462 6.17654Z" fill="#333334"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.04297 10.801C2.93999 10.6698 3.03349 10.4775 3.20032 10.4775H5.28927V3.00074C5.28927 2.89028 5.37881 2.80074 5.48927 2.80074H6.08927C6.19972 2.80074 6.28927 2.89028 6.28927 3.00074V10.4775H8.378C8.54482 10.4775 8.63832 10.6698 8.53534 10.801L5.94661 14.1002C5.86653 14.2023 5.712 14.2023 5.63192 14.1002L3.04297 10.801Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 874 B

5
designer-base/src/main/resources/com/fr/design/vcs/move_failed.svg

@ -0,0 +1,5 @@
<svg width="64" height="65" viewBox="0 0 64 65" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M32 60.5C16.536 60.5 4 47.964 4 32.5C4 17.036 16.536 4.5 32 4.5C47.464 4.5 60 17.036 60 32.5C60 47.964 47.464 60.5 32 60.5Z" fill="#EB1D1F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M44 24.1928L23.692 44.4995L20 40.8075L40.308 20.4995L44 24.1928Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.308 44.5L20 24.1933L23.692 20.5L44 40.8067L40.308 44.5Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 549 B

5
designer-base/src/main/resources/com/fr/design/vcs/move_success.svg

@ -0,0 +1,5 @@
<svg width="58" height="59" viewBox="0 0 58 59" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M29 58.5C12.9837 58.5 0 45.5163 0 29.5C0 13.4837 12.9837 0.5 29 0.5C45.0163 0.5 58 13.4837 58 29.5C58 45.5163 45.0163 58.5 29 58.5Z" fill="#16C153"/>
<rect x="20.66" y="39.8213" width="32.1738" height="5.52381" transform="rotate(-45 20.66 39.8213)" fill="white"/>
<rect x="14.9535" y="26.7378" width="18.7954" height="5.52381" transform="rotate(45 14.9535 26.7378)" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 533 B

3
designer-base/src/main/resources/com/fr/design/vcs/vcs_move_icon.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 8C15 4.13435 11.8656 1 8 1C4.13435 1 1 4.13435 1 8C1 11.8656 4.13435 15 8 15C11.8656 15 15 11.8656 15 8ZM7.43333 5.70798C7.27778 5.55242 7.2 5.36353 7.2 5.14131C7.2 4.91909 7.27778 4.7302 7.43333 4.57464C7.58889 4.41909 7.77778 4.34131 8 4.34131C8.22222 4.34131 8.41111 4.41909 8.56667 4.57464C8.72222 4.7302 8.8 4.91909 8.8 5.14131C8.8 5.36353 8.72222 5.55242 8.56667 5.70798C8.41111 5.86353 8.22222 5.94131 8 5.94131C7.77778 5.94131 7.58889 5.86353 7.43333 5.70798ZM8 11.7787C7.6134 11.7787 7.3 11.4653 7.3 11.0787V7.47868C7.3 7.09208 7.6134 6.77868 8 6.77868C8.3866 6.77868 8.7 7.09208 8.7 7.47868V11.0787C8.7 11.4653 8.3866 11.7787 8 11.7787Z" fill="#419BF9"/>
</svg>

After

Width:  |  Height:  |  Size: 821 B

29
designer-base/src/test/java/com/fr/base/ClassHelperTest.java

@ -1,29 +0,0 @@
package com.fr.base;
import com.fr.form.main.Form;
import com.fr.invoke.ClassHelper;
import com.fr.main.impl.WorkBook;
import java.util.Set;
import junit.framework.TestCase;
import org.junit.Assert;
/**
* @author hades
* @version 10.0
* Created by hades on 2020/12/28
*/
public class ClassHelperTest extends TestCase {
public void testGetClassLoaders() {
WorkBook workBook = new WorkBook();
Set<ClassLoader> set = ClassHelper.getClassLoaders(workBook);
Assert.assertFalse(set.isEmpty());
Form form = new Form();
Set<ClassLoader> set1 = ClassHelper.getClassLoaders(form);
Assert.assertFalse(set1.isEmpty());
}
}

9
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这种情况,之前多虑了
}
}

2
designer-base/src/test/java/com/fr/nx/app/designer/toolbar/TransformResultInfoTest.java

@ -19,7 +19,7 @@ public class TransformResultInfoTest {
resultInfo2.getTransformLog());
TransformResultInfo resultInfo3 = TransformResultInfo.generateResult(TransformResult.UNSUPPORT, "unsupport");
Assert.assertEquals("unsupport\n" +
InterProviderFactory.getProvider().getLocText("Fine-Plugin_Engine_Transform_Unsupport_Tip"),
InterProviderFactory.getProvider().getLocText("Fine-Plugin_Engine_X_Unsupport_Tip"),
resultInfo3.getTransformLog());
}

8
designer-form/src/main/java/com/fr/design/actions/NewFormAction.java

@ -6,16 +6,12 @@ import com.fr.design.widget.ui.designer.NewFormPane;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER;
public class NewFormAction extends UpdateAction {
public NewFormAction() {
this.setMenuKeySet(NEW_FORM);
this.setName(getMenuKeySet().getMenuKeySetName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setName(getMenuKeySet().getMenuName());
this.setSmallIcon("/com/fr/design/images/buttonicon/new_form3");
this.setAccelerator(getMenuKeySet().getKeyStroke());
}
@ -33,7 +29,7 @@ public class NewFormAction extends UpdateAction {
public static final MenuKeySet NEW_FORM = new MenuKeySet() {
@Override
public char getMnemonic() {
return 'F';
return 0;
}
@Override

27
designer-form/src/main/java/com/fr/design/designer/creator/XEditorHolder.java

@ -44,9 +44,7 @@ public class XEditorHolder extends XWidgetCreator {
ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, this);
editingMouseListener.startEditing(this, adapter.getDesignerEditor(), adapter);
Rectangle rect = this.getBounds();
int min = rect.x + rect.width / 2 - editingMouseListener.getMinMoveSize();
int max = rect.x + rect.width / 2 + editingMouseListener.getMinMoveSize();
if (e.getX() > min && e.getX() < max) {
if (checkMouseEditRangeValid(e, rect, editingMouseListener)) {
ToolTipEditor.getInstance().showToolTip((XEditorHolder) this, e.getXOnScreen(),
e.getYOnScreen());
}
@ -54,6 +52,29 @@ public class XEditorHolder extends XWidgetCreator {
}
}
/**
* 判断当前鼠标事件是否在可编辑区域内
*
* @param e 鼠标事件
* @param rect 区域
* @param editingMouseListener 位置处理器
* @return 是否位于可编辑区
*/
private boolean checkMouseEditRangeValid(MouseEvent e, Rectangle rect, EditingMouseListener editingMouseListener) {
int horizontalValue = editingMouseListener.getDesigner().getHorizontalScaleValue();
int verticalValue = editingMouseListener.getDesigner().getVerticalScaleValue();
int minMoveSize = editingMouseListener.getMinMoveSize();
int minHorizontal = rect.x + rect.width / 2 - minMoveSize - horizontalValue;
int maxHorizontal = rect.x + rect.width / 2 + minMoveSize - horizontalValue;
int minVertical = rect.y + rect.height / 2 - minMoveSize - verticalValue;
int maxVertical = rect.y + rect.height / 2 + minMoveSize - verticalValue;
boolean xRangeValid = e.getX() > minHorizontal && e.getX() < maxHorizontal;
boolean yRangeValid = e.getY() > minVertical && e.getY() < maxVertical;
return xRangeValid && yRangeValid;
}
@Override
protected String getIconName() {
return "text_field_16.png";

23
designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java

@ -279,9 +279,7 @@ public class EditingMouseListener extends MouseInputAdapter {
if (component instanceof XEditorHolder) {
XEditorHolder xcreator = (XEditorHolder) component;
Rectangle rect = xcreator.getBounds();
int min = rect.x + rect.width / 2 - minMoveSize;
int max = rect.x + rect.width / 2 + minMoveSize;
if (e.getX() > min && e.getX() < max) {
if (checkCreatorRangeValid(e, rect)) {
if (designer.getCursor().getType() != Cursor.HAND_CURSOR) {
designer.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
@ -673,8 +671,8 @@ public class EditingMouseListener extends MouseInputAdapter {
currentEditor = designerEditor;
currentXCreator = creator;
Rectangle bounds = new Rectangle(1, 1, creator.getWidth() - 2, creator.getHeight() - 2);
bounds.x += (rect.x - designer.getArea().getHorizontalValue());
bounds.y += (rect.y - designer.getArea().getVerticalValue());
bounds.x += (rect.x - designer.getHorizontalScaleValue());
bounds.y += (rect.y - designer.getVerticalScaleValue());
designerEditor.getEditorTarget().setBounds(bounds);
designer.add(designerEditor.getEditorTarget());
designer.invalidate();
@ -747,4 +745,19 @@ public class EditingMouseListener extends MouseInputAdapter {
refreshTopXCreator(false);
}
/**
* 判断当前鼠标移动事件是否在Creator有效范围内
*/
private boolean checkCreatorRangeValid(MouseEvent e, Rectangle rect) {
int horizontalValue = designer.getHorizontalScaleValue();
int verticalValue = designer.getVerticalScaleValue();
int minHorizontal = rect.x + rect.width / 2 - minMoveSize - horizontalValue;
int maxHorizontal = rect.x + rect.width / 2 + minMoveSize - horizontalValue;
int minVertical = rect.y + rect.height / 2 - minMoveSize - verticalValue;
int maxVertical = rect.y + rect.height / 2 + minMoveSize - verticalValue;
boolean xRangeValid = e.getX() > minHorizontal && e.getX() < maxHorizontal;
boolean yRangeValid = e.getY() > minVertical && e.getY() < maxVertical;
return xRangeValid && yRangeValid;
}
}

2
designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java

@ -1208,7 +1208,7 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
}
public XLayoutContainer getRootContainer(int y) {
XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() ? paraComponent : rootComponent;
XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() / scale ? paraComponent : rootComponent;
if (container == null) {
container = rootComponent;
}

2
designer-form/src/main/java/com/fr/design/widget/ui/designer/component/FormWidgetValuePane.java

@ -63,7 +63,7 @@ public class FormWidgetValuePane extends JPanel {
/**
* 根据类型创建
*
* 设计器右侧控件设置 - 属性
* @param type 类型
* @param onlyServer 是否是服务器
* @return 编辑器

40
designer-form/src/test/java/com/fr/design/mainframe/template/info/JFormProcessInfoTest.java

@ -1,7 +1,9 @@
package com.fr.design.mainframe.template.info;
import com.fr.base.background.ColorBackground;
import com.fr.base.svg.IconUtils;
import com.fr.chart.chartattr.ChartCollection;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.theme.utils.DefaultThemedTemplateCellElementCase;
import com.fr.form.main.Form;
import com.fr.form.ui.CardSwitchButton;
@ -20,15 +22,53 @@ import com.fr.json.JSONArray;
import com.fr.plugin.chart.vanchart.VanChart;
import com.fr.report.cell.DefaultTemplateCellElement;
import com.fr.report.worksheet.FormElementCase;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import javax.swing.Icon;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
/**
* Created by kerry on 2020-05-08
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Toolkit.class, IconUtils.class})
@PowerMockIgnore({"javax.management.*"})
public class JFormProcessInfoTest {
@Before
public void setUp() throws Exception {
PowerMock.mockStatic(Toolkit.class);
PowerMock.mockStatic(IconUtils.class);
EasyMock.expect(Toolkit.i18nText(EasyMock.anyString())).andReturn("ignore").anyTimes();
EasyMock.expect(IconUtils.readIcon(EasyMock.anyString())).andReturn(new Icon() {
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
// do nothing
}
@Override
public int getIconWidth() {
return 0;
}
@Override
public int getIconHeight() {
return 0;
}
}).anyTimes();
PowerMock.replayAll();
}
@Test
public void testHasTestECReport() {
Form form = new Form();

14
designer-realize/src/main/java/com/fr/design/report/ImageExportPane.java

@ -84,20 +84,20 @@ public class ImageExportPane extends AbstractExportPane {
private void initGlobalSettings() {
globalResolutionBtnS = new UIRadioButton("96dpi", true);
globalResolutionBtnM = new UIRadioButton("192dpi");
globalResolutionBtnS = new UIRadioButton("96dpi");
globalResolutionBtnM = new UIRadioButton("192dpi", true);
globalResolutionBtnL = new UIRadioButton("300dpi");
wrapButtonsInButtonGroup(globalResolutionBtnS, globalResolutionBtnM, globalResolutionBtnL);
globalFormatJpg = new UIRadioButton("jpg", true);
globalFormatPng = new UIRadioButton("png");
globalFormatJpg = new UIRadioButton("jpg");
globalFormatPng = new UIRadioButton("png", true);
wrapButtonsInButtonGroup(globalFormatJpg, globalFormatPng);
globalRenderQuality = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Quality_First"), true);
globalRenderSpeed = new UIRadioButton(Toolkit.i18nText(("Fine-Design_Image_Export_Speed_Priority")));
globalRenderQuality = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Quality_First"));
globalRenderSpeed = new UIRadioButton(Toolkit.i18nText(("Fine-Design_Image_Export_Speed_Priority")), true);
wrapButtonsInButtonGroup(globalRenderQuality, globalRenderSpeed);
templateThumbnail = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Thumbnail"));
templateThumbnail = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Thumbnail"), true);
templatePaging = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Paging"));
wrapButtonsInButtonGroup(templateThumbnail, templatePaging);
}

22
designer-realize/src/main/java/com/fr/design/sort/common/SortColumnRowPane.java

@ -24,13 +24,16 @@ import com.fr.stable.ColumnRow;
import com.fr.stable.EssentialUtils;
import com.fr.stable.StringUtils;
import javax.swing.*;
import java.awt.*;
import javax.swing.Icon;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class SortColumnRowPane extends JPanel implements UIObserver {
@ -260,8 +263,10 @@ public class SortColumnRowPane extends JPanel implements UIObserver {
disableHeaderCellsStyleMap = new HashMap<>();
tempHeaderCells = new ArrayList<>();
for (ColumnRow columnRow : notSelectables) {
TemplateCellElement templateCellElement
= elementCase.getTemplateCellElement(columnRow.column, columnRow.row);
TemplateCellElement templateCellElement = null;
if (columnRow != ColumnRow.ERROR) {
templateCellElement = elementCase.getTemplateCellElement(columnRow.column, columnRow.row);
}
if (templateCellElement == null) {
templateCellElement = new DefaultTemplateCellElement(columnRow.column, columnRow.row);
elementCase.addCellElement(templateCellElement);
@ -280,8 +285,11 @@ public class SortColumnRowPane extends JPanel implements UIObserver {
if (cellSelectionManager != null) {
try {
for (ColumnRow headerColumnRow : disableHeaderCellsStyleMap.keySet()) {
TemplateCellElement headerTemplateCellElement
= elementCase.getTemplateCellElement(headerColumnRow.column, headerColumnRow.row);
TemplateCellElement headerTemplateCellElement = null;
if (headerColumnRow != ColumnRow.ERROR) {
headerTemplateCellElement
= elementCase.getTemplateCellElement(headerColumnRow.column, headerColumnRow.row);
}
if (headerTemplateCellElement != null) {
headerTemplateCellElement.setStyle(disableHeaderCellsStyleMap.get(headerColumnRow));
}

4
designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java

@ -815,10 +815,6 @@ public class CellSelection extends Selection {
return cellElements;
}
public Set<TemplateCellElement> getCellElements() {
return cellElements;
}
@Override
public void populatePropertyPane(ElementCasePane ePane) {
CellElementPropertyPane.getInstance().reInit(ePane);

2
designer-realize/src/main/java/com/fr/quickeditor/CellQuickEditor.java

@ -442,7 +442,7 @@ public abstract class CellQuickEditor extends QuickEditor<ElementCasePane> {
CellSelection cs = (CellSelection) tc.getSelection();
TemplateElementCase editingElementCase = tc.getEditingElementCase();
Set<TemplateCellElement> allCellElements = cs.getCellElements();
Set<TemplateCellElement> allCellElements = cs.getAllCellElements(editingElementCase);
Style oldStyle = cellElement == null ? Style.DEFAULT_STYLE : cellElement.getStyle();
Style style = formatPane.update(oldStyle);
for (TemplateCellElement cellElement : allCellElements) {

6
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<TemplateCellElement> allCellElements = selection.getCellElements();
Set<TemplateCellElement> 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<TemplateCellElement> allCellElements = selection.getCellElements();
Set<TemplateCellElement> 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);

8
designer-realize/src/main/java/com/fr/start/MainDesigner.java

@ -213,14 +213,18 @@ public class MainDesigner extends BaseDesigner {
ArrayList<ShortCut> shortCuts = new ArrayList<ShortCut>();
// shortCuts.add(new NewWorkBookXAction());
shortCuts.add(new NewWorkBookAction());
// 决策报表、聚合报表归入其他
MenuDef newOtherFileMenuDef = new MenuDef(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_M_New_Other_Template"));
newOtherFileMenuDef.setIconPath("/com/fr/design/images/buttonicon/new_other");
try {
if (DesignModuleFactory.getNewFormAction() != null) {
shortCuts.add((ShortCut) DesignModuleFactory.getNewFormAction().newInstance());
newOtherFileMenuDef.addShortCut((ShortCut) DesignModuleFactory.getNewFormAction().newInstance());
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
shortCuts.add(new NewPolyReportAction());
newOtherFileMenuDef.addShortCut(new NewPolyReportAction());
shortCuts.add(newOtherFileMenuDef);
return shortCuts.toArray(new ShortCut[0]);
}

BIN
designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

BIN
designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

BIN
designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

BIN
designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/images/local_fvs4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

160
designer-realize/src/main/resources/com/fr/design/mainframe/alphafine/template_resource/local_templates.json

File diff suppressed because one or more lines are too long

6
designer-realize/src/test/java/com/fr/nx/app/designer/CptxAppTest.java

@ -4,7 +4,6 @@ import com.fr.file.AbstractFILE;
import com.fr.file.FILE;
import com.fr.main.impl.WorkBook;
import com.fr.nx.cptx.utils.CptxFileUtils;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
@ -42,12 +41,9 @@ public class CptxAppTest {
}
};
WorkBook workBook = new WorkBook();
EasyMock.expect(CptxFileUtils.getWorkBook(file.getPath()))
.andReturn(workBook).once()
.andReturn(null).once();
PowerMock.replay(CptxFileUtils.class);
Assert.assertSame(workBook, new CptxApp().asIOFile(file));
Assert.assertTrue(workBook.equals(new CptxApp().asIOFile(file)));
Assert.assertNotNull(new CptxApp().asIOFile(file));

Loading…
Cancel
Save