* 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
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
@ -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); |
||||||
|
} |
@ -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"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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){} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -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); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -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"); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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){} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 885 B |
After Width: | Height: | Size: 400 B |
After Width: | Height: | Size: 523 B |
After Width: | Height: | Size: 366 B |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 973 B |
After Width: | Height: | Size: 342 B |
After Width: | Height: | Size: 360 B |
After Width: | Height: | Size: 706 B |
After Width: | Height: | Size: 904 B |
After Width: | Height: | Size: 890 B |
After Width: | Height: | Size: 603 B |
After Width: | Height: | Size: 874 B |
After Width: | Height: | Size: 549 B |
After Width: | Height: | Size: 533 B |
After Width: | Height: | Size: 821 B |
@ -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()); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
After Width: | Height: | Size: 802 KiB |
After Width: | Height: | Size: 390 KiB |
After Width: | Height: | Size: 483 KiB |
After Width: | Height: | Size: 181 KiB |