* commit '1d349e1db53d5e9bb5d9a0c0085db9202c6d20d7': (83 commits) ct ct ct ct 页大小改大一点 格式化 bug fix 封装vcsconfigmanager REPORT-16461 设计器中关闭自动推送更新无效=>调整代码 REPORT-16461 设计器中关闭自动推送更新无效 REPORT-16527 @xiaoxia 通过直接预览触发的模版保存,该模版不会保存新版本 REPORT-16517 交互修改 REPORT-16456 【10.0.3埋点-模板】远程设计不生效 REPORT-16494 模板信息收集, 设计器启动有报错=>调整代码 REPORT-16494 模板信息收集, 设计器启动有报错=>调整代码 REPORT-16494 模板信息收集, 设计器启动有报错 REPORT-14835 设计器界面调整 使用JDateTime 文件没有正常删除; 功能点上传的时候数据对不上; REPORT-14835 国际化 ...bugfix/10.0
@ -0,0 +1,117 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
|
||||
import java.text.ParseException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* 管理打开设计器的日期记录 |
||||
* Created by plough on 2019/4/19. |
||||
*/ |
||||
class DesignerOpenHistory implements XMLReadable, XMLWriter { |
||||
static final String XML_TAG = "DesignerOpenHistory"; |
||||
private static DesignerOpenHistory singleton; |
||||
private static final String SPLITTER = ","; |
||||
private static final int LENGTH = 3; // 保留最近 3 次的记录
|
||||
// 最近的日期是 history[0],最早的日期是 history[LENGTH-1]
|
||||
private String[] history = new String[LENGTH]; |
||||
|
||||
private DesignerOpenHistory() { |
||||
for (int i = 0; i < LENGTH; i++) { |
||||
history[i] = StringUtils.EMPTY; |
||||
} |
||||
} |
||||
|
||||
static DesignerOpenHistory getInstance() { |
||||
if (singleton == null) { |
||||
singleton = new DesignerOpenHistory(); |
||||
} |
||||
return singleton; |
||||
} |
||||
|
||||
void update() { |
||||
String today = getToday(); |
||||
if (ComparatorUtils.equals(history[0], today)) { |
||||
return; |
||||
} |
||||
shiftByOne(); |
||||
history[0] = today; |
||||
} |
||||
|
||||
/** |
||||
* 获取历史记录中囊括的日子数。即最早的历史记录 history[LENGTH - 1],到最晚的记录 history[0] 之间的时间跨度 |
||||
*/ |
||||
int getHistorySpanDayCount() { |
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
||||
try { |
||||
Date earliestDate = sdf.parse(getEarliestDate()); |
||||
Date latestDate = sdf.parse(history[0]); |
||||
long diffInMillies = latestDate.getTime() - earliestDate.getTime(); |
||||
return (int)TimeUnit.DAYS.convert(diffInMillies,TimeUnit.MILLISECONDS) + 1; |
||||
} catch (ParseException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
/** |
||||
* 今天是否已经打开过设计器 |
||||
*/ |
||||
boolean hasOpenedToday() { |
||||
String today = getToday(); |
||||
return ComparatorUtils.equals(today, history[0]); |
||||
} |
||||
|
||||
private String getEarliestDate() { |
||||
for (int i = LENGTH - 1; i >= 0; i--) { |
||||
if (StringUtils.isNotEmpty(history[i])) { |
||||
return history[i]; |
||||
} |
||||
} |
||||
throw new AssertionError("Designer open history is empty!"); |
||||
} |
||||
|
||||
private void shiftByOne() { |
||||
for (int i = LENGTH - 1; i > 0; i--) { |
||||
history[i] = history[i-1]; |
||||
} |
||||
} |
||||
|
||||
private String getToday() { |
||||
return new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return StringUtils.join(SPLITTER, history); |
||||
} |
||||
|
||||
private void parseString(String s) { |
||||
String[] arr = s.split(SPLITTER); |
||||
System.arraycopy(arr, 0, history, 0, arr.length); |
||||
} |
||||
|
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (XML_TAG.equals(reader.getTagName())) { |
||||
parseString(reader.getElementValue()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TAG); |
||||
writer.textNode(toString()); |
||||
writer.end(); |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.design.mainframe.SiteCenterToken; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.general.http.HttpToolbox; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 负责向服务器发送信息 |
||||
* Created by plough on 2019/4/18. |
||||
*/ |
||||
class SendHelper { |
||||
private static final String CONSUMING_URL = CloudCenter.getInstance().acquireUrlByKind("tempinfo.consuming") + "/single"; |
||||
private static final String PROCESS_URL = CloudCenter.getInstance().acquireUrlByKind("tempinfo.process") + "/single"; |
||||
|
||||
private static boolean sendConsumingInfo(String content) { |
||||
return sendSingleTemplateInfo(CONSUMING_URL, content); |
||||
} |
||||
|
||||
private static boolean sendProcessInfo(String content) { |
||||
return sendSingleTemplateInfo(PROCESS_URL, content); |
||||
} |
||||
|
||||
static boolean sendTemplateInfo(TemplateInfo templateInfo) { |
||||
return SendHelper.sendConsumingInfo(templateInfo.getConsumingMapJsonString()) && SendHelper.sendProcessInfo(templateInfo.getProcessMapJsonString()); |
||||
} |
||||
|
||||
private static boolean sendSingleTemplateInfo(String url, String content) { |
||||
Map<String, Object> para = new HashMap<>(); |
||||
para.put("token", SiteCenterToken.generateToken()); |
||||
para.put("content", content); |
||||
|
||||
try { |
||||
String res = HttpToolbox.post(url, para); |
||||
return ComparatorUtils.equals(new JSONObject(res).get("status"), "success"); |
||||
} catch (Throwable e) { |
||||
// 客户不需要关心,错误等级为 debug 就行了
|
||||
FineLoggerFactory.getLogger().debug(e.getMessage(), e); |
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,260 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.config.MarketConfig; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
|
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Calendar; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 对应一张模版的记录 |
||||
* Created by plough on 2019/4/18. |
||||
*/ |
||||
class TemplateInfo implements XMLReadable, XMLWriter { |
||||
static final String XML_TAG = "TemplateInfo"; |
||||
|
||||
private static final String XML_PROCESS_MAP = "processMap"; |
||||
private static final String XML_CONSUMING_MAP = "consumingMap"; |
||||
private static final String ATTR_DAY_COUNT = "day_count"; |
||||
private static final String ATTR_TEMPLATE_ID = "templateID"; |
||||
private static final String ATTR_ORIGIN_ID = "originID"; |
||||
private static final String ATTR_PROCESS = "process"; |
||||
private static final String ATTR_FLOAT_COUNT = "float_count"; |
||||
private static final String ATTR_WIDGET_COUNT = "widget_count"; |
||||
private static final String ATTR_CELL_COUNT = "cell_count"; |
||||
private static final String ATTR_BLOCK_COUNT = "block_count"; |
||||
private static final String ATTR_REPORT_TYPE = "report_type"; |
||||
private static final String ATTR_ACTIVITYKEY = "activitykey"; |
||||
private static final String ATTR_JAR_TIME = "jar_time"; |
||||
private static final String ATTR_CREATE_TIME = "create_time"; |
||||
private static final String ATTR_UUID = "uuid"; |
||||
private static final String ATTR_TIME_CONSUME = "time_consume"; |
||||
private static final String ATTR_ORIGIN_TIME = "originTime"; |
||||
private static final String ATTR_VERSION = "version"; |
||||
private static final String ATTR_USERNAME = "username"; |
||||
|
||||
private static final int VALID_CELL_COUNT = 5; // 有效报表模板的格子数
|
||||
private static final int VALID_WIDGET_COUNT = 5; // 有效报表模板的控件数
|
||||
private static final int COMPLETE_DAY_COUNT = 15; // 判断模板是否完成的天数
|
||||
|
||||
private int idleDayCount; // 到现在为止,模版闲置(上次保存后没有再编辑过)的天数
|
||||
private String templateID = StringUtils.EMPTY; |
||||
private String originID = StringUtils.EMPTY; |
||||
// todo: processMap 和 consumingMap 还可以再拆解为小类,以后继续重构
|
||||
private Map<String, Object> processMap = new HashMap<>(); |
||||
private Map<String, Object> consumingMap = new HashMap<>(); |
||||
|
||||
private TemplateInfo() { |
||||
} |
||||
|
||||
private TemplateInfo(String templateID, String originID) { |
||||
this.templateID = templateID; |
||||
this.originID = originID; |
||||
} |
||||
|
||||
static TemplateInfo newInstanceByRead(XMLableReader reader) { |
||||
TemplateInfo templateInfo = new TemplateInfo(); |
||||
reader.readXMLObject(templateInfo); |
||||
return templateInfo; |
||||
} |
||||
|
||||
static TemplateInfo newInstance(String templateID) { |
||||
return newInstance(templateID, StringUtils.EMPTY, 0); |
||||
} |
||||
|
||||
static TemplateInfo newInstance(String templateID, String originID, int originTime) { |
||||
HashMap<String, Object> consumingMap = new HashMap<>(); |
||||
|
||||
String username = MarketConfig.getInstance().getBbsUsername(); |
||||
String uuid = DesignerEnvManager.getEnvManager().getUUID(); |
||||
String activitykey = DesignerEnvManager.getEnvManager().getActivationKey(); |
||||
String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(Calendar.getInstance().getTime()); |
||||
String jarTime = GeneralUtils.readBuildNO(); |
||||
String version = ProductConstants.VERSION; |
||||
consumingMap.put(ATTR_USERNAME, username); |
||||
consumingMap.put(ATTR_UUID, uuid); |
||||
consumingMap.put(ATTR_ACTIVITYKEY, activitykey); |
||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
consumingMap.put(ATTR_ORIGIN_ID, originID); |
||||
consumingMap.put(ATTR_CREATE_TIME, createTime); |
||||
consumingMap.put(ATTR_TIME_CONSUME, originTime); // timeConsume 在原来模版的基础上累加
|
||||
consumingMap.put(ATTR_ORIGIN_TIME, originTime); |
||||
consumingMap.put(ATTR_JAR_TIME, jarTime); |
||||
consumingMap.put(ATTR_VERSION, version); |
||||
|
||||
TemplateInfo templateInfo = new TemplateInfo(templateID, originID); |
||||
templateInfo.consumingMap = consumingMap; |
||||
|
||||
return templateInfo; |
||||
} |
||||
|
||||
String getTemplateID() { |
||||
return templateID; |
||||
} |
||||
|
||||
String getOriginID() { |
||||
return originID; |
||||
} |
||||
|
||||
int getTimeConsume() { |
||||
return (int)consumingMap.get(ATTR_TIME_CONSUME); |
||||
} |
||||
|
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TAG); |
||||
if (StringUtils.isNotEmpty(templateID)) { |
||||
writer.attr(ATTR_TEMPLATE_ID, this.templateID); |
||||
} |
||||
if (StringUtils.isNotEmpty(originID)) { |
||||
writer.attr(ATTR_ORIGIN_ID, this.originID); |
||||
} |
||||
if (idleDayCount >= 0) { |
||||
writer.attr(ATTR_DAY_COUNT, this.idleDayCount); |
||||
} |
||||
writeProcessMap(writer); |
||||
writeConsumingMap(writer); |
||||
|
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeProcessMap(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_PROCESS_MAP); |
||||
writer.attr(ATTR_PROCESS, (String) processMap.get(ATTR_PROCESS)); |
||||
writer.attr(ATTR_FLOAT_COUNT, (int) processMap.get(ATTR_FLOAT_COUNT)); |
||||
writer.attr(ATTR_WIDGET_COUNT, (int) processMap.get(ATTR_WIDGET_COUNT)); |
||||
writer.attr(ATTR_CELL_COUNT, (int) processMap.get(ATTR_CELL_COUNT)); |
||||
writer.attr(ATTR_BLOCK_COUNT, (int) processMap.get(ATTR_BLOCK_COUNT)); |
||||
writer.attr(ATTR_REPORT_TYPE, (int) processMap.get(ATTR_REPORT_TYPE)); |
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeConsumingMap(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_CONSUMING_MAP); |
||||
writer.attr(ATTR_ACTIVITYKEY, (String) consumingMap.get(ATTR_ACTIVITYKEY)); |
||||
writer.attr(ATTR_JAR_TIME, (String) consumingMap.get(ATTR_JAR_TIME)); |
||||
writer.attr(ATTR_CREATE_TIME, (String) consumingMap.get(ATTR_CREATE_TIME)); |
||||
writer.attr(ATTR_UUID, (String) consumingMap.get(ATTR_UUID)); |
||||
writer.attr(ATTR_TIME_CONSUME, (int)consumingMap.get(ATTR_TIME_CONSUME)); |
||||
writer.attr(ATTR_ORIGIN_TIME, (int)consumingMap.get(ATTR_ORIGIN_TIME)); |
||||
writer.attr(ATTR_VERSION, (String) consumingMap.get(ATTR_VERSION)); |
||||
writer.attr(ATTR_USERNAME, (String) consumingMap.get(ATTR_USERNAME)); |
||||
writer.end(); |
||||
} |
||||
|
||||
public void readXML(XMLableReader reader) { |
||||
if (!reader.isChildNode()) { |
||||
idleDayCount = reader.getAttrAsInt(ATTR_DAY_COUNT, 0); |
||||
templateID = reader.getAttrAsString(ATTR_TEMPLATE_ID, StringUtils.EMPTY); |
||||
originID = reader.getAttrAsString(ATTR_ORIGIN_ID, StringUtils.EMPTY); |
||||
} else { |
||||
try { |
||||
String name = reader.getTagName(); |
||||
if (XML_PROCESS_MAP.equals(name)) { |
||||
processMap.put(ATTR_PROCESS, reader.getAttrAsString(ATTR_PROCESS, StringUtils.EMPTY)); |
||||
processMap.put(ATTR_FLOAT_COUNT, reader.getAttrAsInt(ATTR_FLOAT_COUNT, 0)); |
||||
processMap.put(ATTR_WIDGET_COUNT, reader.getAttrAsInt(ATTR_WIDGET_COUNT, 0)); |
||||
processMap.put(ATTR_CELL_COUNT, reader.getAttrAsInt(ATTR_CELL_COUNT, 0)); |
||||
processMap.put(ATTR_BLOCK_COUNT, reader.getAttrAsInt(ATTR_BLOCK_COUNT, 0)); |
||||
processMap.put(ATTR_REPORT_TYPE, reader.getAttrAsInt(ATTR_REPORT_TYPE, 0)); |
||||
processMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
} else if (XML_CONSUMING_MAP.equals(name)) { |
||||
consumingMap.put(ATTR_ACTIVITYKEY, reader.getAttrAsString(ATTR_ACTIVITYKEY, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_JAR_TIME, reader.getAttrAsString(ATTR_JAR_TIME, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_CREATE_TIME, reader.getAttrAsString(ATTR_CREATE_TIME, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
consumingMap.put(ATTR_ORIGIN_ID, originID); |
||||
consumingMap.put(ATTR_UUID, reader.getAttrAsString(ATTR_UUID, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_TIME_CONSUME, reader.getAttrAsInt(ATTR_TIME_CONSUME, 0)); |
||||
consumingMap.put(ATTR_ORIGIN_TIME, reader.getAttrAsInt(ATTR_ORIGIN_TIME, 0)); |
||||
consumingMap.put(ATTR_VERSION, reader.getAttrAsString(ATTR_VERSION, "8.0")); |
||||
consumingMap.put(ATTR_USERNAME, reader.getAttrAsString(ATTR_USERNAME, StringUtils.EMPTY)); |
||||
} |
||||
} catch (Exception ex) { |
||||
// 什么也不做,使用默认值
|
||||
} |
||||
} |
||||
} |
||||
|
||||
boolean isTestTemplate() { |
||||
if (!isComplete()) { |
||||
return false; |
||||
} |
||||
|
||||
int reportType = (int) processMap.get(ATTR_REPORT_TYPE); |
||||
int cellCount = (int) processMap.get(ATTR_CELL_COUNT); |
||||
int floatCount = (int) processMap.get(ATTR_FLOAT_COUNT); |
||||
int blockCount = (int) processMap.get(ATTR_BLOCK_COUNT); |
||||
int widgetCount = (int) processMap.get(ATTR_WIDGET_COUNT); |
||||
boolean isTestTemplate; |
||||
if (reportType == 0) { // 普通报表
|
||||
isTestTemplate = cellCount <= VALID_CELL_COUNT && floatCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
||||
} else if (reportType == 1) { // 聚合报表
|
||||
isTestTemplate = blockCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
||||
} else { // 表单(reportType == 2)
|
||||
isTestTemplate = widgetCount <= 1; |
||||
} |
||||
return isTestTemplate; |
||||
} |
||||
|
||||
boolean isComplete() { |
||||
// 条件 1. 超过15天未编辑
|
||||
// 条件 2. 设计器在这段未编辑的时间内启动超过 X 次(目前定的 X = 3)。即"设计器最近 X 次启动的时间跨度" < "未编辑时间";
|
||||
|
||||
return idleDayCount > COMPLETE_DAY_COUNT |
||||
&& DesignerOpenHistory.getInstance().getHistorySpanDayCount() < idleDayCount; |
||||
} |
||||
|
||||
String getConsumingMapJsonString() { |
||||
return new JSONObject(consumingMap).toString(); |
||||
} |
||||
|
||||
String getProcessMapJsonString() { |
||||
return new JSONObject(processMap).toString(); |
||||
} |
||||
|
||||
boolean isReadyForSend() { |
||||
return isComplete() && !isTestTemplate(); |
||||
} |
||||
|
||||
void addTimeConsume(int timeConsume) { |
||||
timeConsume += (int)consumingMap.get(ATTR_TIME_CONSUME); // 加上之前的累计编辑时间
|
||||
consumingMap.put(ATTR_TIME_CONSUME, timeConsume); |
||||
} |
||||
|
||||
void updateProcessMap(TemplateProcessInfo processInfo) { |
||||
HashMap<String, Object> processMap = new HashMap<>(); |
||||
|
||||
// 暂不支持模版制作过程的收集
|
||||
processMap.put(ATTR_PROCESS, StringUtils.EMPTY); |
||||
|
||||
processMap.put(ATTR_REPORT_TYPE, processInfo.getReportType()); |
||||
processMap.put(ATTR_CELL_COUNT, processInfo.getCellCount()); |
||||
processMap.put(ATTR_FLOAT_COUNT, processInfo.getFloatCount()); |
||||
processMap.put(ATTR_BLOCK_COUNT, processInfo.getBlockCount()); |
||||
processMap.put(ATTR_WIDGET_COUNT, processInfo.getWidgetCount()); |
||||
|
||||
this.processMap = processMap; |
||||
} |
||||
|
||||
void resetIdleDayCount() { |
||||
this.idleDayCount = 0; |
||||
} |
||||
|
||||
void addIdleDayCountByOne() { |
||||
this.idleDayCount += 1; |
||||
} |
||||
|
||||
int getIdleDayCount() { |
||||
return this.idleDayCount; |
||||
} |
||||
} |
@ -0,0 +1,226 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLTools; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
||||
import com.fr.workspace.WorkContext; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.FileOutputStream; |
||||
import java.io.FileReader; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 做模板的过程和耗时收集,辅助类 |
||||
* Created by plough on 2017/2/21. |
||||
*/ |
||||
public class TemplateInfoCollector implements XMLReadable, XMLWriter { |
||||
private static final String XML_TAG = "TplInfo"; |
||||
private static final String XML_TEMPLATE_INFO_LIST = "TemplateInfoList"; |
||||
private static final String XML_FILE_NAME = "tpl.info"; |
||||
private static TemplateInfoCollector instance; |
||||
private Map<String, TemplateInfo> templateInfoMap; |
||||
private DesignerOpenHistory designerOpenHistory; |
||||
|
||||
private TemplateInfoCollector() { |
||||
init(); |
||||
} |
||||
|
||||
private void init() { |
||||
templateInfoMap = new HashMap<>(); |
||||
designerOpenHistory = DesignerOpenHistory.getInstance(); |
||||
|
||||
loadFromFile(); |
||||
} |
||||
|
||||
public static TemplateInfoCollector getInstance() { |
||||
if (instance == null) { |
||||
instance = new TemplateInfoCollector(); |
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
/** |
||||
* 根据模板ID是否在收集列表中,判断是否需要收集当前模板的信息 |
||||
*/ |
||||
public boolean contains(String templateID) { |
||||
return StringUtils.isNotEmpty(templateID) && templateInfoMap.containsKey(templateID); |
||||
} |
||||
|
||||
/** |
||||
* 收集模板信息。如果之前没有记录,则新增;如果已有记录,则更新。 |
||||
* 同时将最新数据保存到文件中。 |
||||
* @param templateID 模版id |
||||
* @param originID 模版的原始id,仅对另存为的模版有效,对于非另存为的模版,值总是为空 |
||||
* @param processInfo 包含模版的一些基本信息(如模版类型、包含控件数量等) |
||||
* @param timeConsume 本次制作耗时,单位为 s |
||||
*/ |
||||
public void collectInfo(String templateID, String originID, TemplateProcessInfo processInfo, int timeConsume) { |
||||
if (!shouldCollectInfo()) { |
||||
return; |
||||
} |
||||
|
||||
TemplateInfo templateInfo; |
||||
if (this.contains(templateID)) { |
||||
templateInfo = templateInfoMap.get(templateID); |
||||
} else { |
||||
int originTime = this.contains(originID) ? templateInfoMap.get(originID).getTimeConsume() : 0; |
||||
templateInfo = TemplateInfo.newInstance(templateID, originID, originTime); |
||||
templateInfoMap.put(templateID, templateInfo); |
||||
} |
||||
|
||||
// 收集制作耗时
|
||||
templateInfo.addTimeConsume(timeConsume); |
||||
// 收集模版基本信息
|
||||
templateInfo.updateProcessMap(processInfo); |
||||
// 刷新闲置日计数器
|
||||
templateInfo.resetIdleDayCount(); |
||||
|
||||
// 每次更新之后,都同步到暂存文件中
|
||||
saveInfo(); |
||||
} |
||||
|
||||
/** |
||||
* 发送本地模板信息到服务器,并清空已发送模版的本地记录 |
||||
*/ |
||||
public void sendTemplateInfo() { |
||||
// 每次启动设计器后,都会执行这个函数(被 InformationCollector 的 collectStartTime 调用)
|
||||
addIdleDayCount(); |
||||
|
||||
removeTestTemplates(); |
||||
|
||||
for (String key : templateInfoMap.keySet()) { |
||||
TemplateInfo templateInfo = templateInfoMap.get(key); |
||||
if (templateInfo.isReadyForSend()) { |
||||
if (SendHelper.sendTemplateInfo(templateInfo)) { |
||||
// 清空记录
|
||||
removeFromTemplateInfoList(templateInfo.getTemplateID()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
saveInfo(); |
||||
} |
||||
|
||||
/** |
||||
* 获取缓存文件存放路径 |
||||
*/ |
||||
private static File getInfoFile() { |
||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), XML_FILE_NAME)); |
||||
} |
||||
|
||||
void loadFromFile() { |
||||
if (!getInfoFile().exists()) { |
||||
return; |
||||
} |
||||
try { |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(new FileReader(getInfoFile())); |
||||
xmlReader.readXMLObject(this); |
||||
} catch (XMLStreamException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} catch (FileNotFoundException e) { |
||||
// do nothing
|
||||
} |
||||
} |
||||
|
||||
TemplateInfo getOrCreateTemplateInfoByID(String templateID) { |
||||
if (templateInfoMap.containsKey(templateID)) { |
||||
return templateInfoMap.get(templateID); |
||||
} |
||||
TemplateInfo templateInfo = TemplateInfo.newInstance(templateID); |
||||
templateInfoMap.put(templateID, templateInfo); |
||||
return templateInfo; |
||||
} |
||||
|
||||
private boolean shouldCollectInfo() { |
||||
return DesignerEnvManager.getEnvManager().isJoinProductImprove() && FRContext.isChineseEnv(); |
||||
} |
||||
|
||||
/** |
||||
* 将包含所有信息的对象保存到文件 |
||||
*/ |
||||
private void saveInfo() { |
||||
try { |
||||
FileOutputStream out = new FileOutputStream(getInfoFile()); |
||||
XMLTools.writeOutputStreamXML(this, out); |
||||
} catch (Exception ex) { |
||||
FineLoggerFactory.getLogger().error(ex.getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 更新 day_count:打开设计器却未编辑模板的连续日子 |
||||
*/ |
||||
private void addIdleDayCount() { |
||||
// 判断今天是否第一次打开设计器,为了防止同一天内,多次 addIdleDayCount
|
||||
if (designerOpenHistory.hasOpenedToday()) { |
||||
return; |
||||
} |
||||
for (TemplateInfo templateInfo : templateInfoMap.values()) { |
||||
templateInfo.addIdleDayCountByOne(); |
||||
} |
||||
designerOpenHistory.update(); |
||||
} |
||||
|
||||
// 删除所有已完成的测试模版
|
||||
private void removeTestTemplates() { |
||||
ArrayList<String> testTemplateKeys = new ArrayList<>(); // 保存测试模板的key
|
||||
for (String key : templateInfoMap.keySet()) { |
||||
if (templateInfoMap.get(key).isTestTemplate()) { |
||||
testTemplateKeys.add(key); |
||||
} |
||||
} |
||||
// 删除测试模板
|
||||
for (String key : testTemplateKeys) { |
||||
removeFromTemplateInfoList(key); |
||||
} |
||||
} |
||||
|
||||
private void removeFromTemplateInfoList(String key) { |
||||
templateInfoMap.remove(key); |
||||
} |
||||
|
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (reader.isChildNode()) { |
||||
try { |
||||
String name = reader.getTagName(); |
||||
if (DesignerOpenHistory.XML_TAG.equals(name)) { |
||||
reader.readXMLObject(designerOpenHistory); |
||||
} else if (TemplateInfo.XML_TAG.equals(name)) { |
||||
TemplateInfo templateInfo = TemplateInfo.newInstanceByRead(reader); |
||||
templateInfoMap.put(templateInfo.getTemplateID(), templateInfo); |
||||
} |
||||
} catch (Exception ex) { |
||||
// 什么也不做,使用默认值
|
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TAG); |
||||
|
||||
designerOpenHistory.writeXML(writer); |
||||
|
||||
writer.startTAG(XML_TEMPLATE_INFO_LIST); |
||||
for (TemplateInfo templateInfo : templateInfoMap.values()) { |
||||
templateInfo.writeXML(writer); |
||||
} |
||||
writer.end(); |
||||
|
||||
writer.end(); |
||||
} |
||||
} |
@ -1,10 +1,14 @@
|
||||
package com.fr.design.mainframe.templateinfo; |
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.base.io.BaseBook; |
||||
|
||||
/** |
||||
* Created by plough on 2017/3/17. |
||||
*/ |
||||
// todo: 重构
|
||||
// 1. 命名不好,表意不清晰。
|
||||
// 2. 逻辑混乱,到底是一个 Info 类,还是一个 InfoCollector 类?
|
||||
// 3. 耦合太强,用组合替代继承
|
||||
public abstract class TemplateProcessInfo<T extends BaseBook> { |
||||
|
||||
protected T template; |
@ -0,0 +1,69 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/19. |
||||
*/ |
||||
public class TimeConsumeTimer { |
||||
private static final int ONE_THOUSAND = 1000; |
||||
private enum State { |
||||
RUNNING, STOPPED |
||||
} |
||||
private int timeConsume; // 单位 s
|
||||
private long startMS; // 单位 ms
|
||||
private long stopMS; |
||||
private State state; |
||||
private boolean enabled; |
||||
|
||||
public TimeConsumeTimer() { |
||||
reset(); |
||||
} |
||||
|
||||
public boolean isEnabled() { |
||||
return enabled; |
||||
} |
||||
|
||||
public void setEnabled(boolean enabled) { |
||||
this.enabled = enabled; |
||||
} |
||||
|
||||
public void start() { |
||||
if (!isEnabled() || isRunning()) { |
||||
return; |
||||
} |
||||
startMS = System.currentTimeMillis(); |
||||
state = State.RUNNING; |
||||
} |
||||
|
||||
public void stop() { |
||||
if (!isEnabled() || !isRunning()) { |
||||
return; |
||||
} |
||||
stopMS = System.currentTimeMillis(); |
||||
|
||||
timeConsume += ((stopMS - startMS) / ONE_THOUSAND); |
||||
startMS = 0; |
||||
stopMS = 0; |
||||
state = State.STOPPED; |
||||
} |
||||
|
||||
public int popTime() { |
||||
if (!isEnabled()) { |
||||
return 0; |
||||
} |
||||
stop(); |
||||
int result = timeConsume; |
||||
reset(); |
||||
return result; |
||||
} |
||||
|
||||
private boolean isRunning() { |
||||
return state == State.RUNNING; |
||||
} |
||||
|
||||
private void reset() { |
||||
timeConsume = 0; |
||||
startMS = 0; |
||||
stopMS = 0; |
||||
state = State.STOPPED; |
||||
} |
||||
} |
@ -1,550 +0,0 @@
|
||||
package com.fr.design.mainframe.templateinfo; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.base.io.BaseBook; |
||||
import com.fr.config.MarketConfig; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.JTemplate; |
||||
import com.fr.design.mainframe.SiteCenterToken; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.general.IOUtils; |
||||
import com.fr.general.http.HttpClient; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.EncodeConstants; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLTools; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
||||
import com.fr.workspace.WorkContext; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.Serializable; |
||||
import java.io.UnsupportedEncodingException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.ArrayList; |
||||
import java.util.Calendar; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 做模板的过程和耗时收集,辅助类 |
||||
* Created by plough on 2017/2/21. |
||||
*/ |
||||
public class TemplateInfoCollector<T extends BaseBook> implements Serializable, XMLReadable, XMLWriter { |
||||
static final long serialVersionUID = 2007L; |
||||
private static final String FILE_NAME = "tpl.info"; |
||||
private static final String OBJECT_FILE_NAME = "tplInfo.ser"; |
||||
private static final int VALID_CELL_COUNT = 5; // 有效报表模板的格子数
|
||||
private static final int VALID_WIDGET_COUNT = 5; // 有效报表模板的控件数
|
||||
private static final int COMPLETE_DAY_COUNT = 15; // 判断模板是否完成的天数
|
||||
private static final int ONE_THOUSAND = 1000; |
||||
private static final String XML_DESIGNER_OPEN_DATE = "DesignerOpenDate"; |
||||
private static final String XML_TEMPLATE_INFO_LIST = "TemplateInfoList"; |
||||
private static final String XML_TEMPLATE_INFO = "TemplateInfo"; |
||||
private static final String XML_PROCESS_MAP = "processMap"; |
||||
private static final String XML_CONSUMING_MAP = "consumingMap"; |
||||
private static final String ATTR_DAY_COUNT = "day_count"; |
||||
private static final String ATTR_TEMPLATE_ID = "templateID"; |
||||
private static final String ATTR_PROCESS = "process"; |
||||
private static final String ATTR_FLOAT_COUNT = "float_count"; |
||||
private static final String ATTR_WIDGET_COUNT = "widget_count"; |
||||
private static final String ATTR_CELL_COUNT = "cell_count"; |
||||
private static final String ATTR_BLOCK_COUNT = "block_count"; |
||||
private static final String ATTR_REPORT_TYPE = "report_type"; |
||||
private static final String ATTR_ACTIVITYKEY = "activitykey"; |
||||
private static final String ATTR_JAR_TIME = "jar_time"; |
||||
private static final String ATTR_CREATE_TIME = "create_time"; |
||||
private static final String ATTR_UUID = "uuid"; |
||||
private static final String ATTR_TIME_CONSUME = "time_consume"; |
||||
private static final String ATTR_VERSION = "version"; |
||||
private static final String ATTR_USERNAME = "username"; |
||||
private static final String JSON_CONSUMING_MAP = "jsonConsumingMap"; |
||||
private static final String JSON_PROCESS_MAP = "jsonProcessMap"; |
||||
private static TemplateInfoCollector instance; |
||||
private Map<String, HashMap<String, Object>> templateInfoList; |
||||
private String designerOpenDate; //设计器最近一次打开日期
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private TemplateInfoCollector() { |
||||
templateInfoList = new HashMap<>(); |
||||
setDesignerOpenDate(); |
||||
} |
||||
|
||||
/** |
||||
* 获取缓存文件存放路径 |
||||
*/ |
||||
private static File getInfoFile() { |
||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), FILE_NAME)); |
||||
} |
||||
|
||||
private static File getObjectInfoFile() { |
||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), OBJECT_FILE_NAME)); |
||||
} |
||||
|
||||
public static TemplateInfoCollector getInstance() { |
||||
if (instance == null) { |
||||
instance = new TemplateInfoCollector(); |
||||
readXMLFile(instance, getInfoFile()); |
||||
// 兼容过渡。如果没有新文件,则从老文件读取数据。以后都是读写新的 xml 文件
|
||||
if (!getInfoFile().exists() && getObjectInfoFile().exists()) { |
||||
try { |
||||
ObjectInputStream is = new ObjectInputStream(new FileInputStream(getObjectInfoFile())); |
||||
instance = (TemplateInfoCollector) is.readObject(); |
||||
} catch (Exception ex) { |
||||
// 什么也不做,instance 使用新值
|
||||
} |
||||
} |
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
private static void readXMLFile(XMLReadable xmlReadable, File xmlFile) { |
||||
if (xmlFile == null || !xmlFile.exists()) { |
||||
return; |
||||
} |
||||
String charset = EncodeConstants.ENCODING_UTF_8; |
||||
try { |
||||
String fileContent = getFileContent(xmlFile); |
||||
InputStream xmlInputStream = new ByteArrayInputStream(fileContent.getBytes(charset)); |
||||
InputStreamReader inputStreamReader = new InputStreamReader(xmlInputStream, charset); |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(inputStreamReader); |
||||
|
||||
if (xmlReader != null) { |
||||
xmlReader.readXMLObject(xmlReadable); |
||||
} |
||||
xmlInputStream.close(); |
||||
} catch (FileNotFoundException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} catch (IOException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} catch (XMLStreamException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static String getFileContent(File xmlFile) throws FileNotFoundException, UnsupportedEncodingException { |
||||
InputStream is = new FileInputStream(xmlFile); |
||||
return IOUtils.inputStream2String(is); |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
TemplateInfoCollector tic = TemplateInfoCollector.getInstance(); |
||||
tic.sendTemplateInfo(); |
||||
} |
||||
|
||||
/** |
||||
* 把设计器最近打开日期设定为当前日期 |
||||
*/ |
||||
private void setDesignerOpenDate() { |
||||
designerOpenDate = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
||||
} |
||||
|
||||
/** |
||||
* 判断今天是否第一次打开设计器 |
||||
*/ |
||||
private boolean designerOpenFirstTime() { |
||||
String today = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
||||
return !ComparatorUtils.equals(today, designerOpenDate); |
||||
} |
||||
|
||||
private boolean shouldCollectInfo() { |
||||
//只收集本地环境的
|
||||
if (!WorkContext.getCurrent().isLocal()) { |
||||
return false; |
||||
} |
||||
return DesignerEnvManager.getEnvManager().isJoinProductImprove() && FRContext.isChineseEnv(); |
||||
} |
||||
|
||||
public void appendProcess(String log) { |
||||
if (!shouldCollectInfo()) { |
||||
return; |
||||
} |
||||
// 获取当前编辑的模板
|
||||
JTemplate jt = DesignerContext.getDesignerFrame().getSelectedJTemplate(); |
||||
// 追加过程记录
|
||||
jt.appendProcess(log); |
||||
} |
||||
|
||||
/** |
||||
* 加载已经存储的模板过程 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public String loadProcess(T t) { |
||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfoList.get(t.getTemplateID()).get(XML_PROCESS_MAP); |
||||
return (String) processMap.get(ATTR_PROCESS); |
||||
} |
||||
|
||||
/** |
||||
* 根据模板ID是否在收集列表中,判断是否需要收集当前模板的信息 |
||||
*/ |
||||
public boolean inList(T t) { |
||||
return templateInfoList.containsKey(t.getTemplateID()); |
||||
} |
||||
|
||||
/** |
||||
* 将包含所有信息的对象保存到文件 |
||||
*/ |
||||
private void saveInfo() { |
||||
try { |
||||
FileOutputStream out = new FileOutputStream(getInfoFile()); |
||||
XMLTools.writeOutputStreamXML(this, out); |
||||
} catch (Exception ex) { |
||||
FineLoggerFactory.getLogger().error(ex.getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 更新 day_count:打开设计器却未编辑模板的连续日子 |
||||
*/ |
||||
private void addDayCount() { |
||||
if (designerOpenFirstTime()) { |
||||
for (String key : templateInfoList.keySet()) { |
||||
HashMap<String, Object> templateInfo = templateInfoList.get(key); |
||||
int dayCount = (int) templateInfo.get(ATTR_DAY_COUNT) + 1; |
||||
templateInfo.put(ATTR_DAY_COUNT, dayCount); |
||||
} |
||||
setDesignerOpenDate(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 收集模板信息。如果之前没有记录,则新增;如果已有记录,则更新。 |
||||
* 同时将最新数据保存到文件中。 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public void collectInfo(T t, JTemplate jt, long openTime, long saveTime) { |
||||
if (!shouldCollectInfo()) { |
||||
return; |
||||
} |
||||
|
||||
HashMap<String, Object> templateInfo; |
||||
|
||||
long timeConsume = ((saveTime - openTime) / ONE_THOUSAND); // 制作模板耗时(单位:s)
|
||||
String templateID = t.getTemplateID(); |
||||
|
||||
if (inList(t)) { // 已有记录
|
||||
templateInfo = templateInfoList.get(templateID); |
||||
// 更新 conusmingMap
|
||||
HashMap<String, Object> consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
||||
timeConsume += (long) consumingMap.get(ATTR_TIME_CONSUME); // 加上之前的累计编辑时间
|
||||
consumingMap.put(ATTR_TIME_CONSUME, timeConsume); |
||||
} else { // 新增
|
||||
templateInfo = new HashMap<>(); |
||||
templateInfo.put(XML_CONSUMING_MAP, getNewConsumingMap(templateID, openTime, timeConsume)); |
||||
} |
||||
|
||||
// 直接覆盖 processMap
|
||||
templateInfo.put(XML_PROCESS_MAP, getProcessMap(templateID, jt)); |
||||
|
||||
// 保存模板时,让 day_count 归零
|
||||
templateInfo.put(ATTR_DAY_COUNT, 0); |
||||
|
||||
templateInfoList.put(templateID, templateInfo); |
||||
|
||||
saveInfo(); // 每次更新之后,都同步到暂存文件中
|
||||
} |
||||
|
||||
private HashMap<String, Object> getNewConsumingMap(String templateID, long openTime, long timeConsume) { |
||||
HashMap<String, Object> consumingMap = new HashMap<>(); |
||||
|
||||
String username = MarketConfig.getInstance().getBbsUsername(); |
||||
String uuid = DesignerEnvManager.getEnvManager().getUUID(); |
||||
String activitykey = DesignerEnvManager.getEnvManager().getActivationKey(); |
||||
String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(Calendar.getInstance().getTime()); |
||||
String jarTime = GeneralUtils.readBuildNO(); |
||||
String version = ProductConstants.VERSION; |
||||
consumingMap.put(ATTR_USERNAME, username); |
||||
consumingMap.put(ATTR_UUID, uuid); |
||||
consumingMap.put(ATTR_ACTIVITYKEY, activitykey); |
||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
consumingMap.put(ATTR_CREATE_TIME, createTime); |
||||
consumingMap.put(ATTR_TIME_CONSUME, timeConsume); |
||||
consumingMap.put(ATTR_JAR_TIME, jarTime); |
||||
consumingMap.put(ATTR_VERSION, version); |
||||
|
||||
return consumingMap; |
||||
} |
||||
|
||||
private HashMap<String, Object> getProcessMap(String templateID, JTemplate jt) { |
||||
HashMap<String, Object> processMap = new HashMap<>(); |
||||
|
||||
processMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
processMap.put(ATTR_PROCESS, jt.getProcess()); |
||||
|
||||
TemplateProcessInfo info = jt.getProcessInfo(); |
||||
processMap.put(ATTR_REPORT_TYPE, info.getReportType()); |
||||
processMap.put(ATTR_CELL_COUNT, info.getCellCount()); |
||||
processMap.put(ATTR_FLOAT_COUNT, info.getFloatCount()); |
||||
processMap.put(ATTR_BLOCK_COUNT, info.getBlockCount()); |
||||
processMap.put(ATTR_WIDGET_COUNT, info.getWidgetCount()); |
||||
|
||||
return processMap; |
||||
} |
||||
|
||||
/** |
||||
* 发送本地模板信息到服务器 |
||||
*/ |
||||
public void sendTemplateInfo() { |
||||
addDayCount(); |
||||
String consumingUrl = CloudCenter.getInstance().acquireUrlByKind("tempinfo.consuming") + "/single"; |
||||
String processUrl = CloudCenter.getInstance().acquireUrlByKind("tempinfo.process") + "/single"; |
||||
ArrayList<HashMap<String, String>> completeTemplatesInfo = getCompleteTemplatesInfo(); |
||||
for (HashMap<String, String> templateInfo : completeTemplatesInfo) { |
||||
String jsonConsumingMap = templateInfo.get(JSON_CONSUMING_MAP); |
||||
String jsonProcessMap = templateInfo.get(JSON_PROCESS_MAP); |
||||
if (sendSingleTemplateInfo(consumingUrl, jsonConsumingMap) && sendSingleTemplateInfo(processUrl, jsonProcessMap)) { |
||||
// 清空记录
|
||||
removeFromTemplateInfoList(templateInfo.get(ATTR_TEMPLATE_ID)); |
||||
} |
||||
} |
||||
saveInfo(); |
||||
} |
||||
|
||||
private boolean sendSingleTemplateInfo(String url, String content) { |
||||
HashMap<String, String> para = new HashMap<>(); |
||||
para.put("token", SiteCenterToken.generateToken()); |
||||
para.put("content", content); |
||||
HttpClient httpClient = new HttpClient(url, para, true); |
||||
httpClient.setTimeout(5000); |
||||
httpClient.asGet(); |
||||
|
||||
if (!httpClient.isServerAlive()) { |
||||
return false; |
||||
} |
||||
|
||||
String res = httpClient.getResponseText(); |
||||
boolean success; |
||||
try { |
||||
success = ComparatorUtils.equals(new JSONObject(res).get("status"), "success"); |
||||
} catch (Exception ex) { |
||||
success = false; |
||||
} |
||||
return success; |
||||
} |
||||
|
||||
/** |
||||
* 返回已完成的模板信息 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
private ArrayList<HashMap<String, String>> getCompleteTemplatesInfo() { |
||||
ArrayList<HashMap<String, String>> completeTemplatesInfo = new ArrayList<>(); |
||||
ArrayList<String> testTemplateKeys = new ArrayList<>(); // 保存测试模板的key
|
||||
for (String key : templateInfoList.keySet()) { |
||||
HashMap<String, Object> templateInfo = templateInfoList.get(key); |
||||
if ((int) templateInfo.get(ATTR_DAY_COUNT) <= COMPLETE_DAY_COUNT) { // 未完成模板
|
||||
continue; |
||||
} |
||||
if (isTestTemplate(templateInfo)) { |
||||
testTemplateKeys.add(key); |
||||
continue; |
||||
} |
||||
HashMap<String, Object> consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
||||
String jsonConsumingMap = new JSONObject(consumingMap).toString(); |
||||
String jsonProcessMap = new JSONObject(processMap).toString(); |
||||
HashMap<String, String> jsonTemplateInfo = new HashMap<>(); |
||||
jsonTemplateInfo.put(JSON_CONSUMING_MAP, jsonConsumingMap); |
||||
jsonTemplateInfo.put(JSON_PROCESS_MAP, jsonProcessMap); |
||||
jsonTemplateInfo.put(ATTR_TEMPLATE_ID, key); |
||||
completeTemplatesInfo.add(jsonTemplateInfo); |
||||
} |
||||
// 删除测试模板
|
||||
for (String key : testTemplateKeys) { |
||||
removeFromTemplateInfoList(key); |
||||
} |
||||
return completeTemplatesInfo; |
||||
} |
||||
|
||||
private void removeFromTemplateInfoList(String key) { |
||||
templateInfoList.remove(key); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private boolean isTestTemplate(HashMap<String, Object> templateInfo) { |
||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
||||
int reportType = (int) processMap.get(ATTR_REPORT_TYPE); |
||||
int cellCount = (int) processMap.get(ATTR_CELL_COUNT); |
||||
int floatCount = (int) processMap.get(ATTR_FLOAT_COUNT); |
||||
int blockCount = (int) processMap.get(ATTR_BLOCK_COUNT); |
||||
int widgetCount = (int) processMap.get(ATTR_WIDGET_COUNT); |
||||
boolean isTestTemplate = false; |
||||
if (reportType == 0) { // 普通报表
|
||||
isTestTemplate = cellCount <= VALID_CELL_COUNT && floatCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
||||
} else if (reportType == 1) { // 聚合报表
|
||||
isTestTemplate = blockCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
||||
} else { // 表单(reportType == 2)
|
||||
isTestTemplate = widgetCount <= 1; |
||||
} |
||||
return isTestTemplate; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (reader.isChildNode()) { |
||||
try { |
||||
String name = reader.getTagName(); |
||||
if (XML_DESIGNER_OPEN_DATE.equals(name)) { |
||||
this.designerOpenDate = reader.getElementValue(); |
||||
} else if (XML_TEMPLATE_INFO_LIST.equals(name)) { |
||||
readTemplateInfoList(reader); |
||||
} |
||||
} catch (Exception ex) { |
||||
// 什么也不做,使用默认值
|
||||
} |
||||
} |
||||
} |
||||
|
||||
private void readTemplateInfoList(XMLableReader reader) { |
||||
reader.readXMLObject(new XMLReadable() { |
||||
public void readXML(XMLableReader reader) { |
||||
if (XML_TEMPLATE_INFO.equals(reader.getTagName())) { |
||||
TemplateInfo templateInfo = new TemplateInfo(); |
||||
reader.readXMLObject(templateInfo); |
||||
templateInfoList.put(templateInfo.getTemplateID(), templateInfo.getTemplateInfo()); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG("TplInfo"); |
||||
|
||||
writer.startTAG(XML_DESIGNER_OPEN_DATE); |
||||
writer.textNode(designerOpenDate); |
||||
writer.end(); |
||||
|
||||
writeTemplateInfoList(writer); |
||||
|
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeTemplateInfoList(XMLPrintWriter writer) { |
||||
//启停
|
||||
writer.startTAG(XML_TEMPLATE_INFO_LIST); |
||||
for (String templateID : templateInfoList.keySet()) { |
||||
new TemplateInfo(templateInfoList.get(templateID)).writeXML(writer); |
||||
} |
||||
writer.end(); |
||||
} |
||||
|
||||
private class TemplateInfo implements XMLReadable, XMLWriter { |
||||
|
||||
private int dayCount; |
||||
private String templateID; |
||||
private HashMap<String, Object> processMap = new HashMap<>(); |
||||
private HashMap<String, Object> consumingMap = new HashMap<>(); |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public TemplateInfo(HashMap<String, Object> templateInfo) { |
||||
this.dayCount = (int) templateInfo.get(ATTR_DAY_COUNT); |
||||
this.processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
||||
this.consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
||||
this.templateID = (String) processMap.get(ATTR_TEMPLATE_ID); |
||||
} |
||||
|
||||
public TemplateInfo() { |
||||
} |
||||
|
||||
public String getTemplateID() { |
||||
return templateID; |
||||
} |
||||
|
||||
public HashMap<String, Object> getTemplateInfo() { |
||||
HashMap<String, Object> templateInfo = new HashMap<>(); |
||||
templateInfo.put(XML_PROCESS_MAP, processMap); |
||||
templateInfo.put(XML_CONSUMING_MAP, consumingMap); |
||||
templateInfo.put(ATTR_DAY_COUNT, dayCount); |
||||
return templateInfo; |
||||
} |
||||
|
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TEMPLATE_INFO); |
||||
if (StringUtils.isNotEmpty(templateID)) { |
||||
writer.attr(ATTR_TEMPLATE_ID, this.templateID); |
||||
} |
||||
if (dayCount >= 0) { |
||||
writer.attr(ATTR_DAY_COUNT, this.dayCount); |
||||
} |
||||
writeProcessMap(writer); |
||||
writeConsumingMap(writer); |
||||
|
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeProcessMap(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_PROCESS_MAP); |
||||
writer.attr(ATTR_PROCESS, (String) processMap.get(ATTR_PROCESS)); |
||||
writer.attr(ATTR_FLOAT_COUNT, (int) processMap.get(ATTR_FLOAT_COUNT)); |
||||
writer.attr(ATTR_WIDGET_COUNT, (int) processMap.get(ATTR_WIDGET_COUNT)); |
||||
writer.attr(ATTR_CELL_COUNT, (int) processMap.get(ATTR_CELL_COUNT)); |
||||
writer.attr(ATTR_BLOCK_COUNT, (int) processMap.get(ATTR_BLOCK_COUNT)); |
||||
writer.attr(ATTR_REPORT_TYPE, (int) processMap.get(ATTR_REPORT_TYPE)); |
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeConsumingMap(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_CONSUMING_MAP); |
||||
writer.attr(ATTR_ACTIVITYKEY, (String) consumingMap.get(ATTR_ACTIVITYKEY)); |
||||
writer.attr(ATTR_JAR_TIME, (String) consumingMap.get(ATTR_JAR_TIME)); |
||||
writer.attr(ATTR_CREATE_TIME, (String) consumingMap.get(ATTR_CREATE_TIME)); |
||||
writer.attr(ATTR_UUID, (String) consumingMap.get(ATTR_UUID)); |
||||
writer.attr(ATTR_TIME_CONSUME, (long) consumingMap.get(ATTR_TIME_CONSUME)); |
||||
writer.attr(ATTR_VERSION, (String) consumingMap.get(ATTR_VERSION)); |
||||
writer.attr(ATTR_USERNAME, (String) consumingMap.get(ATTR_USERNAME)); |
||||
writer.end(); |
||||
} |
||||
|
||||
public void readXML(XMLableReader reader) { |
||||
if (!reader.isChildNode()) { |
||||
dayCount = reader.getAttrAsInt(ATTR_DAY_COUNT, 0); |
||||
templateID = reader.getAttrAsString(ATTR_TEMPLATE_ID, StringUtils.EMPTY); |
||||
} else { |
||||
try { |
||||
String name = reader.getTagName(); |
||||
if (XML_PROCESS_MAP.equals(name)) { |
||||
processMap.put(ATTR_PROCESS, reader.getAttrAsString(ATTR_PROCESS, StringUtils.EMPTY)); |
||||
processMap.put(ATTR_FLOAT_COUNT, reader.getAttrAsInt(ATTR_FLOAT_COUNT, 0)); |
||||
processMap.put(ATTR_WIDGET_COUNT, reader.getAttrAsInt(ATTR_WIDGET_COUNT, 0)); |
||||
processMap.put(ATTR_CELL_COUNT, reader.getAttrAsInt(ATTR_CELL_COUNT, 0)); |
||||
processMap.put(ATTR_BLOCK_COUNT, reader.getAttrAsInt(ATTR_BLOCK_COUNT, 0)); |
||||
processMap.put(ATTR_REPORT_TYPE, reader.getAttrAsInt(ATTR_REPORT_TYPE, 0)); |
||||
processMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
} else if (XML_CONSUMING_MAP.equals(name)) { |
||||
consumingMap.put(ATTR_ACTIVITYKEY, reader.getAttrAsString(ATTR_ACTIVITYKEY, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_JAR_TIME, reader.getAttrAsString(ATTR_JAR_TIME, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_CREATE_TIME, reader.getAttrAsString(ATTR_CREATE_TIME, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
consumingMap.put(ATTR_UUID, reader.getAttrAsString(ATTR_UUID, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_TIME_CONSUME, reader.getAttrAsLong(ATTR_TIME_CONSUME, 0)); |
||||
consumingMap.put(ATTR_VERSION, reader.getAttrAsString(ATTR_VERSION, "8.0")); |
||||
consumingMap.put(ATTR_USERNAME, reader.getAttrAsString(ATTR_USERNAME, StringUtils.EMPTY)); |
||||
} |
||||
} catch (Exception ex) { |
||||
// 什么也不做,使用默认值
|
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,74 @@
|
||||
package com.fr.design.mainframe.vcs; |
||||
|
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
|
||||
/** |
||||
* Created by XiaXiang on 2019/4/26. |
||||
*/ |
||||
public class VcsConfigManager implements XMLReadable, XMLWriter { |
||||
public static final String XML_TAG = "VcsConfigManager"; |
||||
private static volatile VcsConfigManager instance = new VcsConfigManager(); |
||||
private boolean vcsEnable; |
||||
private boolean saveCommit; |
||||
private boolean useInterval; |
||||
private int saveInterval; |
||||
|
||||
public static VcsConfigManager getInstance() { |
||||
return instance; |
||||
} |
||||
|
||||
public boolean isVcsEnable() { |
||||
return vcsEnable; |
||||
} |
||||
|
||||
public void setVcsEnable(boolean vcsEnable) { |
||||
this.vcsEnable = vcsEnable; |
||||
} |
||||
|
||||
public boolean isSaveCommit() { |
||||
return saveCommit; |
||||
} |
||||
|
||||
public void setSaveCommit(boolean saveCommit) { |
||||
this.saveCommit = saveCommit; |
||||
} |
||||
|
||||
public boolean isUseInterval() { |
||||
return useInterval; |
||||
} |
||||
|
||||
public void setUseInterval(boolean useInterval) { |
||||
this.useInterval = useInterval; |
||||
} |
||||
|
||||
public int getSaveInterval() { |
||||
return saveInterval; |
||||
} |
||||
|
||||
public void setSaveInterval(int saveInterval) { |
||||
this.saveInterval = saveInterval; |
||||
} |
||||
|
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (reader.isAttr()) { |
||||
this.setSaveCommit(reader.getAttrAsBoolean("saveCommit", true)); |
||||
this.setSaveInterval(reader.getAttrAsInt("saveInterval", 60)); |
||||
this.setUseInterval(reader.getAttrAsBoolean("useInterval", true)); |
||||
this.setVcsEnable(reader.getAttrAsBoolean("vcsEnable", true)); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TAG); |
||||
writer.attr("saveCommit", this.isSaveCommit()); |
||||
writer.attr("saveInterval", this.getSaveInterval()); |
||||
writer.attr("useInterval", this.isUseInterval()); |
||||
writer.attr("vcsEnable", this.isVcsEnable()); |
||||
writer.end(); |
||||
} |
||||
} |
@ -0,0 +1,71 @@
|
||||
package com.fr.design.mainframe.vcs.common; |
||||
|
||||
import com.fr.base.io.XMLEncryptUtils; |
||||
import com.fr.file.FileNodeFILE; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.resource.WorkResource; |
||||
import com.fr.workspace.resource.WorkResourceOutputStream; |
||||
|
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
|
||||
|
||||
public class VcsCacheFileNodeFile extends FileNodeFILE { |
||||
|
||||
private final FileNode node; |
||||
|
||||
public VcsCacheFileNodeFile(FileNode node) { |
||||
super(node); |
||||
this.node = node; |
||||
} |
||||
|
||||
/** |
||||
* 和FileNodeFILE中一样,只是去掉了必须以reportlets开头的限制,改为vcs开头 |
||||
* |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
@Override |
||||
public InputStream asInputStream() { |
||||
if (node == null) { |
||||
return null; |
||||
} |
||||
|
||||
String envPath = node.getEnvPath(); |
||||
// envPath必须以vcs开头
|
||||
if (!envPath.startsWith(VcsHelper.VCS_CACHE_DIR)) { |
||||
return null; |
||||
} |
||||
|
||||
InputStream in = WorkContext.getCurrent().get(WorkResource.class) |
||||
.openStream(StableUtils.pathJoin(VcsHelper.VCS_CACHE_DIR, envPath.substring(VcsHelper.VCS_CACHE_DIR.length() + 1))); |
||||
|
||||
return envPath.endsWith(".cpt") || envPath.endsWith(".frm") |
||||
? XMLEncryptUtils.decodeInputStream(in) : in; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 和FileNodeFILE中一样,只是去掉了必须以reportlets开头的限制,改为vcs开头 |
||||
* |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
@Override |
||||
public OutputStream asOutputStream() { |
||||
if (ComparatorUtils.equals(node, null)) { |
||||
return null; |
||||
} |
||||
|
||||
String envPath = node.getEnvPath(); |
||||
// envPath必须以reportLets开头
|
||||
if (!envPath.startsWith(VcsHelper.VCS_CACHE_DIR)) { |
||||
return null; |
||||
} |
||||
|
||||
return new WorkResourceOutputStream(StableUtils.pathJoin(VcsHelper.VCS_CACHE_DIR, envPath.substring(VcsHelper.VCS_CACHE_DIR.length() + 1))); |
||||
} |
||||
} |
@ -0,0 +1,147 @@
|
||||
package com.fr.design.mainframe.vcs.common; |
||||
|
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.design.file.HistoryTemplateListCache; |
||||
import com.fr.design.file.TemplateTreePane; |
||||
import com.fr.design.gui.itree.filetree.TemplateFileTree; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.mainframe.DesignerFrameFileDealerPane; |
||||
import com.fr.design.mainframe.JTemplate; |
||||
import com.fr.design.mainframe.vcs.VcsConfigManager; |
||||
import com.fr.design.mainframe.vcs.ui.FileVersionTable; |
||||
import com.fr.general.IOUtils; |
||||
import com.fr.plugin.context.PluginContext; |
||||
import com.fr.plugin.manage.PluginManager; |
||||
import com.fr.report.entity.VcsEntity; |
||||
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.border.EmptyBorder; |
||||
import java.awt.Color; |
||||
import java.util.Date; |
||||
|
||||
import static com.fr.stable.StableUtils.pathJoin; |
||||
|
||||
/** |
||||
* Created by XiaXiang on 2019/4/17. |
||||
*/ |
||||
public class VcsHelper { |
||||
|
||||
private final static String VCS_DIR = "vcs"; |
||||
public final static String VCS_CACHE_DIR = pathJoin(VCS_DIR, "cache"); |
||||
private static final int MINUTE = 60 * 1000; |
||||
private final static String VCS_PLUGIN_ID = "com.fr.plugin.vcs.v10"; |
||||
|
||||
|
||||
public final static String CURRENT_USERNAME = WorkContext.getCurrent().isLocal() |
||||
? Toolkit.i18nText("Fine-Design_Vcs_Local_User") |
||||
: WorkContext.getCurrent().getConnection().getUserName(); |
||||
|
||||
public final static Color TABLE_SELECT_BACKGROUND = new Color(0xD8F2FD); |
||||
public final static Color COPY_VERSION_BTN_COLOR = new Color(0x419BF9); |
||||
|
||||
|
||||
public final static EmptyBorder EMPTY_BORDER = new EmptyBorder(10, 10, 0, 10); |
||||
|
||||
public final static EmptyBorder EMPTY_BORDER_BOTTOM = new EmptyBorder(10, 10, 10, 10); |
||||
|
||||
|
||||
public final static Icon VCS_LIST_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/vcs_list.png"); |
||||
public final static Icon VCS_BACK_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/vcs_back.png"); |
||||
public final static Icon VCS_FILTER_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_filter@1x.png"); |
||||
public final static Icon VCS_EDIT_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_edit.png"); |
||||
public final static Icon VCS_DELETE_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_delete.png"); |
||||
public final static Icon VCS_USER_PNG = IOUtils.readIcon("/com/fr/design/images/vcs/icon_user@1x.png"); |
||||
public final static Icon VCS_REVERT = IOUtils.readIcon("/com/fr/design/images/vcs/icon_revert.png"); |
||||
|
||||
private static int containsFolderCounts() { |
||||
TemplateFileTree fileTree = TemplateTreePane.getInstance().getTemplateFileTree(); |
||||
if (fileTree.getSelectionPaths() == null) { |
||||
return 0; |
||||
} |
||||
|
||||
//选择的包含文件和文件夹的数目
|
||||
if (fileTree.getSelectionPaths().length == 0) { |
||||
return 0; |
||||
} |
||||
//所有的num减去模板的count,得到文件夹的count
|
||||
return fileTree.getSelectionPaths().length - fileTree.getSelectedTemplatePaths().length; |
||||
} |
||||
|
||||
private static int selectedTemplateCounts() { |
||||
TemplateFileTree fileTree = TemplateTreePane.getInstance().getTemplateFileTree(); |
||||
if (fileTree.getSelectionPaths() == null) { |
||||
return 0; |
||||
} |
||||
|
||||
return fileTree.getSelectedTemplatePaths().length; |
||||
} |
||||
|
||||
public static boolean isUnSelectedTemplate() { |
||||
return VcsHelper.containsFolderCounts() + VcsHelper.selectedTemplateCounts() != 1; |
||||
} |
||||
|
||||
public static String getEditingFilename() { |
||||
JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); |
||||
String editingFilePath = jt.getEditingFILE().getPath(); |
||||
if (editingFilePath.startsWith(ProjectConstants.REPORTLETS_NAME)) { |
||||
editingFilePath = editingFilePath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); |
||||
} else if (editingFilePath.startsWith(VcsHelper.VCS_CACHE_DIR)) { |
||||
editingFilePath = editingFilePath.replaceFirst(VcsHelper.VCS_CACHE_DIR, StringUtils.EMPTY); |
||||
} |
||||
if (editingFilePath.startsWith("/")) { |
||||
editingFilePath = editingFilePath.substring(1); |
||||
} |
||||
return editingFilePath; |
||||
} |
||||
|
||||
public static boolean needDeleteVersion(VcsEntity entity) { |
||||
if (entity == null || !DesignerEnvManager.getEnvManager().getVcsConfigManager().isUseInterval()) { |
||||
return false; |
||||
} |
||||
return new Date().getTime() - entity.getTime().getTime() < DesignerEnvManager.getEnvManager().getVcsConfigManager().getSaveInterval() * MINUTE && StringUtils.isBlank(entity.getCommitMsg()); |
||||
} |
||||
|
||||
public static boolean needInit() { |
||||
PluginContext context = PluginManager.getContext(VCS_PLUGIN_ID); |
||||
return context == null || !context.isActive(); |
||||
} |
||||
|
||||
/** |
||||
* 版本控制 |
||||
* @param jt |
||||
*/ |
||||
public static void dealWithVcs(final JTemplate jt) { |
||||
new Thread(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
|
||||
String fileName = VcsHelper.getEditingFilename(); |
||||
VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); |
||||
VcsEntity entity = operator.getFileVersionByIndex(fileName, 0); |
||||
int latestFileVersion = 0; |
||||
if (entity != null) { |
||||
latestFileVersion = entity.getVersion(); |
||||
} |
||||
if (jt.getEditingFILE() instanceof VcsCacheFileNodeFile) { |
||||
operator.saveVersionFromCache(VcsHelper.CURRENT_USERNAME, fileName, StringUtils.EMPTY, latestFileVersion + 1); |
||||
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); |
||||
FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", ""))); |
||||
} else { |
||||
operator.saveVersion(VcsHelper.CURRENT_USERNAME, fileName, StringUtils.EMPTY, latestFileVersion + 1); |
||||
} |
||||
VcsEntity oldEntity = WorkContext.getCurrent().get(VcsOperator.class).getFileVersionByIndex(fileName, 1); |
||||
if (VcsHelper.needDeleteVersion(oldEntity)) { |
||||
operator.deleteVersion(oldEntity.getFilename(), oldEntity.getVersion()); |
||||
} |
||||
|
||||
} |
||||
}).start(); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,99 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.design.dialog.UIDialog; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.icontainer.UIScrollPane; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.gui.itextarea.UITextArea; |
||||
import com.fr.design.layout.TableLayoutHelper; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import com.fr.report.ReportContext; |
||||
import com.fr.report.entity.VcsEntity; |
||||
|
||||
import javax.swing.JPanel; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Component; |
||||
import java.awt.FlowLayout; |
||||
import java.awt.Frame; |
||||
import java.awt.Toolkit; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
|
||||
|
||||
/** |
||||
* 编辑版本信息面板 |
||||
*/ |
||||
public class EditFileVersionDialog extends UIDialog { |
||||
|
||||
private final UITextArea msgTestArea = new UITextArea(); |
||||
private final UILabel versionLabel = new UILabel(); |
||||
private VcsEntity entity; |
||||
|
||||
public EditFileVersionDialog(VcsEntity entity) { |
||||
this(DesignerContext.getDesignerFrame()); |
||||
this.entity = entity; |
||||
msgTestArea.setText(entity.getCommitMsg()); |
||||
versionLabel.setText(String.valueOf(entity.getVersion())); |
||||
} |
||||
|
||||
private EditFileVersionDialog(Frame parent) { |
||||
super(parent); |
||||
|
||||
initComponents(); |
||||
setModal(true); |
||||
setTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Save_Version")); |
||||
setSize(300, 220); |
||||
setResizable(false); |
||||
GUICoreUtils.centerWindow(this); |
||||
|
||||
} |
||||
|
||||
private void initComponents() { |
||||
|
||||
JPanel fontPane = new JPanel(new BorderLayout()); |
||||
fontPane.add(new UILabel(" " + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Version_Message") + ":"), BorderLayout.NORTH); |
||||
|
||||
msgTestArea.setBorder(null); |
||||
UIScrollPane scrollPane = new UIScrollPane(msgTestArea); |
||||
|
||||
Component[][] components = new Component[][]{ |
||||
new Component[]{new UILabel(" " + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Version_Number") + ":"), versionLabel}, |
||||
new Component[]{fontPane, scrollPane} |
||||
}; |
||||
double[] rowSizes = new double[]{25, 100}; |
||||
double[] columnSizes = new double[]{70, 200}; |
||||
|
||||
add(TableLayoutHelper.createTableLayoutPane(components, rowSizes, columnSizes), BorderLayout.CENTER); |
||||
|
||||
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT)); |
||||
add(buttonPane, BorderLayout.SOUTH); |
||||
|
||||
UIButton ok = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_OK")); |
||||
UIButton cancel = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Design_Action_Cancel")); |
||||
|
||||
buttonPane.add(ok); |
||||
buttonPane.add(cancel); |
||||
|
||||
ok.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
entity.setCommitMsg(msgTestArea.getText()); |
||||
ReportContext.getInstance().getVcsController().saveOrUpdateFileVersion(entity); |
||||
setVisible(false); |
||||
} |
||||
}); |
||||
|
||||
cancel.addActionListener(new ActionListener() { |
||||
public void actionPerformed(ActionEvent e) { |
||||
doCancel(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void checkValid() throws Exception { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,74 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.design.file.HistoryTemplateListCache; |
||||
import com.fr.design.file.MutilTempalteTabPane; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.DesignerFrameFileDealerPane; |
||||
import com.fr.design.mainframe.JTemplate; |
||||
import com.fr.design.mainframe.vcs.common.VcsHelper; |
||||
import com.fr.design.mainframe.vcs.common.VcsCacheFileNodeFile; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.report.entity.VcsEntity; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.server.vcs.VcsOperator; |
||||
|
||||
import javax.swing.AbstractCellEditor; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.JTable; |
||||
import javax.swing.table.TableCellEditor; |
||||
import java.awt.Component; |
||||
|
||||
|
||||
public class FileVersionCellEditor extends AbstractCellEditor implements TableCellEditor { |
||||
private static final long serialVersionUID = -7299526575184810693L; |
||||
//第一行
|
||||
private final JPanel firstRowPanel; |
||||
//其余行
|
||||
private final FileVersionRowPanel renderAndEditor; |
||||
|
||||
public FileVersionCellEditor() { |
||||
this.firstRowPanel = new FileVersionFirstRowPanel(); |
||||
this.renderAndEditor = new FileVersionRowPanel(); |
||||
} |
||||
|
||||
@Override |
||||
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { |
||||
String fileOfVersion; |
||||
Component editor = row == 0 ? firstRowPanel : renderAndEditor; |
||||
if (isSelected) { |
||||
return editor; |
||||
} else if (row == 0) { |
||||
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); |
||||
fileOfVersion = WorkContext.getCurrent().get(VcsOperator.class).getFileOfCurrent(path.replaceFirst("/", "")); |
||||
} else { |
||||
renderAndEditor.update((VcsEntity) value); |
||||
fileOfVersion = WorkContext.getCurrent().get(VcsOperator.class).getFileOfFileVersion(((VcsEntity) value).getFilename(), ((VcsEntity) value).getVersion()); |
||||
|
||||
} |
||||
|
||||
editor.setBackground(VcsHelper.TABLE_SELECT_BACKGROUND); |
||||
if (StringUtils.isNotEmpty(fileOfVersion)) { |
||||
//先关闭当前打开的模板版本
|
||||
JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); |
||||
jt.stopEditing(); |
||||
MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); |
||||
MutilTempalteTabPane.getInstance().closeFormat(jt); |
||||
MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jt); |
||||
//再打开cache中的模板
|
||||
DesignerContext.getDesignerFrame().openTemplate(new VcsCacheFileNodeFile(new FileNode(fileOfVersion, false))); |
||||
|
||||
} |
||||
|
||||
double height = editor.getPreferredSize().getHeight(); |
||||
if (table.getRowHeight(row) != height) { |
||||
table.setRowHeight(row, (int) height); |
||||
} |
||||
return editor; |
||||
} |
||||
|
||||
@Override |
||||
public Object getCellEditorValue() { |
||||
return renderAndEditor.getVcsEntity(); |
||||
} |
||||
} |
@ -0,0 +1,43 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.report.entity.VcsEntity; |
||||
|
||||
import javax.swing.JPanel; |
||||
import javax.swing.JTable; |
||||
import javax.swing.table.TableCellRenderer; |
||||
import java.awt.Component; |
||||
|
||||
import static com.fr.design.constants.UIConstants.TREE_BACKGROUND; |
||||
import static com.fr.design.mainframe.vcs.common.VcsHelper.TABLE_SELECT_BACKGROUND; |
||||
|
||||
|
||||
public class FileVersionCellRender implements TableCellRenderer { |
||||
|
||||
//第一行
|
||||
private final JPanel firstRowPanel; |
||||
//其余行
|
||||
private final FileVersionRowPanel render; |
||||
|
||||
public FileVersionCellRender() { |
||||
this.render = new FileVersionRowPanel(); |
||||
this.firstRowPanel = new FileVersionFirstRowPanel(); |
||||
} |
||||
|
||||
@Override |
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { |
||||
Component editor = row == 0 ? firstRowPanel : render; |
||||
// https://stackoverflow.com/questions/3054775/jtable-strange-behavior-from-getaccessiblechild-method-resulting-in-null-point
|
||||
if (value != null) { |
||||
render.update((VcsEntity) value); |
||||
} |
||||
editor.setBackground(isSelected ? TABLE_SELECT_BACKGROUND : TREE_BACKGROUND); |
||||
|
||||
double height = editor.getPreferredSize().getHeight(); |
||||
if (table.getRowHeight(row) != height) { |
||||
table.setRowHeight(row, (int) height); |
||||
} |
||||
return editor; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,94 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.design.dialog.UIDialog; |
||||
import com.fr.design.editor.editor.DateEditor; |
||||
import com.fr.design.gui.date.UIDatePicker; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.gui.itextfield.UITextField; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.mainframe.vcs.common.VcsHelper; |
||||
import com.fr.report.entity.VcsEntity; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.server.vcs.VcsOperator; |
||||
|
||||
import javax.swing.AbstractAction; |
||||
import javax.swing.Box; |
||||
import javax.swing.JPanel; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Dimension; |
||||
import java.awt.FlowLayout; |
||||
import java.awt.Frame; |
||||
import java.awt.Window; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
|
||||
|
||||
public class FileVersionDialog extends UIDialog { |
||||
public static final long DELAY = 24 * 60 * 60 * 1000; |
||||
private UIButton okBtn; |
||||
private UIButton cancelBtn; |
||||
private DateEditor dateEditor; |
||||
private UITextField textField; |
||||
|
||||
|
||||
public FileVersionDialog(Frame frame) { |
||||
super(frame); |
||||
setUndecorated(true); |
||||
setModal(true); |
||||
JPanel panel = new JPanel(new BorderLayout()); |
||||
Box upBox = Box.createHorizontalBox(); |
||||
upBox.setBorder(VcsHelper.EMPTY_BORDER); |
||||
upBox.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_buildTime") + " ")); |
||||
upBox.add(Box.createHorizontalGlue()); |
||||
dateEditor = new DateEditor(new Date(), true, StringUtils.EMPTY, UIDatePicker.STYLE_CN_DATE1); |
||||
upBox.add(dateEditor); |
||||
Box downBox = Box.createHorizontalBox(); |
||||
downBox.setBorder(VcsHelper.EMPTY_BORDER); |
||||
downBox.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_CommitMsg") + " ")); |
||||
textField = new UITextField(); |
||||
downBox.add(textField); |
||||
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT)); |
||||
okBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_OK")); |
||||
cancelBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Design_Action_Cancel")); |
||||
buttonPane.setBorder(VcsHelper.EMPTY_BORDER); |
||||
buttonPane.add(okBtn); |
||||
buttonPane.add(cancelBtn); |
||||
okBtn.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
FileVersionDialog.this.setVisible(false); |
||||
Date date = dateEditor.getValue(); |
||||
List<VcsEntity> vcsEntities = WorkContext.getCurrent().get(VcsOperator.class).getFilterVersions(date, new Date(date.getTime() + DELAY), textField.getText()); |
||||
FileVersionTable.getInstance().updateModel(1, vcsEntities); |
||||
|
||||
} |
||||
}); |
||||
cancelBtn.addActionListener(new AbstractAction() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
FileVersionDialog.this.setVisible(false); |
||||
} |
||||
}); |
||||
panel.add(upBox, BorderLayout.NORTH); |
||||
panel.add(downBox, BorderLayout.CENTER); |
||||
panel.add(buttonPane, BorderLayout.SOUTH); |
||||
add(panel); |
||||
setSize(new Dimension(230, 105)); |
||||
centerWindow(this); |
||||
} |
||||
|
||||
private void centerWindow(Window window) { |
||||
window.setLocation(0, 95); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void checkValid() throws Exception { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,21 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.i18n.Toolkit; |
||||
|
||||
import javax.swing.Box; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.border.EmptyBorder; |
||||
import java.awt.BorderLayout; |
||||
|
||||
|
||||
public class FileVersionFirstRowPanel extends JPanel { |
||||
|
||||
public FileVersionFirstRowPanel() { |
||||
super(new BorderLayout()); |
||||
Box upPane = Box.createVerticalBox(); |
||||
upPane.setBorder(new EmptyBorder(5, 10, 5, 10)); |
||||
upPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Local_User"))); |
||||
add(upPane, BorderLayout.CENTER); |
||||
} |
||||
} |
@ -0,0 +1,150 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.design.gui.frpane.UITextPane; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.mainframe.DesignerFrameFileDealerPane; |
||||
import com.fr.design.mainframe.vcs.common.VcsHelper; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.report.entity.VcsEntity; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.server.vcs.VcsOperator; |
||||
|
||||
import javax.swing.Box; |
||||
import javax.swing.JOptionPane; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.SwingConstants; |
||||
import javax.swing.text.BadLocationException; |
||||
import javax.swing.text.Style; |
||||
import javax.swing.text.StyleConstants; |
||||
import javax.swing.text.StyledDocument; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Color; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Date; |
||||
|
||||
|
||||
public class FileVersionRowPanel extends JPanel { |
||||
|
||||
private VcsEntity vcsEntity; |
||||
private UILabel versionLabel = new UILabel(); |
||||
private UILabel usernameLabel = new UILabel(StringUtils.EMPTY, VcsHelper.VCS_USER_PNG, SwingConstants.LEFT); |
||||
private UITextPane msgLabel = new UITextPane(); |
||||
private UILabel timeLabel = new UILabel(); |
||||
private EditFileVersionDialog editDialog; |
||||
|
||||
|
||||
public FileVersionRowPanel() { |
||||
setLayout(new BorderLayout()); |
||||
|
||||
// version + username
|
||||
Box upPane = Box.createHorizontalBox(); |
||||
upPane.setBorder(VcsHelper.EMPTY_BORDER); |
||||
upPane.add(versionLabel); |
||||
upPane.add(Box.createHorizontalGlue()); |
||||
|
||||
|
||||
// msg
|
||||
msgLabel.setBorder(VcsHelper.EMPTY_BORDER); |
||||
msgLabel.setOpaque(false); |
||||
msgLabel.setBackground(new Color(0, 0, 0, 0)); |
||||
msgLabel.setEditable(false); |
||||
|
||||
// confirm + delete + edit
|
||||
UIButton confirmBtn = new UIButton(VcsHelper.VCS_REVERT); |
||||
confirmBtn.set4ToolbarButton(); |
||||
confirmBtn.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Revert")); |
||||
confirmBtn.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent evt) { |
||||
if (JOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Vcs_Version_Revert_Confirm"), Toolkit.i18nText("Fine-Design_Vcs_Version_Revert_Title"), |
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { |
||||
WorkContext.getCurrent().get(VcsOperator.class).rollbackTo(vcsEntity); |
||||
FileVersionsPanel.getInstance().exitVcs(vcsEntity.getFilename()); |
||||
} |
||||
} |
||||
}); |
||||
UIButton deleteBtn = new UIButton(VcsHelper.VCS_DELETE_PNG); |
||||
deleteBtn.set4ToolbarButton(); |
||||
deleteBtn.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Delete")); |
||||
deleteBtn.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent evt) { |
||||
if (JOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Vcs_Delete-Confirm"), Toolkit.i18nText("Fine-Design_Vcs_Remove"), |
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { |
||||
try { |
||||
WorkContext.getCurrent().get(VcsOperator.class).deleteVersion(vcsEntity.getFilename(), vcsEntity.getVersion()); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage()); |
||||
} |
||||
FileVersionTable table = (FileVersionTable) (FileVersionRowPanel.this.getParent()); |
||||
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); |
||||
try { |
||||
table.updateModel(table.getSelectedRow() - 1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", ""))); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage()); |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
UIButton editBtn = new UIButton(VcsHelper.VCS_EDIT_PNG); |
||||
editBtn.set4ToolbarButton(); |
||||
editBtn.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Edit")); |
||||
editBtn.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
showEditDialog(); |
||||
|
||||
} |
||||
}); |
||||
upPane.add(editBtn); |
||||
upPane.add(confirmBtn); |
||||
upPane.add(deleteBtn); |
||||
Box downPane = Box.createHorizontalBox(); |
||||
downPane.add(usernameLabel); |
||||
downPane.setBorder(VcsHelper.EMPTY_BORDER_BOTTOM); |
||||
downPane.add(Box.createHorizontalGlue()); |
||||
timeLabel.setForeground(VcsHelper.COPY_VERSION_BTN_COLOR); |
||||
downPane.add(timeLabel); |
||||
add(upPane, BorderLayout.NORTH); |
||||
add(msgLabel, BorderLayout.CENTER); |
||||
add(downPane, BorderLayout.SOUTH); |
||||
} |
||||
|
||||
private void showEditDialog() { |
||||
this.editDialog = new EditFileVersionDialog(vcsEntity); |
||||
|
||||
editDialog.setVisible(true); |
||||
update(vcsEntity); |
||||
} |
||||
|
||||
|
||||
public void update(final VcsEntity fileVersion) { |
||||
this.vcsEntity = fileVersion; |
||||
versionLabel.setText(String.format("V.%s", fileVersion.getVersion())); |
||||
usernameLabel.setText(fileVersion.getUsername()); |
||||
msgLabel.setText(StringUtils.EMPTY); |
||||
timeLabel.setText(timeStr(fileVersion.getTime())); |
||||
try { |
||||
StyledDocument doc = msgLabel.getStyledDocument(); |
||||
Style style = msgLabel.getLogicalStyle(); |
||||
StyleConstants.setForeground(style, Color.BLACK); |
||||
doc.insertString(doc.getLength(), " " + fileVersion.getCommitMsg(), style); |
||||
} catch (BadLocationException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
private String timeStr(Date time) { |
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
return simpleDateFormat.format(time); |
||||
} |
||||
|
||||
public VcsEntity getVcsEntity() { |
||||
return vcsEntity; |
||||
} |
||||
} |
@ -0,0 +1,79 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.report.entity.VcsEntity; |
||||
|
||||
import javax.swing.JTable; |
||||
import javax.swing.ListSelectionModel; |
||||
import javax.swing.table.AbstractTableModel; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
|
||||
public class FileVersionTable extends JTable { |
||||
private static volatile FileVersionTable instance; |
||||
|
||||
private FileVersionTable() { |
||||
super(new CellModel(new ArrayList<VcsEntity>())); |
||||
|
||||
setDefaultRenderer(VcsEntity.class, new FileVersionCellRender()); |
||||
setDefaultEditor(VcsEntity.class, new FileVersionCellEditor()); |
||||
setSelectionMode(ListSelectionModel.SINGLE_SELECTION); |
||||
setTableHeader(null); |
||||
setRowHeight(30); |
||||
} |
||||
|
||||
public static FileVersionTable getInstance() { |
||||
if (instance == null) { |
||||
synchronized (FileVersionTable.class) { |
||||
if (instance == null) { |
||||
instance = new FileVersionTable(); |
||||
} |
||||
} |
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
public void updateModel(int selectedRow, List<VcsEntity> entities) { |
||||
if (selectedRow > entities.size()) { |
||||
selectedRow = entities.size(); |
||||
} |
||||
setModel(new CellModel(entities)); |
||||
editCellAt(selectedRow, 0); |
||||
setRowSelectionInterval(selectedRow, selectedRow); |
||||
} |
||||
|
||||
private static class CellModel extends AbstractTableModel { |
||||
private static final long serialVersionUID = -6078568799037607690L; |
||||
private List<VcsEntity> vcsEntities; |
||||
|
||||
|
||||
CellModel(List<VcsEntity> vcsEntities) { |
||||
this.vcsEntities = vcsEntities; |
||||
} |
||||
|
||||
public Class getColumnClass(int columnIndex) { |
||||
return VcsEntity.class; |
||||
} |
||||
|
||||
public int getColumnCount() { |
||||
return 1; |
||||
} |
||||
|
||||
public int getRowCount() { |
||||
return (vcsEntities == null) ? 0 : vcsEntities.size() + 1; |
||||
} |
||||
|
||||
public Object getValueAt(int rowIndex, int columnIndex) { |
||||
if (rowIndex == 0) { |
||||
return null; |
||||
} |
||||
return (vcsEntities == null) ? null : vcsEntities.get(rowIndex - 1); |
||||
} |
||||
|
||||
public boolean isCellEditable(int columnIndex, int rowIndex) { |
||||
return true; |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
@ -0,0 +1,200 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.base.GraphHelper; |
||||
import com.fr.design.base.mode.DesignModeContext; |
||||
import com.fr.design.dialog.BasicPane; |
||||
import com.fr.design.file.HistoryTemplateListCache; |
||||
import com.fr.design.file.MutilTempalteTabPane; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.icontainer.UIScrollPane; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.gui.itoolbar.UIToolbar; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.DesignerFrameFileDealerPane; |
||||
import com.fr.design.mainframe.JTemplate; |
||||
import com.fr.design.mainframe.ToolBarNewTemplatePane; |
||||
import com.fr.design.mainframe.WestRegionContainerPane; |
||||
import com.fr.design.mainframe.vcs.common.VcsHelper; |
||||
import com.fr.design.menu.ToolBarDef; |
||||
import com.fr.file.FileNodeFILE; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.project.ProjectConstants; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.server.vcs.VcsOperator; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.Box; |
||||
import javax.swing.SwingConstants; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Dimension; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
|
||||
|
||||
public class FileVersionsPanel extends BasicPane { |
||||
private static final String ELLIPSIS = "..."; |
||||
private static volatile FileVersionsPanel instance; |
||||
|
||||
private UILabel titleLabel; |
||||
private String templatePath; |
||||
private UIButton filterBtn; |
||||
private FileVersionDialog versionDialog; |
||||
|
||||
|
||||
private FileVersionsPanel() { |
||||
initComponents(); |
||||
} |
||||
|
||||
public static FileVersionsPanel getInstance() { |
||||
if (instance == null) { |
||||
synchronized (FileVersionsPanel.class) { |
||||
if (instance == null) { |
||||
instance = new FileVersionsPanel(); |
||||
} |
||||
} |
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
private void initComponents() { |
||||
setLayout(new BorderLayout()); |
||||
UIToolbar toolbar = ToolBarDef.createJToolBar(); |
||||
toolbar.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0)); |
||||
toolbar.setBorderPainted(true); |
||||
Box upPane = Box.createHorizontalBox(); |
||||
UIButton backBtn = new UIButton(VcsHelper.VCS_BACK_PNG); |
||||
backBtn.set4ToolbarButton(); |
||||
backBtn.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
exitVcs(templatePath); |
||||
} |
||||
}); |
||||
toolbar.add(backBtn); |
||||
filterBtn = new UIButton(VcsHelper.VCS_FILTER_PNG); |
||||
filterBtn.set4ToolbarButton(); |
||||
filterBtn.setHorizontalAlignment(SwingConstants.RIGHT); |
||||
filterBtn.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
showFilterPane(); |
||||
} |
||||
}); |
||||
titleLabel = new UILabel() { |
||||
@Override |
||||
public Dimension getMaximumSize() { |
||||
return new Dimension(257, 21); |
||||
} |
||||
}; |
||||
upPane.add(titleLabel); |
||||
upPane.add(Box.createHorizontalGlue()); |
||||
upPane.add(filterBtn); |
||||
toolbar.add(Box.createHorizontalGlue()); |
||||
toolbar.add(upPane); |
||||
add(toolbar, BorderLayout.NORTH); |
||||
|
||||
UIScrollPane jScrollPane = new UIScrollPane(FileVersionTable.getInstance()); |
||||
add(jScrollPane, BorderLayout.CENTER); |
||||
} |
||||
|
||||
private void showFilterPane() { |
||||
versionDialog = new FileVersionDialog(DesignerContext.getDesignerFrame()); |
||||
versionDialog.setVisible(true); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 退出版本管理,并且打开模板 |
||||
* |
||||
* @param path 被管理的模板的名字 |
||||
*/ |
||||
public void exitVcs(String path) { |
||||
|
||||
// 关闭当前打开的版本
|
||||
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); |
||||
MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); |
||||
MutilTempalteTabPane.getInstance().closeFormat(jt); |
||||
MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jt); |
||||
|
||||
updateDesignerFrame(true); |
||||
|
||||
final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, path); |
||||
DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); |
||||
} |
||||
|
||||
private void refreshVersionTablePane() { |
||||
templatePath = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); |
||||
String[] paths = StableUtils.pathSplit(templatePath); |
||||
String filename = paths[paths.length - 1]; |
||||
int width = FileVersionTable.getInstance().getWidth() - 40; |
||||
if (getStringWidth(filename) > width) { |
||||
filename = getEllipsisName(filename, width); |
||||
} |
||||
titleLabel.setText(filename); |
||||
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); |
||||
FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", ""))); |
||||
} |
||||
|
||||
public void showFileVersionsPane() { |
||||
updateDesignerFrame(false); |
||||
refreshVersionTablePane(); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return null; |
||||
} |
||||
|
||||
|
||||
private void updateDesignerFrame(boolean isExit) { |
||||
// 左上侧面板
|
||||
WestRegionContainerPane.getInstance().replaceUpPane( |
||||
isExit ? DesignerFrameFileDealerPane.getInstance() : this); |
||||
|
||||
DesignModeContext.switchTo(isExit ? com.fr.design.base.mode.DesignerMode.NORMAL : com.fr.design.base.mode.DesignerMode.VCS); |
||||
// MutilTempalteTabPane & NewTemplatePane 是否可点
|
||||
ToolBarNewTemplatePane.getInstance().setButtonGray(!isExit); |
||||
|
||||
JTemplate<?, ?> currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); |
||||
if (currentEditingTemplate.isJWorkBook()) { |
||||
DesignerContext.getDesignerFrame().resetToolkitByPlus(currentEditingTemplate); |
||||
} |
||||
} |
||||
|
||||
|
||||
private int getStringWidth(String str) { |
||||
return GraphHelper.getFontMetrics(this.getFont()).stringWidth(str); |
||||
} |
||||
|
||||
|
||||
private String getEllipsisName(String name, int maxStringlength) { |
||||
|
||||
//若是名字长度大于能显示的长度,那能显示的文字的最大长度还要减去省略号的最大长度
|
||||
// int maxellipsislength = maxStringlength - ELLIPSIS.length();
|
||||
int ellipsisWidth = getStringWidth(ELLIPSIS); |
||||
int leftkeyPoint = 0; |
||||
int rightKeyPoint = name.length() - 1; |
||||
int leftStrWidth = 0; |
||||
int rightStrWidth = 0; |
||||
while (leftStrWidth + rightStrWidth + ellipsisWidth < maxStringlength) { |
||||
if (leftStrWidth <= rightStrWidth) { |
||||
leftkeyPoint++; |
||||
} else { |
||||
rightKeyPoint--; |
||||
} |
||||
leftStrWidth = getStringWidth(name.substring(0, leftkeyPoint)); |
||||
rightStrWidth = getStringWidth(name.substring(rightKeyPoint)); |
||||
|
||||
if (leftStrWidth + rightStrWidth + ellipsisWidth > maxStringlength) { |
||||
if (leftStrWidth <= rightStrWidth) { |
||||
rightKeyPoint++; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return name.substring(0, leftkeyPoint) + ELLIPSIS + name.substring(rightKeyPoint); |
||||
} |
||||
} |
@ -1,9 +1,9 @@
|
||||
package com.fr.design.onlineupdate.actions; |
||||
package com.fr.design.update.actions; |
||||
|
||||
import com.fr.design.onlineupdate.domain.UpdateConstants; |
||||
import com.fr.design.update.domain.UpdateConstants; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.design.onlineupdate.domain.DownloadItem; |
||||
import com.fr.design.update.domain.DownloadItem; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StableUtils; |
||||
|
@ -1,10 +1,9 @@
|
||||
package com.fr.design.onlineupdate.actions; |
||||
package com.fr.design.update.actions; |
||||
|
||||
import com.fr.base.BaseUtils; |
||||
import com.fr.design.actions.UpdateAction; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.onlineupdate.ui.dialog.UpdateMainDialog; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import com.fr.design.update.ui.dialog.UpdateMainDialog; |
||||
|
||||
import java.awt.event.ActionEvent; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.domain; |
||||
package com.fr.design.update.domain; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.json.JSONObject; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.domain; |
||||
package com.fr.design.update.domain; |
||||
|
||||
/** |
||||
* Created by XINZAI on 2018/8/21. |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.domain; |
||||
package com.fr.design.update.domain; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.factory; |
||||
package com.fr.design.update.factory; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.ArrayUtils; |
@ -0,0 +1,61 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
|
||||
/** |
||||
* 持久化与设计器自动推送更新相关的配置 |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { |
||||
public static final String XML_TAG = "DesignerPushUpdateConfigManager"; |
||||
private static DesignerPushUpdateConfigManager singleton; |
||||
|
||||
private boolean autoPushUpdateEnabled = true; // 是否开启自动推送更新
|
||||
private String lastIgnoredVersion = StringUtils.EMPTY; // 最近一次跳过的更新版本
|
||||
|
||||
private DesignerPushUpdateConfigManager() { |
||||
} |
||||
|
||||
public static DesignerPushUpdateConfigManager getInstance() { |
||||
if (singleton == null) { |
||||
singleton = new DesignerPushUpdateConfigManager(); |
||||
} |
||||
return singleton; |
||||
} |
||||
|
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (reader.isAttr()) { |
||||
this.setAutoPushUpdateEnabled(reader.getAttrAsBoolean("autoPushUpdateEnabled", true)); |
||||
this.setLastIgnoredVersion(reader.getAttrAsString("lastIgnoredVersion", StringUtils.EMPTY)); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TAG); |
||||
writer.attr("autoPushUpdateEnabled", autoPushUpdateEnabled); |
||||
writer.attr("lastIgnoredVersion", lastIgnoredVersion); |
||||
writer.end(); |
||||
} |
||||
|
||||
public boolean isAutoPushUpdateEnabled() { |
||||
return autoPushUpdateEnabled; |
||||
} |
||||
|
||||
public void setAutoPushUpdateEnabled(boolean autoPushUpdateEnabled) { |
||||
this.autoPushUpdateEnabled = autoPushUpdateEnabled; |
||||
} |
||||
|
||||
public String getLastIgnoredVersion() { |
||||
return lastIgnoredVersion; |
||||
} |
||||
|
||||
public void setLastIgnoredVersion(String lastIgnoredVersion) { |
||||
this.lastIgnoredVersion = lastIgnoredVersion; |
||||
} |
||||
} |
@ -0,0 +1,190 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.design.dialog.UIDialog; |
||||
import com.fr.design.ui.ModernUIPane; |
||||
import com.fr.design.utils.BrowseUtils; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
import com.fr.intelli.record.FocusPoint; |
||||
import com.fr.intelli.record.MetricRegistry; |
||||
import com.fr.intelli.record.Original; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.web.struct.AssembleComponent; |
||||
import com.fr.web.struct.Atom; |
||||
import com.fr.web.struct.browser.RequestClient; |
||||
import com.fr.web.struct.category.ScriptPath; |
||||
import com.fr.web.struct.category.StylePath; |
||||
import com.fr.web.struct.impl.FineUI; |
||||
|
||||
import javax.swing.JPanel; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Dimension; |
||||
import java.awt.Frame; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/10. |
||||
*/ |
||||
class DesignerPushUpdateDialog extends UIDialog { |
||||
public static final Dimension DEFAULT = new Dimension(640, 360); |
||||
|
||||
private ModernUIPane<Model> jsPane; |
||||
|
||||
private DesignerPushUpdateDialog(Frame parent) { |
||||
super(parent); |
||||
setModal(true); |
||||
initComponents(); |
||||
} |
||||
|
||||
static void createAndShow(Frame parent, DesignerUpdateInfo updateInfo) { |
||||
DesignerPushUpdateDialog dialog = new DesignerPushUpdateDialog(parent); |
||||
dialog.populate(updateInfo); |
||||
dialog.showDialog(); |
||||
} |
||||
|
||||
private void initComponents() { |
||||
JPanel contentPane = (JPanel) getContentPane(); |
||||
contentPane.setLayout(new BorderLayout()); |
||||
|
||||
jsPane = new ModernUIPane.Builder<Model>() |
||||
.withComponent(new AssembleComponent() { |
||||
@Override |
||||
public ScriptPath script(RequestClient req) { |
||||
return ScriptPath.build("/com/fr/design/ui/update/push/pushUpdate.js"); |
||||
} |
||||
|
||||
@Override |
||||
public StylePath style(RequestClient req) { |
||||
return StylePath.build("/com/fr/design/ui/update/push/pushUpdate.css"); |
||||
} |
||||
|
||||
@Override |
||||
public Atom[] refer() { |
||||
return new Atom[]{FineUI.KEY}; |
||||
} |
||||
}).namespace("Pool").build(); |
||||
|
||||
contentPane.add(jsPane); |
||||
} |
||||
|
||||
private void populate(DesignerUpdateInfo updateInfo) { |
||||
Model model = createModel(updateInfo); |
||||
jsPane.populate(model); |
||||
} |
||||
|
||||
private Model createModel(DesignerUpdateInfo updateInfo) { |
||||
Model model = new Model(); |
||||
model.setVersion(updateInfo.getPushVersion()); |
||||
model.setContent(updateInfo.getPushContent()); |
||||
model.setMoreInfoUrl(updateInfo.getMoreInfoUrl()); |
||||
model.setBackgroundUrl(updateInfo.getBackgroundUrl()); |
||||
return model; |
||||
} |
||||
|
||||
@Override |
||||
public void checkValid() throws Exception { |
||||
// do nothing
|
||||
} |
||||
|
||||
/** |
||||
* 显示窗口 |
||||
*/ |
||||
private void showDialog() { |
||||
setSize(DEFAULT); |
||||
setUndecorated(true); |
||||
GUICoreUtils.centerWindow(this); |
||||
setVisible(true); |
||||
} |
||||
|
||||
public class Model { |
||||
private String version; |
||||
private String content; |
||||
private String moreInfoUrl; |
||||
private String backgroundUrl; |
||||
|
||||
public String getVersion() { |
||||
return version; |
||||
} |
||||
|
||||
public void setVersion(String version) { |
||||
this.version = version; |
||||
} |
||||
|
||||
public String getContent() { |
||||
return content; |
||||
} |
||||
|
||||
public void setContent(String content) { |
||||
this.content = content; |
||||
} |
||||
|
||||
public void browseMoreInfoUrl() { |
||||
if (StringUtils.isNotEmpty(moreInfoUrl)) { |
||||
BrowseUtils.browser(moreInfoUrl); |
||||
} |
||||
} |
||||
|
||||
public void setMoreInfoUrl(String moreInfoUrl) { |
||||
this.moreInfoUrl = moreInfoUrl; |
||||
} |
||||
|
||||
public String getBackgroundUrl() { |
||||
return backgroundUrl; |
||||
} |
||||
|
||||
public void setBackgroundUrl(String backgroundUrl) { |
||||
this.backgroundUrl = backgroundUrl; |
||||
} |
||||
|
||||
public void updateNow() { |
||||
DesignerPushUpdateManager.getInstance().doUpdate(); |
||||
FocusPointManager.submit(FocusPointManager.OperateType.UPDATE); |
||||
exit(); |
||||
} |
||||
|
||||
public void remindNextTime() { |
||||
FocusPointManager.submit(FocusPointManager.OperateType.REMIND_NEXT_TIME); |
||||
exit(); |
||||
} |
||||
|
||||
public void skipThisVersion() { |
||||
DesignerPushUpdateManager.getInstance().skipCurrentPushVersion(); |
||||
FocusPointManager.submit(FocusPointManager.OperateType.SKIP); |
||||
exit(); |
||||
} |
||||
|
||||
public void closeWindow() { |
||||
FocusPointManager.submit(FocusPointManager.OperateType.CLOSE_WINDOW); |
||||
exit(); |
||||
} |
||||
|
||||
public String i18nText(String key) { |
||||
return com.fr.design.i18n.Toolkit.i18nText(key); |
||||
} |
||||
|
||||
private void exit() { |
||||
DesignerPushUpdateDialog.this.dialogExit(); |
||||
} |
||||
} |
||||
|
||||
private static class FocusPointManager { |
||||
|
||||
private static final String ID = "com.fr.update.push"; |
||||
private static final String TITLE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Push_Update_Focus_Point"); |
||||
|
||||
private enum OperateType { |
||||
CLOSE_WINDOW(0), UPDATE(1), REMIND_NEXT_TIME(2), SKIP(3); |
||||
private int index; |
||||
OperateType(int index) { |
||||
this.index = index; |
||||
} |
||||
private String toText() { |
||||
return String.valueOf(this.index); |
||||
} |
||||
} |
||||
|
||||
private static void submit(OperateType opType) { |
||||
FocusPoint focusPoint = FocusPoint.create(ID, opType.toText(), Original.EMBED); |
||||
focusPoint.setTitle(TITLE); |
||||
MetricRegistry.getMetric().submit(focusPoint); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,168 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.design.event.DesignerOpenedListener; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.DesignerFrame; |
||||
import com.fr.design.update.ui.dialog.UpdateMainDialog; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.GeneralContext; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.general.http.HttpToolbox; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
public class DesignerPushUpdateManager { |
||||
private static final String SPLIT_CHAR = "-"; |
||||
private static DesignerPushUpdateManager singleton; |
||||
|
||||
private DesignerUpdateInfo updateInfo; |
||||
|
||||
static { |
||||
if (DesignerPushUpdateConfigManager.getInstance().isAutoPushUpdateEnabled()) { |
||||
DesignerContext.getDesignerFrame().addDesignerOpenedListener(new DesignerOpenedListener() { |
||||
@Override |
||||
public void designerOpened() { |
||||
getInstance().checkAndPop(); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
private DesignerPushUpdateManager() { |
||||
} |
||||
|
||||
public static DesignerPushUpdateManager getInstance() { |
||||
if (singleton == null) { |
||||
singleton = new DesignerPushUpdateManager(); |
||||
} |
||||
return singleton; |
||||
} |
||||
|
||||
private void initUpdateInfo(String currentVersion, String latestVersion) { |
||||
String lastIgnoredVersion = DesignerPushUpdateConfigManager.getInstance().getLastIgnoredVersion(); |
||||
String updatePushInfo = CloudCenter.getInstance().acquireUrlByKind("update.push"); |
||||
JSONObject pushData = new JSONObject(updatePushInfo); |
||||
|
||||
updateInfo = new DesignerUpdateInfo(currentVersion, latestVersion, lastIgnoredVersion, pushData); |
||||
} |
||||
|
||||
private String getFullLatestVersion() { |
||||
try { |
||||
String res = HttpToolbox.get(CloudCenter.getInstance().acquireUrlByKind("jar10.update")); |
||||
return new JSONObject(res).optString("buildNO"); |
||||
} catch (Throwable e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return StringUtils.EMPTY; |
||||
} |
||||
|
||||
private String getVersionByFullNO(String fullNO) { |
||||
if (fullNO.contains(SPLIT_CHAR)) { |
||||
fullNO = fullNO.substring(fullNO.lastIndexOf(SPLIT_CHAR) + 1); |
||||
} |
||||
return fullNO; |
||||
} |
||||
|
||||
private String getPrefixByFullNO(String fullNO) { |
||||
if (fullNO.contains(SPLIT_CHAR)) { |
||||
return fullNO.substring(0, fullNO.lastIndexOf(SPLIT_CHAR)); |
||||
} |
||||
return StringUtils.EMPTY; |
||||
} |
||||
|
||||
/** |
||||
* "自动更新推送"选项是否生效 |
||||
*/ |
||||
public boolean isAutoPushUpdateSupported() { |
||||
boolean isLocalEnv = WorkContext.getCurrent().isLocal(); |
||||
boolean isChineseEnv = GeneralContext.isChineseEnv(); |
||||
|
||||
return isAutoPushUpdateSupported(isLocalEnv, isChineseEnv); |
||||
} |
||||
|
||||
private boolean isAutoPushUpdateSupported(boolean isLocalEnv, boolean isChineseEnv) { |
||||
// 远程设计和非中文环境,都不生效
|
||||
return isLocalEnv && isChineseEnv; |
||||
} |
||||
|
||||
/** |
||||
* 检查更新,如果有合适的更新版本,则弹窗 |
||||
*/ |
||||
private void checkAndPop() { |
||||
new Thread() { |
||||
@Override |
||||
public void run() { |
||||
if (!shouldPopUp()) { |
||||
FineLoggerFactory.getLogger().debug("skip push update"); |
||||
return; |
||||
} |
||||
final DesignerFrame designerFrame = DesignerContext.getDesignerFrame(); |
||||
DesignerPushUpdateDialog.createAndShow(designerFrame, updateInfo); |
||||
} |
||||
}.start(); |
||||
} |
||||
|
||||
private boolean shouldPopUp() { |
||||
if (updateInfo == null) { |
||||
String fullCurrentVersion = GeneralUtils.readFullBuildNO(); |
||||
|
||||
String fullLatestVersion = getFullLatestVersion(); |
||||
boolean isValidJarVersion = isValidJarVersion(fullCurrentVersion, fullLatestVersion); |
||||
if (!isValidJarVersion) { |
||||
FineLoggerFactory.getLogger().info("Jar version is not valid for push update."); |
||||
return false; |
||||
} else { |
||||
String currentVersion = getVersionByFullNO(fullCurrentVersion); |
||||
String latestVersion = getVersionByFullNO(fullLatestVersion); |
||||
initUpdateInfo(currentVersion, latestVersion); |
||||
} |
||||
} |
||||
|
||||
return isAutoPushUpdateSupported() && updateInfo.hasNewPushVersion(); |
||||
} |
||||
|
||||
private boolean isValidJarVersion(String fullCurrentVersion, String fullLatestVersion) { |
||||
// todo: 目前设定的逻辑是 feature/release/stable 都弹,且不区分版本号。后期肯定要变的,注释代码先留着
|
||||
// // 无效的情况:
|
||||
// // 1. 版本号格式有误
|
||||
// // 2. 当前用的是 release 或 feature 的 jar 包
|
||||
// // 3. 代码启动的
|
||||
// String prefix = getPrefixByFullNO(fullLatestVersion);
|
||||
// return StringUtils.isNotEmpty(prefix) && fullCurrentVersion.startsWith(prefix);
|
||||
|
||||
// 无效的情况:
|
||||
// 1. 版本号格式有误(正常情况下都有前缀,只有异常的时候才可能出现)
|
||||
// 2. 代码启动的(fullCurrentVersion 为"不是安装版本")
|
||||
String prefix = getPrefixByFullNO(fullLatestVersion); |
||||
return StringUtils.isNotEmpty(prefix) && fullCurrentVersion.contains(SPLIT_CHAR); |
||||
} |
||||
|
||||
/** |
||||
* 跳转到更新升级窗口,并自动开始更新 |
||||
*/ |
||||
void doUpdate() { |
||||
new Thread() { |
||||
@Override |
||||
public void run() { |
||||
UpdateMainDialog dialog = new UpdateMainDialog(DesignerContext.getDesignerFrame()); |
||||
dialog.setAutoUpdateAfterInit(); |
||||
dialog.showDialog(); |
||||
} |
||||
}.start(); |
||||
} |
||||
|
||||
/** |
||||
* 跳过当前的推送版本 |
||||
*/ |
||||
void skipCurrentPushVersion() { |
||||
if (updateInfo == null) { |
||||
return; |
||||
} |
||||
DesignerPushUpdateConfigManager.getInstance().setLastIgnoredVersion(updateInfo.getPushVersion()); |
||||
} |
||||
} |
@ -0,0 +1,91 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import java.security.InvalidParameterException; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
class DesignerUpdateInfo { |
||||
private static final String KEY_VERSION = "version"; |
||||
private static final String KEY_CONTENT = "content"; |
||||
private static final String KEY_BACKGROUND_URL = "background"; |
||||
private static final String KEY_MORE_INFO_URL = "more"; |
||||
|
||||
private final String currentVersion; // 当前版本
|
||||
private final String latestVersion; // 最新版本
|
||||
private final String lastIgnoredVersion; // 最近一次跳过的版本
|
||||
|
||||
private final String pushVersion; // 推送版本
|
||||
private final String pushContent; // 推送更新内容
|
||||
private final String backgroundUrl; // 推送背景图片 url
|
||||
private final String moreInfoUrl; // 更多新特性
|
||||
|
||||
DesignerUpdateInfo(String currentVersion, String latestVersion, String lastIgnoredVersion, JSONObject pushData) { |
||||
this.currentVersion = currentVersion; |
||||
this.latestVersion = latestVersion; |
||||
this.lastIgnoredVersion = lastIgnoredVersion; |
||||
|
||||
this.pushVersion = pushData.optString(KEY_VERSION); |
||||
this.pushContent = pushData.optString(KEY_CONTENT); |
||||
this.backgroundUrl = pushData.optString(KEY_BACKGROUND_URL); |
||||
this.moreInfoUrl = pushData.optString(KEY_MORE_INFO_URL); |
||||
|
||||
// 简单做下参数校验
|
||||
if (hasEmptyField()) { |
||||
throw new InvalidParameterException(); |
||||
} |
||||
} |
||||
|
||||
private boolean hasEmptyField() { |
||||
// lastIgnoredVersion 可以为空
|
||||
return StringUtils.isEmpty(currentVersion) |
||||
|| StringUtils.isEmpty(latestVersion) |
||||
|| StringUtils.isEmpty(pushVersion) |
||||
|| StringUtils.isEmpty(pushContent) |
||||
|| StringUtils.isEmpty(backgroundUrl) |
||||
|| StringUtils.isEmpty(moreInfoUrl); |
||||
} |
||||
|
||||
String getCurrentVersion() { |
||||
return currentVersion; |
||||
} |
||||
|
||||
String getLatestVersion() { |
||||
return latestVersion; |
||||
} |
||||
|
||||
String getLastIgnoredVersion() { |
||||
return lastIgnoredVersion; |
||||
} |
||||
|
||||
String getPushVersion() { |
||||
return pushVersion; |
||||
} |
||||
|
||||
String getPushContent() { |
||||
return pushContent; |
||||
} |
||||
|
||||
String getBackgroundUrl() { |
||||
return backgroundUrl; |
||||
} |
||||
|
||||
String getMoreInfoUrl() { |
||||
return moreInfoUrl; |
||||
} |
||||
|
||||
boolean hasNewPushVersion() { |
||||
boolean result = ComparatorUtils.compare(pushVersion, currentVersion) > 0 |
||||
&& ComparatorUtils.compare(pushVersion, latestVersion) <= 0; |
||||
if (StringUtils.isNotEmpty(lastIgnoredVersion)) { |
||||
result = result && ComparatorUtils.compare(pushVersion, lastIgnoredVersion) > 0; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
} |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.dialog; |
||||
package com.fr.design.update.ui.dialog; |
||||
|
||||
|
||||
import java.io.File; |
@ -1,13 +1,12 @@
|
||||
package com.fr.design.onlineupdate.ui.dialog; |
||||
package com.fr.design.update.ui.dialog; |
||||
|
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.onlineupdate.domain.UpdateConstants; |
||||
import com.fr.design.onlineupdate.factory.DirectoryOperationFactory; |
||||
import com.fr.design.onlineupdate.ui.widget.ColorfulCellRender; |
||||
import com.fr.design.update.domain.UpdateConstants; |
||||
import com.fr.design.update.factory.DirectoryOperationFactory; |
||||
import com.fr.design.update.ui.widget.ColorfulCellRender; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StableUtils; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.JList; |
||||
import javax.swing.JPanel; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.general.IOUtils; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.JTable; |
||||
import javax.swing.table.TableModel; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.stable.StringUtils; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.table.AbstractTableModel; |
||||
import java.util.List; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JTable; |
@ -1,58 +0,0 @@
|
||||
package com.fr.aspectj.designerbase; |
||||
|
||||
/** |
||||
* 记录模板过程 |
||||
* Created by plough on 2017/3/3. |
||||
*/ |
||||
|
||||
import org.aspectj.lang.reflect.SourceLocation; |
||||
|
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
public aspect TemplateProcessTracker { |
||||
//声明一个pointcut,匹配你需要的方法 |
||||
pointcut onMouseClicked(MouseEvent e): |
||||
execution(* mouseClicked(MouseEvent)) && args(e); |
||||
pointcut onMousePressed(MouseEvent e): |
||||
execution(* mousePressed(MouseEvent)) && args(e); |
||||
pointcut onMouseReleased(MouseEvent e): |
||||
execution(* mouseReleased(MouseEvent)) && args(e); |
||||
pointcut onActionPerformed(ActionEvent e): |
||||
execution(* actionPerformed(ActionEvent)) && args(e); |
||||
pointcut onSetValueAt(Object v, int r, int c): |
||||
execution(* setValueAt(java.lang.Object, int, int)) && args(v, r, c); |
||||
|
||||
//before表示之前的意思 |
||||
//这整个表示在MouseAdapter的public void mouseXXX(MouseEvent)方法调用之前,你想要执行的代码 |
||||
before(MouseEvent e): onMouseClicked(e) || onMousePressed(e) || onMouseReleased(e) { |
||||
SourceLocation sl = thisJoinPoint.getSourceLocation();//切面对应的代码位置 |
||||
|
||||
//String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); |
||||
String log = ""; |
||||
//TemplateInfoCollector.appendProcess(log); |
||||
} |
||||
//同上 |
||||
before(ActionEvent e): onActionPerformed(e) { |
||||
SourceLocation sl = thisJoinPoint.getSourceLocation(); |
||||
// !within(LogHandlerBar) 没用, 手动过滤 |
||||
if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { |
||||
return; |
||||
} |
||||
|
||||
//String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); |
||||
String log = ""; |
||||
//TemplateInfoCollector.appendProcess(log); |
||||
|
||||
} |
||||
//同上 |
||||
before(Object v, int r, int c): onSetValueAt(v, r, c) { |
||||
SourceLocation sl = thisJoinPoint.getSourceLocation(); |
||||
|
||||
//String log getSourceLocation= String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); |
||||
String log = ""; |
||||
// TemplateInfoCollector.appendProcess(log); |
||||
} |
||||
|
||||
|
||||
} |
After Width: | Height: | Size: 804 B |
After Width: | Height: | Size: 167 B |
After Width: | Height: | Size: 211 B |
After Width: | Height: | Size: 398 B |
After Width: | Height: | Size: 730 B |
After Width: | Height: | Size: 317 B |
After Width: | Height: | Size: 537 B |
After Width: | Height: | Size: 289 B |
After Width: | Height: | Size: 605 B |
After Width: | Height: | Size: 586 B |
After Width: | Height: | Size: 512 B |
After Width: | Height: | Size: 971 B |
After Width: | Height: | Size: 467 B |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 908 B |
After Width: | Height: | Size: 376 B |
After Width: | Height: | Size: 668 B |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 286 B |
After Width: | Height: | Size: 453 B |
@ -0,0 +1,86 @@
|
||||
body { |
||||
padding-left: 30px; |
||||
padding-top: 30px; |
||||
color: white; |
||||
background-size: 100% 100% !important; |
||||
-moz-background-size: 100% 100% !important; |
||||
} |
||||
|
||||
.close-btn { |
||||
position: fixed !important; |
||||
font-size: 15px !important; |
||||
color: white !important; |
||||
top: 8px; |
||||
right: 10px; |
||||
width: 19px; |
||||
} |
||||
|
||||
.close-btn .b-font { |
||||
height: 19px !important; |
||||
line-height: 19px !important; |
||||
} |
||||
|
||||
.close-btn .b-font:before { |
||||
color: white !important; |
||||
} |
||||
|
||||
.title { |
||||
font-family: PingFangSC-Semibold; |
||||
font-size: 24px; |
||||
letter-spacing: 1.5px; |
||||
line-height: 24px; |
||||
} |
||||
|
||||
.version { |
||||
font-family: PingFangSC-Semibold; |
||||
font-size: 12px; |
||||
line-height: 14px; |
||||
margin-top: 6px; |
||||
} |
||||
|
||||
.desc { |
||||
margin-top: 40px; |
||||
font-family: PingFangSC-Regular; |
||||
font-size: 13px; |
||||
width: 540px; |
||||
margin-left: 19px; |
||||
text-indent: -19px; |
||||
overflow: visible !important; |
||||
} |
||||
|
||||
.desc .bi-label { |
||||
overflow: visible !important; |
||||
} |
||||
|
||||
.moreInfo { |
||||
margin-top: 20px; |
||||
font-family: PingFangSC-Regular; |
||||
font-size: 13px; |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
.buttonGroup { |
||||
position: absolute !important; |
||||
bottom: 60px; |
||||
} |
||||
|
||||
.buttonGroup .bi-button { |
||||
font-family: PingFangSC-Medium; |
||||
font-size: 11px; |
||||
text-align: center; |
||||
line-height: 12px; |
||||
box-shadow: 0 2px 4px 0 rgba(0,82,169,0.20); |
||||
border-radius: 12px; |
||||
} |
||||
|
||||
.buttonGroup .button-ignore { |
||||
background-color: white !important; |
||||
border: 1px solid white !important; |
||||
color: #51A6FF; |
||||
} |
||||
|
||||
.buttonGroup .button-common { |
||||
background-color: #51A6FF !important; |
||||
border: 1px solid #51A6FF !important; |
||||
} |
||||
|
@ -0,0 +1,149 @@
|
||||
var MAX_DESC_NUM = 5; // 最多显示5条信息
|
||||
|
||||
function i18nText(key) { |
||||
return Pool.data.i18nText(key); |
||||
} |
||||
|
||||
function getDescArea(descList) { |
||||
var descItems = []; |
||||
for (var i in descList) { |
||||
var num = parseInt(i) + 1; |
||||
if (num > MAX_DESC_NUM) { |
||||
break; |
||||
} |
||||
descItems.push({ |
||||
type: "bi.label", |
||||
text: num + ")" + descList[i], |
||||
whiteSpace: "pre-wrap", |
||||
textAlign: "left" |
||||
}) |
||||
} |
||||
|
||||
return BI.createWidget({ |
||||
type: "bi.vertical", |
||||
cls: "desc", |
||||
items: descItems |
||||
}); |
||||
} |
||||
|
||||
function getTitleArea() { |
||||
return BI.createWidget({ |
||||
type: "bi.vertical", |
||||
items: [ |
||||
{ |
||||
type: "bi.label", |
||||
text: i18nText("Fine-Design_Find_New_Version"), |
||||
cls: "title", |
||||
textAlign: "left" |
||||
}, |
||||
{ |
||||
type: "bi.label", |
||||
text: Pool.data.getVersion(), |
||||
cls: "version", |
||||
textAlign: "left" |
||||
} |
||||
] |
||||
}); |
||||
} |
||||
|
||||
function getButtonGroup() { |
||||
return BI.createWidget({ |
||||
type: 'bi.left', |
||||
cls: "buttonGroup", |
||||
items: [ |
||||
{ |
||||
type: 'bi.button', |
||||
text: i18nText("Fine-Design_Update_Now"), |
||||
level: 'common', |
||||
height: 24, |
||||
handler: function () { |
||||
Pool.data.updateNow(); |
||||
} |
||||
}, |
||||
{ |
||||
el: { |
||||
type: 'bi.button', |
||||
text: i18nText("Fine-Design_Remind_Me_Next_Time"), |
||||
level: 'ignore', |
||||
height: 24, |
||||
handler: function () { |
||||
Pool.data.remindNextTime(); |
||||
} |
||||
}, |
||||
lgap: 10 |
||||
}, |
||||
{ |
||||
el: { |
||||
type: 'bi.button', |
||||
text: i18nText("Fine-Design_Skip_This_Version"), |
||||
level: 'ignore', |
||||
height: 24, |
||||
handler: function () { |
||||
Pool.data.skipThisVersion(); |
||||
} |
||||
}, |
||||
lgap: 10 |
||||
} |
||||
] |
||||
}); |
||||
} |
||||
|
||||
function getMoreInfo() { |
||||
return BI.createWidget({ |
||||
type: "bi.text_button", |
||||
text: i18nText("Fine-Design_See_More_New_Features"), |
||||
cls: "moreInfo", |
||||
textAlign: "left", |
||||
handler: function () { |
||||
// 为了使用系统的浏览器,只能从 Java 那边打开网页
|
||||
Pool.data.browseMoreInfoUrl(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function getCloseButton() { |
||||
return BI.createWidget({ |
||||
type: "bi.button", |
||||
text: "", |
||||
iconCls: "close-font", |
||||
cls: "close-btn", |
||||
clear: true, |
||||
handler: function () { |
||||
Pool.data.closeWindow(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function getShowItems() { |
||||
var title = getTitleArea(); |
||||
|
||||
var closeButton = getCloseButton(); |
||||
|
||||
var descList = Pool.data.getContent().split("\n"); |
||||
var descArea = getDescArea(descList); |
||||
|
||||
var moreInfo = getMoreInfo(); |
||||
|
||||
var buttonGroup = getButtonGroup(); |
||||
|
||||
var showItems = [title, closeButton, descArea]; |
||||
if (descList.length > MAX_DESC_NUM) { |
||||
showItems.push(moreInfo); |
||||
} |
||||
showItems.push(buttonGroup); |
||||
|
||||
return showItems; |
||||
} |
||||
|
||||
window.addEventListener("load", function (ev) { |
||||
var showItems = getShowItems(); |
||||
|
||||
var container = BI.createWidget({ |
||||
type:"bi.vertical", |
||||
element: "body", |
||||
cls: "container", |
||||
items: showItems |
||||
}); |
||||
|
||||
container.element.css("background", "url(" + Pool.data.getBackgroundUrl() + ")"); |
||||
}); |
@ -0,0 +1,108 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.invoke.Reflect; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
import java.io.PrintWriter; |
||||
import java.io.StringReader; |
||||
import java.io.StringWriter; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Calendar; |
||||
|
||||
import static org.junit.Assert.assertArrayEquals; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertTrue; |
||||
import static org.junit.Assert.fail; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/21. |
||||
*/ |
||||
public class DesignerOpenHistoryTest { |
||||
private DesignerOpenHistory openHistory; |
||||
private String[] mockHistory = new String[] { |
||||
"2019-04-08", "2019-04-03", "2019-03-29" |
||||
}; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
openHistory = DesignerOpenHistory.getInstance(); |
||||
Reflect.on(openHistory).set("history", mockHistory); |
||||
} |
||||
|
||||
@Test |
||||
public void testReadAndWrite() throws XMLStreamException { |
||||
// 写入 xml
|
||||
StringWriter sw = new StringWriter(); |
||||
XMLPrintWriter writer = XMLPrintWriter.create(new PrintWriter(sw)); |
||||
openHistory.writeXML(writer); |
||||
writer.flush(); |
||||
writer.close(); |
||||
|
||||
String xmlText = sw.getBuffer().toString(); |
||||
|
||||
// 临时修改配置
|
||||
Reflect.on(openHistory).set("history", new String[] {"", "", ""}); |
||||
|
||||
// 从 xml 中读取
|
||||
StringReader sr = new StringReader(xmlText); |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(sr); |
||||
xmlReader.readXMLObject(openHistory); |
||||
|
||||
// 验证:与写入时的配置一致
|
||||
assertArrayEquals(mockHistory, (String[])Reflect.on(openHistory).field("history").get()); |
||||
} |
||||
|
||||
@Test |
||||
public void testToString() { |
||||
assertEquals("2019-04-08,2019-04-03,2019-03-29", openHistory.toString()); |
||||
} |
||||
|
||||
@Test |
||||
public void testParseString() { |
||||
String[] mockDates = {"2020-04-08", "2019-04-03", "2016-03-29"}; |
||||
Reflect.on(openHistory).call("parseString", StringUtils.join(",", mockDates)); |
||||
assertArrayEquals(mockDates, (String[])Reflect.on(openHistory).field("history").get()); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetHistorySpanDayCount() { |
||||
assertEquals(11, openHistory.getHistorySpanDayCount()); |
||||
|
||||
Reflect.on(openHistory).set("history", new String[] {"2019-05-03", "2019-05-02", ""}); |
||||
assertEquals(2, openHistory.getHistorySpanDayCount()); |
||||
|
||||
Reflect.on(openHistory).set("history", new String[] {"2019-05-03", "", ""}); |
||||
assertEquals(1, openHistory.getHistorySpanDayCount()); |
||||
|
||||
try { |
||||
Reflect.on(openHistory).set("history", new String[] {"", "", ""}); |
||||
fail("should not be here"); |
||||
} catch (AssertionError ignore) { |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testHasOpenedToday() { |
||||
assertFalse(openHistory.hasOpenedToday()); |
||||
|
||||
Reflect.on(openHistory).set("history", new String[] {getToday(), "2019-02-02", ""}); |
||||
assertTrue(openHistory.hasOpenedToday()); |
||||
} |
||||
|
||||
@Test |
||||
public void testUpdate() { |
||||
openHistory.update(); |
||||
String[] arr = { getToday(), "2019-04-08", "2019-04-03" }; |
||||
assertArrayEquals(arr, (String[])Reflect.on(openHistory).field("history").get()); |
||||
} |
||||
|
||||
private String getToday() { |
||||
return new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.invoke.Reflect; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
||||
|
||||
import java.io.StringReader; |
||||
|
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/25. |
||||
*/ |
||||
public class SendHelperTest { |
||||
private static final String CONSUMING_URL = "http://cloud.fanruan.com/api/monitor/record_of_reports_consuming/single"; |
||||
private static final String PROCESS_URL = "http://cloud.fanruan.com/api/monitor/record_of_reports_process/single"; |
||||
|
||||
private static final String NORMAL_INFO = "<TemplateInfo templateID=\"16a988ce-8529-42f5-b17c-2ee849355071\" day_count=\"9\">\n" + |
||||
"<processMap process=\"\" float_count=\"0\" widget_count=\"0\" cell_count=\"1\" block_count=\"0\" report_type=\"0\"/>\n" + |
||||
"<consumingMap activitykey=\"2e0ea413-fa9c241e0-9723-4354fce51e81\" jar_time=\"不是安装版本\" create_time=\"2019-03-26 16:13\" uuid=\"476ca2cc-f789-4c5d-8e89-ef146580775c\" time_consume=\"129\" version=\"10.0\" username=\"plough\"/>\n" + |
||||
"</TemplateInfo>"; |
||||
|
||||
// 只在调试的时候运行,不需要每次都自动运行
|
||||
public static void main(String[] args) throws XMLStreamException { |
||||
StringReader sr = new StringReader(NORMAL_INFO); |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(sr); |
||||
TemplateInfo templateInfo = TemplateInfo.newInstanceByRead(xmlReader); |
||||
|
||||
boolean res = Reflect.on(SendHelper.class).call("sendSingleTemplateInfo", CONSUMING_URL, templateInfo.getConsumingMapJsonString()).get(); |
||||
assertTrue(res); |
||||
|
||||
boolean res2 = Reflect.on(SendHelper.class).call("sendSingleTemplateInfo", PROCESS_URL, templateInfo.getProcessMapJsonString()).get(); |
||||
assertTrue(res2); |
||||
} |
||||
} |
@ -0,0 +1,195 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.config.MarketConfig; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.invoke.Reflect; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.org.apache.commons.io.FileUtils; |
||||
import org.easymock.EasyMock; |
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.powermock.api.easymock.PowerMock; |
||||
import org.powermock.core.classloader.annotations.PrepareForTest; |
||||
import org.powermock.modules.junit4.PowerMockRunner; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
import static com.fr.design.mainframe.template.info.TemplateInfoTestHelper.assertJsonStringEquals; |
||||
import static com.fr.design.mainframe.template.info.TemplateInfoTestHelper.setUpMockForNewInstance; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/18. |
||||
*/ |
||||
@RunWith(PowerMockRunner.class) |
||||
@PrepareForTest({ProductConstants.class, MarketConfig.class, ProductConstants.class, GeneralUtils.class}) |
||||
public class TemplateInfoCollectorTest { |
||||
private String filePath; |
||||
private String initialFileContent; |
||||
private TemplateProcessInfo mockProcessInfo; |
||||
|
||||
@Before |
||||
public void setUp() throws IOException { |
||||
PowerMock.mockStatic(ProductConstants.class); |
||||
|
||||
filePath = getClass().getResource("tpl.info").getPath(); |
||||
String dirPath = filePath.substring(0, filePath.indexOf("tpl.info")); |
||||
EasyMock.expect(ProductConstants.getEnvHome()).andReturn(dirPath).anyTimes(); |
||||
EasyMock.replay(); |
||||
PowerMock.replayAll(); |
||||
|
||||
mockProcessInfo = EasyMock.mock(TemplateProcessInfo.class); |
||||
EasyMock.expect(mockProcessInfo.getBlockCount()).andReturn(3).anyTimes(); |
||||
EasyMock.expect(mockProcessInfo.getCellCount()).andReturn(13).anyTimes(); |
||||
EasyMock.expect(mockProcessInfo.getFloatCount()).andReturn(1).anyTimes(); |
||||
EasyMock.expect(mockProcessInfo.getReportType()).andReturn(0).anyTimes(); |
||||
EasyMock.expect(mockProcessInfo.getWidgetCount()).andReturn(0).anyTimes(); |
||||
EasyMock.replay(mockProcessInfo); |
||||
|
||||
// 缓存 tpl.info
|
||||
initialFileContent = FileUtils.readFileToString(new File(filePath), "utf-8"); |
||||
|
||||
Reflect.on(TemplateInfoCollector.class).set("instance", null); |
||||
} |
||||
|
||||
@After |
||||
public void tearDown() throws IOException { |
||||
// 恢复 tpl.info
|
||||
FileUtils.writeStringToFile(new File(filePath), initialFileContent, "utf-8"); |
||||
} |
||||
|
||||
@Test |
||||
public void testReadXML() { |
||||
assertEquals(",,", DesignerOpenHistory.getInstance().toString()); |
||||
|
||||
TemplateInfoCollector collector = TemplateInfoCollector.getInstance(); |
||||
assertEquals(7, ((Map) Reflect.on(collector).field("templateInfoMap").get()).size()); |
||||
|
||||
assertEquals("2019-04-08,2019-04-03,2019-03-29", DesignerOpenHistory.getInstance().toString()); |
||||
} |
||||
|
||||
@Test |
||||
public void testCollectInfo() { |
||||
TemplateInfoCollector collector = TemplateInfoCollector.getInstance(); |
||||
|
||||
String templateID = "16a988ce-8529-42f5-b17c-2ee849355071"; |
||||
int timeConsume = 200; |
||||
|
||||
collector.collectInfo(templateID, StringUtils.EMPTY, mockProcessInfo, timeConsume); |
||||
|
||||
// 检查是否写入成功
|
||||
collector.loadFromFile(); |
||||
TemplateInfo templateInfo = collector.getOrCreateTemplateInfoByID(templateID); |
||||
|
||||
assertJsonStringEquals("{\"process\":\"\",\"float_count\":1,\"widget_count\":0," + |
||||
"\"cell_count\":13,\"block_count\":3,\"report_type\":0," + |
||||
"\"templateID\":\"16a988ce-8529-42f5-b17c-2ee849355071\"}",templateInfo.getProcessMapJsonString()); |
||||
|
||||
assertJsonStringEquals("{\"activitykey\":\"2e0ea413-fa9c241e0-9723-4354fce51e81\"," + |
||||
"\"jar_time\":\"不是安装版本\",\"create_time\":\"2019-03-26 16:13\"," + |
||||
"\"templateID\":\"16a988ce-8529-42f5-b17c-2ee849355071\",\"originID\":\"\"," + |
||||
"\"uuid\":\"476ca2cc-f789-4c5d-8e89-ef146580775c\",\"time_consume\":329,\"originTime\":0," + |
||||
"\"version\":\"10.0\",\"username\":\"plough\"}", templateInfo.getConsumingMapJsonString()); |
||||
} |
||||
|
||||
@Test |
||||
public void testCollectInfoForNewTemplate() throws Exception { |
||||
setUpMockForNewInstance(); |
||||
|
||||
TemplateInfoCollector collector = TemplateInfoCollector.getInstance(); |
||||
|
||||
String templateID = "73a97777-8jnk-47cd-b57c-2ee89991279796"; |
||||
int timeConsume = 200; |
||||
|
||||
collector.collectInfo(templateID, StringUtils.EMPTY, mockProcessInfo, timeConsume); |
||||
|
||||
// 检查是否写入成功
|
||||
collector.loadFromFile(); |
||||
assertTrue(collector.contains(templateID)); |
||||
|
||||
TemplateInfo templateInfo = collector.getOrCreateTemplateInfoByID(templateID); |
||||
assertEquals(templateID, templateInfo.getTemplateID()); |
||||
|
||||
assertJsonStringEquals("{\"process\":\"\",\"float_count\":1,\"widget_count\":0," + |
||||
"\"cell_count\":13,\"block_count\":3,\"report_type\":0," + |
||||
"\"templateID\":\"73a97777-8jnk-47cd-b57c-2ee89991279796\"}",templateInfo.getProcessMapJsonString()); |
||||
|
||||
Map<String, Object> consumingMap = Reflect.on(templateInfo).field("consumingMap").get(); |
||||
assertEquals(templateID, consumingMap.get("templateID")); |
||||
assertEquals(StringUtils.EMPTY, consumingMap.get("originID")); |
||||
assertEquals(200, consumingMap.get("time_consume")); |
||||
assertEquals(0, consumingMap.get("originTime")); |
||||
} |
||||
|
||||
@Test |
||||
public void testCollectInfoWhenSaveAs() throws Exception { |
||||
setUpMockForNewInstance(); |
||||
|
||||
TemplateInfoCollector collector = TemplateInfoCollector.getInstance(); |
||||
|
||||
String templateID = "423238d4-5223-22vj-vlsj-42jc49245iw3"; |
||||
String originID = "16a988ce-8529-42f5-b17c-2ee849355071"; |
||||
int timeConsume = 200; |
||||
|
||||
collector.collectInfo(templateID, originID, mockProcessInfo, timeConsume); |
||||
|
||||
// 检查是否写入成功
|
||||
collector.loadFromFile(); |
||||
TemplateInfo templateInfo = collector.getOrCreateTemplateInfoByID(templateID); |
||||
|
||||
assertJsonStringEquals("{\"process\":\"\",\"float_count\":1,\"widget_count\":0," + |
||||
"\"cell_count\":13,\"block_count\":3,\"report_type\":0," + |
||||
"\"templateID\":\"423238d4-5223-22vj-vlsj-42jc49245iw3\"}", templateInfo.getProcessMapJsonString()); |
||||
|
||||
Map<String, Object> consumingMap = Reflect.on(templateInfo).field("consumingMap").get(); |
||||
assertEquals(templateID, consumingMap.get("templateID")); |
||||
assertEquals(originID, consumingMap.get("originID")); |
||||
assertEquals(329, consumingMap.get("time_consume")); |
||||
assertEquals(129, consumingMap.get("originTime")); |
||||
} |
||||
|
||||
@Test |
||||
public void testCollectInfoWhenSaveAsWithNoTrackOriginID() throws Exception { |
||||
setUpMockForNewInstance(); |
||||
|
||||
TemplateInfoCollector collector = TemplateInfoCollector.getInstance(); |
||||
|
||||
String templateID = "423238d4-5223-22vj-vlsj-42jc49245iw3"; |
||||
String originID = "3kha8jcs-31xw-42f5-h2ww-2ee84935312z"; |
||||
int timeConsume = 200; |
||||
|
||||
collector.collectInfo(templateID, originID, mockProcessInfo, timeConsume); |
||||
|
||||
TemplateInfo templateInfo = collector.getOrCreateTemplateInfoByID(templateID); |
||||
assertEquals(templateID, templateInfo.getTemplateID()); |
||||
assertEquals(originID, templateInfo.getOriginID()); |
||||
|
||||
Map<String, Object> consumingMap = Reflect.on(templateInfo).field("consumingMap").get(); |
||||
assertEquals(templateID, consumingMap.get("templateID")); |
||||
assertEquals(originID, consumingMap.get("originID")); |
||||
assertEquals(200, consumingMap.get("time_consume")); |
||||
assertEquals(0, consumingMap.get("originTime")); |
||||
} |
||||
|
||||
@Test |
||||
public void testAddIdleDateCount() { |
||||
String templateID = "16a988ce-8529-42f5-b17c-2ee849355071"; |
||||
TemplateInfoCollector collecter = TemplateInfoCollector.getInstance(); |
||||
TemplateInfo templateInfo = collecter.getOrCreateTemplateInfoByID(templateID); |
||||
|
||||
assertEquals(9, templateInfo.getIdleDayCount()); |
||||
|
||||
Reflect.on(collecter).call("addIdleDayCount"); |
||||
assertEquals(10, templateInfo.getIdleDayCount()); |
||||
|
||||
// 同一天内多次调用无效
|
||||
Reflect.on(collecter).call("addIdleDayCount"); |
||||
assertEquals(10, templateInfo.getIdleDayCount()); |
||||
} |
||||
} |
@ -0,0 +1,125 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.config.MarketConfig; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.invoke.Reflect; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.powermock.core.classloader.annotations.PrepareForTest; |
||||
import org.powermock.modules.junit4.PowerMockRunner; |
||||
|
||||
import java.io.StringReader; |
||||
import java.util.Map; |
||||
|
||||
import static com.fr.design.mainframe.template.info.TemplateInfoTestHelper.assertJsonStringEquals; |
||||
import static com.fr.design.mainframe.template.info.TemplateInfoTestHelper.setUpMockForNewInstance; |
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/19. |
||||
*/ |
||||
@RunWith(PowerMockRunner.class) |
||||
@PrepareForTest({MarketConfig.class, ProductConstants.class, GeneralUtils.class}) |
||||
public class TemplateInfoTest { |
||||
|
||||
private static final String NORMAL_INFO = "<TemplateInfo templateID=\"16a988ce-8529-42f5-b17c-2ee849355071\" day_count=\"9\">\n" + |
||||
"<processMap process=\"\" float_count=\"0\" widget_count=\"0\" cell_count=\"1\" block_count=\"0\" report_type=\"0\"/>\n" + |
||||
"<consumingMap activitykey=\"2e0ea413-fa9c241e0-9723-4354fce51e81\" jar_time=\"不是安装版本\" create_time=\"2019-03-26 16:13\" uuid=\"476ca2cc-f789-4c5d-8e89-ef146580775c\" time_consume=\"129\" version=\"10.0\" username=\"plough\"/>\n" + |
||||
"</TemplateInfo>"; |
||||
|
||||
private static final String SAVE_AS_INFO = "<TemplateInfo templateID=\"49avd2c4-1104-92j2-wx24-3dd0k2136080\" originID=\"16a988ce-8529-42f5-b17c-2ee849355071\" day_count=\"9\">\n" + |
||||
"<processMap process=\"\" float_count=\"0\" widget_count=\"0\" cell_count=\"1\" block_count=\"0\" report_type=\"0\"/>\n" + |
||||
"<consumingMap activitykey=\"2e0ea413-fa9c241e0-9723-4354fce51e81\" jar_time=\"不是安装版本\" create_time=\"2019-03-26 16:13\" uuid=\"476ca2cc-f789-4c5d-8e89-ef146580775c\" time_consume=\"429\" originTime=\"129\" version=\"10.0\" username=\"plough\"/>\n" + |
||||
"</TemplateInfo>"; |
||||
|
||||
private TemplateInfo templateInfo; |
||||
private TemplateInfo templateInfoSaveAs; // 另存为的模版记录
|
||||
|
||||
@Before |
||||
public void setUp() throws XMLStreamException { |
||||
templateInfo = createTemplateInfo(NORMAL_INFO); |
||||
templateInfoSaveAs = createTemplateInfo(SAVE_AS_INFO); |
||||
} |
||||
|
||||
@Test |
||||
public void testNewInstance() throws Exception { |
||||
setUpMockForNewInstance(); |
||||
|
||||
String templateID = "24avc8n2-1iq8-iuj2-wx24-8yy0i8132302"; |
||||
TemplateInfo templateInfo = TemplateInfo.newInstance(templateID); |
||||
assertEquals(templateID, templateInfo.getTemplateID()); |
||||
assertEquals(StringUtils.EMPTY, Reflect.on(templateInfo).field("originID").get()); |
||||
assertEquals(0, Reflect.on(templateInfo).field("idleDayCount").get()); |
||||
assertEquals("{}", templateInfo.getProcessMapJsonString()); |
||||
|
||||
Map<String, Object> consumingMap = Reflect.on(templateInfo).field("consumingMap").get(); |
||||
assertEquals(templateID, consumingMap.get("templateID")); |
||||
assertEquals(0, consumingMap.get("originTime")); |
||||
assertEquals(StringUtils.EMPTY, consumingMap.get("originID")); |
||||
assertEquals(0, consumingMap.get("time_consume")); |
||||
assertEquals("不是安装版本", consumingMap.get("jar_time")); |
||||
assertEquals("plough", consumingMap.get("username")); |
||||
assertEquals("10.0", consumingMap.get("version")); |
||||
} |
||||
|
||||
@Test |
||||
public void testNewInstanceWithMoreArgs() throws Exception { |
||||
setUpMockForNewInstance(); |
||||
|
||||
String templateID = "24121212-u2c8-ncd2-82nx-8ud0i8138888"; |
||||
String originID = "24avc8n2-1iq8-iuj2-wx24-8yy0i8132302"; |
||||
int originTime = 100; |
||||
TemplateInfo templateInfo = TemplateInfo.newInstance(templateID, originID, originTime); |
||||
assertEquals(templateID, templateInfo.getTemplateID()); |
||||
assertEquals(originID, Reflect.on(templateInfo).field("originID").get()); |
||||
assertEquals(0, Reflect.on(templateInfo).field("idleDayCount").get()); |
||||
assertEquals("{}", templateInfo.getProcessMapJsonString()); |
||||
|
||||
Map<String, Object> consumingMap = Reflect.on(templateInfo).field("consumingMap").get(); |
||||
assertEquals(templateID, consumingMap.get("templateID")); |
||||
assertEquals(originTime, consumingMap.get("originTime")); |
||||
assertEquals(originID, consumingMap.get("originID")); |
||||
assertEquals(originTime, consumingMap.get("time_consume")); |
||||
assertEquals("不是安装版本", consumingMap.get("jar_time")); |
||||
assertEquals("plough", consumingMap.get("username")); |
||||
assertEquals("10.0", consumingMap.get("version")); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetTemplateID() { |
||||
assertEquals("16a988ce-8529-42f5-b17c-2ee849355071", templateInfo.getTemplateID()); |
||||
assertEquals("49avd2c4-1104-92j2-wx24-3dd0k2136080", templateInfoSaveAs.getTemplateID()); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetConsumingMapJsonString() { |
||||
assertJsonStringEquals("{\"activitykey\":\"2e0ea413-fa9c241e0-9723-4354fce51e81\",\"jar_time\":\"不是安装版本\"," + |
||||
"\"create_time\":\"2019-03-26 16:13\",\"templateID\":\"16a988ce-8529-42f5-b17c-2ee849355071\",\"originID\":\"\"," + |
||||
"\"uuid\":\"476ca2cc-f789-4c5d-8e89-ef146580775c\",\"time_consume\":129,\"originTime\":0,\"version\":\"10.0\"," + |
||||
"\"username\":\"plough\"}", templateInfo.getConsumingMapJsonString()); |
||||
|
||||
assertJsonStringEquals("{\"activitykey\":\"2e0ea413-fa9c241e0-9723-4354fce51e81\",\"jar_time\":\"不是安装版本\"," + |
||||
"\"create_time\":\"2019-03-26 16:13\",\"templateID\":\"49avd2c4-1104-92j2-wx24-3dd0k2136080\",\"originID\":\"16a988ce-8529-42f5-b17c-2ee849355071\"," + |
||||
"\"uuid\":\"476ca2cc-f789-4c5d-8e89-ef146580775c\",\"time_consume\":429,\"originTime\":129,\"version\":\"10.0\"," + |
||||
"\"username\":\"plough\"}", templateInfoSaveAs.getConsumingMapJsonString()); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetProcessMapJsonString() { |
||||
assertJsonStringEquals("{\"process\":\"\",\"float_count\":0,\"widget_count\":0,\"cell_count\":1," + |
||||
"\"block_count\":0,\"report_type\":0,\"templateID\":\"16a988ce-8529-42f5-b17c-2ee849355071\"}", templateInfo.getProcessMapJsonString()); |
||||
assertJsonStringEquals("{\"process\":\"\",\"float_count\":0,\"widget_count\":0,\"cell_count\":1," + |
||||
"\"block_count\":0,\"report_type\":0,\"templateID\":\"49avd2c4-1104-92j2-wx24-3dd0k2136080\"}", templateInfoSaveAs.getProcessMapJsonString()); |
||||
} |
||||
|
||||
private TemplateInfo createTemplateInfo(String xmlContent) throws XMLStreamException { |
||||
StringReader sr = new StringReader(xmlContent); |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(sr); |
||||
return TemplateInfo.newInstanceByRead(xmlReader); |
||||
} |
||||
} |
@ -0,0 +1,49 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.config.MarketConfig; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.stable.ProductConstants; |
||||
import org.easymock.EasyMock; |
||||
import org.powermock.api.easymock.PowerMock; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Modifier; |
||||
|
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/19. |
||||
*/ |
||||
class TemplateInfoTestHelper { |
||||
static void assertJsonStringEquals(String jo1, String jo2) { |
||||
// HashMap 是无序的,所以不能直接比较它生成的 json 字符串
|
||||
assertTrue(ComparatorUtils.equals(new JSONObject(jo1), new JSONObject(jo2))); |
||||
} |
||||
|
||||
private static void setFinalStatic(Field field, Object newValue) throws Exception { |
||||
field.setAccessible(true); |
||||
// remove final modifier from field
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers"); |
||||
modifiersField.setAccessible(true); |
||||
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); |
||||
field.set(null, newValue); |
||||
} |
||||
|
||||
static void setUpMockForNewInstance() throws Exception { |
||||
MarketConfig mockMarketConfig = EasyMock.mock(MarketConfig.class); |
||||
EasyMock.expect(mockMarketConfig.getBbsUsername()).andReturn("plough").anyTimes(); |
||||
|
||||
PowerMock.mockStatic(MarketConfig.class); |
||||
EasyMock.expect(MarketConfig.getInstance()).andReturn(mockMarketConfig).anyTimes(); |
||||
|
||||
PowerMock.mockStatic(GeneralUtils.class); |
||||
EasyMock.expect(GeneralUtils.readBuildNO()).andReturn("不是安装版本").anyTimes(); |
||||
|
||||
setFinalStatic(ProductConstants.class.getDeclaredField("VERSION"), "10.0"); |
||||
|
||||
EasyMock.replay(mockMarketConfig); |
||||
PowerMock.replayAll(); |
||||
} |
||||
} |
@ -0,0 +1,62 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/19. |
||||
*/ |
||||
public class TimeConsumeTimerTest { |
||||
|
||||
@Test |
||||
public void testNotEnabled() throws InterruptedException { |
||||
TimeConsumeTimer consumeTimer = new TimeConsumeTimer(); |
||||
consumeTimer.start(); |
||||
Thread.sleep(1100); |
||||
consumeTimer.stop(); |
||||
assertEquals(0, consumeTimer.popTime()); |
||||
} |
||||
|
||||
@Test |
||||
public void testEnabled() throws InterruptedException { |
||||
TimeConsumeTimer consumeTimer = new TimeConsumeTimer(); |
||||
consumeTimer.setEnabled(true); |
||||
consumeTimer.start(); |
||||
Thread.sleep(1100); |
||||
consumeTimer.stop(); |
||||
assertEquals(1, consumeTimer.popTime()); |
||||
assertEquals(0, consumeTimer.popTime()); |
||||
} |
||||
|
||||
@Test |
||||
public void testMultiTimes() throws InterruptedException { |
||||
TimeConsumeTimer consumeTimer = new TimeConsumeTimer(); |
||||
consumeTimer.setEnabled(true); |
||||
|
||||
consumeTimer.start(); |
||||
Thread.sleep(1010); |
||||
consumeTimer.stop(); |
||||
|
||||
Thread.sleep(2000); |
||||
|
||||
consumeTimer.start(); |
||||
Thread.sleep(1010); |
||||
assertEquals(2, consumeTimer.popTime()); |
||||
} |
||||
|
||||
@Test |
||||
public void testStartMultiTime() throws InterruptedException { |
||||
TimeConsumeTimer consumeTimer = new TimeConsumeTimer(); |
||||
consumeTimer.setEnabled(true); |
||||
|
||||
consumeTimer.start(); |
||||
Thread.sleep(1010); |
||||
consumeTimer.start(); |
||||
Thread.sleep(1010); |
||||
consumeTimer.start(); |
||||
Thread.sleep(1010); |
||||
|
||||
assertEquals(3, consumeTimer.popTime()); |
||||
} |
||||
} |
@ -0,0 +1,72 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
||||
import org.junit.Test; |
||||
|
||||
import java.io.PrintWriter; |
||||
import java.io.StringReader; |
||||
import java.io.StringWriter; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertSame; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
|
||||
/** |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
public class DesignerPushUpdateConfigManagerTest { |
||||
|
||||
@Test |
||||
public void testSingleton() { |
||||
DesignerPushUpdateConfigManager m1 = DesignerPushUpdateConfigManager.getInstance(); |
||||
DesignerPushUpdateConfigManager m2 = DesignerPushUpdateConfigManager.getInstance(); |
||||
assertSame(m1, m2); |
||||
} |
||||
|
||||
@Test |
||||
public void testDefaultValue() throws XMLStreamException { |
||||
DesignerPushUpdateConfigManager configManager = DesignerPushUpdateConfigManager.getInstance(); |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(new StringReader("<xml></xml>")); |
||||
xmlReader.readXMLObject(configManager); |
||||
|
||||
assertEquals(StringUtils.EMPTY, configManager.getLastIgnoredVersion()); |
||||
assertTrue(configManager.isAutoPushUpdateEnabled()); |
||||
} |
||||
|
||||
@Test |
||||
public void testReadAndWrite() throws XMLStreamException { |
||||
final String initLastIngnoredVersion = "1.1.2"; |
||||
final boolean initAutoPushEnabled = false; |
||||
|
||||
DesignerPushUpdateConfigManager configManager = DesignerPushUpdateConfigManager.getInstance(); |
||||
|
||||
configManager.setLastIgnoredVersion(initLastIngnoredVersion); |
||||
configManager.setAutoPushUpdateEnabled(initAutoPushEnabled); |
||||
|
||||
// 写入 xml
|
||||
StringWriter sw = new StringWriter(); |
||||
XMLPrintWriter writer = XMLPrintWriter.create(new PrintWriter(sw)); |
||||
configManager.writeXML(writer); |
||||
writer.flush(); |
||||
writer.close(); |
||||
|
||||
String xml_str = sw.getBuffer().toString(); |
||||
|
||||
// 临时修改配置
|
||||
configManager.setAutoPushUpdateEnabled(true); |
||||
configManager.setLastIgnoredVersion("0.20.1"); |
||||
|
||||
// 从 xml 中读取
|
||||
StringReader sr = new StringReader(xml_str); |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(sr); |
||||
xmlReader.readXMLObject(configManager); |
||||
|
||||
// 验证:与写入时的配置一致
|
||||
assertEquals(initLastIngnoredVersion, configManager.getLastIgnoredVersion()); |
||||
assertEquals(initAutoPushEnabled, configManager.isAutoPushUpdateEnabled()); |
||||
} |
||||
} |
@ -0,0 +1,23 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.json.JSONObject; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/10. |
||||
*/ |
||||
public class DesignerPushUpdateDialogTest { |
||||
|
||||
public static void main(String[] args) { |
||||
DesignerEnvManager.getEnvManager().setOpenDebug(true); |
||||
|
||||
JSONObject jo = JSONObject.create(); |
||||
jo.put("version", "2019.03.06.04.02.43.6"); |
||||
jo.put("content", "设计器改进:去除右击弹框,让操作过程更流畅;增加报表块缩放功能,利于从全局角度整体设计报表\n插件重构:插件支持热部署,即装即用,不再需要重启服务器;\nsapbw:可用于bwcube和bwquery;\n私有云认证:可在客户本地部署私有云认证服务器,业务服务器可到此服务器进行认证;\n开放:打通简道云,可以在简道云里创建项目,并将数据同步到客户的私有库\nshould not display"); |
||||
jo.put("more", "http://baidu.com"); |
||||
jo.put("background", "http://updateten.finereport.com/fr.png"); |
||||
DesignerUpdateInfo mockUpdateInfo = new DesignerUpdateInfo("111.22.11", "2211.231.1", "11.23.1", jo); |
||||
|
||||
DesignerPushUpdateDialog.createAndShow(null, mockUpdateInfo); |
||||
} |
||||
} |
@ -0,0 +1,76 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.design.event.DesignerOpenedListener; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.DesignerFrame; |
||||
import com.fr.invoke.Reflect; |
||||
import com.fr.stable.StringUtils; |
||||
import org.easymock.EasyMock; |
||||
import org.junit.BeforeClass; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.powermock.api.easymock.PowerMock; |
||||
import org.powermock.core.classloader.annotations.PrepareForTest; |
||||
import org.powermock.modules.junit4.PowerMockRunner; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertSame; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
@RunWith(value = PowerMockRunner.class) |
||||
@PrepareForTest(DesignerContext.class) |
||||
public class DesignerPushUpdateManagerTest { |
||||
|
||||
@BeforeClass |
||||
public static void setUp() { |
||||
DesignerFrame mockFrame = EasyMock.mock(DesignerFrame.class); |
||||
mockFrame.addDesignerOpenedListener(EasyMock.anyObject(DesignerOpenedListener.class)); |
||||
EasyMock.replay(mockFrame); |
||||
|
||||
PowerMock.mockStatic(DesignerContext.class); |
||||
EasyMock.expect(DesignerContext.getDesignerFrame()).andReturn(mockFrame).anyTimes(); |
||||
PowerMock.replayAll(); |
||||
} |
||||
|
||||
@Test |
||||
public void testSingleton() { |
||||
DesignerPushUpdateManager m1 = DesignerPushUpdateManager.getInstance(); |
||||
DesignerPushUpdateManager m2 = DesignerPushUpdateManager.getInstance(); |
||||
assertSame(m1, m2); |
||||
} |
||||
|
||||
@Test |
||||
public void testIsAutoPushUpdateSupported() { |
||||
// 中文环境 + 本地设计 -> true
|
||||
DesignerPushUpdateManager pushUpdateManager = DesignerPushUpdateManager.getInstance(); |
||||
assertEquals(true, Reflect.on(pushUpdateManager).call("isAutoPushUpdateSupported", true, true).get()); |
||||
|
||||
// 非中文环境 || 远程设计 -> false
|
||||
assertEquals(false, Reflect.on(pushUpdateManager).call("isAutoPushUpdateSupported", false, true).get()); |
||||
assertEquals(false, Reflect.on(pushUpdateManager).call("isAutoPushUpdateSupported", true, false).get()); |
||||
assertEquals(false, Reflect.on(pushUpdateManager).call("isAutoPushUpdateSupported", false, false).get()); |
||||
} |
||||
|
||||
@Test |
||||
public void testSkipCurrentPushVersion() { |
||||
DesignerPushUpdateManager pushUpdateManager = DesignerPushUpdateManager.getInstance(); |
||||
|
||||
// 1. updateInfo 为 null 的情况
|
||||
pushUpdateManager.skipCurrentPushVersion(); |
||||
assertEquals(StringUtils.EMPTY, DesignerPushUpdateConfigManager.getInstance().getLastIgnoredVersion()); |
||||
|
||||
|
||||
// 2. updateInfo 有值的情况
|
||||
final String PUSH_VERSION = "stable-2019.02.03.12.44.22"; |
||||
DesignerUpdateInfo mockInfo = EasyMock.mock(DesignerUpdateInfo.class); |
||||
EasyMock.expect(mockInfo.getPushVersion()).andReturn(PUSH_VERSION).anyTimes(); |
||||
Reflect.on(pushUpdateManager).set("updateInfo", mockInfo); |
||||
EasyMock.replay(mockInfo); |
||||
|
||||
pushUpdateManager.skipCurrentPushVersion(); |
||||
assertEquals(PUSH_VERSION, DesignerPushUpdateConfigManager.getInstance().getLastIgnoredVersion()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,97 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.json.JSONObject; |
||||
import com.fr.stable.StringUtils; |
||||
import org.junit.Assert; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
import java.security.InvalidParameterException; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/9. |
||||
*/ |
||||
public class DesignerUpdateInfoTest { |
||||
private static final String CURRENT_VERSION = "2018.09.03.xx"; |
||||
private static final String LATEST_VERSION = "2019.04.03.yy"; |
||||
private static final String LAST_IGNORED_VERSION = "2019.02.03.yy"; |
||||
private static final String PUSH_VERSION = "2019.01.03.21.11"; |
||||
private static final String PUSH_CONTENT = "the update desc content"; |
||||
private static final String PUSH_BACKGROUND = "http://image.fr.com/123.jpg"; |
||||
private static final String PUSH_MORE = "http://help.finereport.com/xxx"; |
||||
private DesignerUpdateInfo updateInfo; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
JSONObject pushData = JSONObject.create(); |
||||
|
||||
pushData.put("version", PUSH_VERSION); |
||||
pushData.put("content", PUSH_CONTENT); |
||||
pushData.put("background", PUSH_BACKGROUND); |
||||
pushData.put("more", PUSH_MORE); |
||||
|
||||
updateInfo = new DesignerUpdateInfo(CURRENT_VERSION, LATEST_VERSION, LAST_IGNORED_VERSION, pushData); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetters() { |
||||
assertEquals(CURRENT_VERSION, updateInfo.getCurrentVersion()); |
||||
assertEquals(LATEST_VERSION, updateInfo.getLatestVersion()); |
||||
assertEquals(LAST_IGNORED_VERSION, updateInfo.getLastIgnoredVersion()); |
||||
assertEquals(PUSH_VERSION, updateInfo.getPushVersion()); |
||||
assertEquals(PUSH_CONTENT, updateInfo.getPushContent()); |
||||
assertEquals(PUSH_BACKGROUND, updateInfo.getBackgroundUrl()); |
||||
assertEquals(PUSH_MORE, updateInfo.getMoreInfoUrl()); |
||||
} |
||||
|
||||
@Test |
||||
public void testHasNewPushVersion() { |
||||
// (1)最近被跳过的维护版本号 X0;
|
||||
// (2)本地版本号 Y;
|
||||
// (3)最新的推送版本号 X;
|
||||
// (4)最新的版本号 Z
|
||||
// 必须满足:Y < X <= Z && X > X0,才返回 true
|
||||
|
||||
// 1 true
|
||||
assertTrue(hasNewVersion("2019.01.03.xx", "2018.05.03.xx", "2019.04.03.yy", "2018.05.03.xx")); |
||||
assertTrue(hasNewVersion("2019.01.03.xx", "2018.05.03.xx", "2019.04.03.yy", null)); |
||||
assertTrue(hasNewVersion("2019.01.03.xx", "2018.05.03.xx", "2019.04.03.yy", StringUtils.EMPTY)); |
||||
|
||||
// 2 false
|
||||
// 2.1 X <= Y && X > X0
|
||||
assertFalse(hasNewVersion("2019.01.03.xx", "2019.03.03.xx", "2019.04.03.yy", "2018.05.03.xx")); |
||||
assertFalse(hasNewVersion("2019.03.03.xx", "2019.03.03.xx", "2019.04.03.yy", "2018.05.03.xx")); |
||||
|
||||
// 2.2 X > Z && X > X0
|
||||
assertFalse(hasNewVersion("2020.01.03.xx", "2019.03.03.xx", "2019.04.03.yy", "2018.05.03.xx")); |
||||
|
||||
// 2.3 Y < X <= Z && X <= X0
|
||||
assertFalse(hasNewVersion("2019.01.03.xx", "2018.05.03.xx", "2019.04.03.yy", "2019.02.03.xx")); |
||||
assertFalse(hasNewVersion("2019.01.03.xx", "2018.05.03.xx", "2019.04.03.yy", "2019.01.03.xx")); |
||||
} |
||||
|
||||
|
||||
private boolean hasNewVersion(String X, String Y, String Z, String X0) { |
||||
JSONObject pushData = JSONObject.create(); |
||||
pushData.put("version", X); |
||||
pushData.put("content", PUSH_CONTENT); |
||||
pushData.put("background", PUSH_BACKGROUND); |
||||
pushData.put("more", PUSH_MORE); |
||||
DesignerUpdateInfo updateInfo = new DesignerUpdateInfo(Y, Z, X0, pushData); |
||||
return updateInfo.hasNewPushVersion(); |
||||
} |
||||
|
||||
@Test |
||||
public void testParameterValidation() { |
||||
try { |
||||
DesignerUpdateInfo updateInfo = new DesignerUpdateInfo(null, null, null, new JSONObject()); |
||||
Assert.fail("should not reach here!"); |
||||
} catch (InvalidParameterException e) { |
||||
// do nothing
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<TplInfo xmlVersion="20170720" releaseVersion="10.0.0"> |
||||
<DesignerOpenHistory> |
||||
<![CDATA[2019-04-08,2019-04-03,2019-03-29]]></DesignerOpenHistory> |
||||
<TemplateInfoList> |
||||
<TemplateInfo templateID="16a988ce-8529-42f5-b17c-2ee849355071" day_count="9"> |
||||
<processMap process="" float_count="0" widget_count="0" cell_count="1" block_count="0" report_type="0"/> |
||||
<consumingMap activitykey="2e0ea413-fa9c241e0-9723-4354fce51e81" jar_time="不是安装版本" create_time="2019-03-26 16:13" uuid="476ca2cc-f789-4c5d-8e89-ef146580775c" time_consume="129" version="10.0" username="plough"/> |
||||
</TemplateInfo> |
||||
<TemplateInfo templateID="23817e4f-64b6-438e-b23b-91c1a4d0b254" day_count="9"> |
||||
<processMap process="" float_count="0" widget_count="0" cell_count="231" block_count="0" report_type="0"/> |
||||
<consumingMap activitykey="2e0ea413-fa9c241e0-9723-4354fce51e81" jar_time="不是安装版本" create_time="2019-03-26 16:52" uuid="476ca2cc-f789-4c5d-8e89-ef146580775c" time_consume="91" version="10.0" username="plough"/> |
||||
</TemplateInfo> |
||||
<TemplateInfo templateID="31319947-5ce7-4d82-97e4-3cfea825df9c" day_count="9"> |
||||
<processMap process="" float_count="0" widget_count="0" cell_count="3" block_count="0" report_type="0"/> |
||||
<consumingMap activitykey="2e0ea413-fa9c241e0-9723-4354fce51e81" jar_time="不是安装版本" create_time="2019-03-26 16:49" uuid="476ca2cc-f789-4c5d-8e89-ef146580775c" time_consume="160" version="10.0" username="plough"/> |
||||
</TemplateInfo> |
||||
<TemplateInfo templateID="43bdd914-a3f7-405c-ad96-2feaf28bed74" day_count="8"> |
||||
<processMap process="" float_count="0" widget_count="0" cell_count="1" block_count="0" report_type="0"/> |
||||
<consumingMap activitykey="2e0ea413-fa9c241e0-9723-4354fce51e81" jar_time="2019.01.04.18.06.01.38" create_time="2019-03-27 16:17" uuid="476ca2cc-f789-4c5d-8e89-ef146580775c" time_consume="1426" version="10.0" username="plough"/> |
||||
</TemplateInfo> |
||||
<TemplateInfo templateID="cd527ae5-06e4-48fb-a73e-e9a06c9e7c58" day_count="12"> |
||||
<processMap process="" float_count="0" widget_count="0" cell_count="3" block_count="0" report_type="0"/> |
||||
<consumingMap activitykey="2e0ea413-fa9c241e0-9723-4354fce51e81" jar_time="2019.01.04.18.06.01.38" create_time="2019-03-15 10:02" uuid="476ca2cc-f789-4c5d-8e89-ef146580775c" time_consume="430" version="10.0" username="plough"/> |
||||
</TemplateInfo> |
||||
<TemplateInfo templateID="08f9c404-8124-4615-a34c-735dcabee137" day_count="9"> |
||||
<processMap process="" float_count="0" widget_count="0" cell_count="2" block_count="0" report_type="0"/> |
||||
<consumingMap activitykey="2e0ea413-fa9c241e0-9723-4354fce51e81" jar_time="不是安装版本" create_time="2019-03-25 17:22" uuid="476ca2cc-f789-4c5d-8e89-ef146580775c" time_consume="1497" version="10.0" username="plough"/> |
||||
</TemplateInfo> |
||||
<TemplateInfo templateID="981314a5-9c5b-4831-97d8-15e76735f9e2" day_count="1"> |
||||
<processMap process="" float_count="0" widget_count="0" cell_count="3" block_count="0" report_type="0"/> |
||||
<consumingMap activitykey="2e0ea413-fa9c241e0-9723-4354fce51e81" jar_time="不是安装版本" create_time="2019-04-17 16:24" uuid="476ca2cc-f789-4c5d-8e89-ef146580775c" time_consume="155" version="10.0" username="plough"/> |
||||
</TemplateInfo> |
||||
</TemplateInfoList> |
||||
</TplInfo> |
@ -0,0 +1,28 @@
|
||||
package com.fr.design.form.util; |
||||
|
||||
import com.fr.design.mainframe.FormDesigner; |
||||
import com.fr.form.ui.container.WFitLayout; |
||||
|
||||
public class FormDesignerUtils { |
||||
/** |
||||
* body布局是否设置了手机重布局 |
||||
* |
||||
* @param designer |
||||
* @return |
||||
*/ |
||||
public static boolean isAppRelayout(FormDesigner designer) { |
||||
return ((WFitLayout) designer.getRootComponent().toData()).isAppRelayout(); |
||||
} |
||||
|
||||
/** |
||||
* body布局是否设置了绝对布局 |
||||
* |
||||
* @param designer |
||||
* @return |
||||
*/ |
||||
public static boolean isBodyAbsolute(FormDesigner designer) { |
||||
WFitLayout root = ((WFitLayout) designer.getRootComponent().toData()); |
||||
return root.getBodyLayoutType() == com.fr.form.ui.container.WBodyLayoutType.ABSOLUTE; |
||||
} |
||||
|
||||
} |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.mainframe.templateinfo; |
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.form.main.Form; |
||||
import com.fr.form.ui.container.WLayout; |
@ -0,0 +1,18 @@
|
||||
package com.fr.design.widget.ui.designer; |
||||
|
||||
import com.fr.design.dialog.BasicPane; |
||||
|
||||
/** |
||||
* 有些控件在不同终端需要对相同的属性分别进行设置,基础设置面板是一样的但是映射到控件上的属性又是不一样的,为了重用面板,这边加上xmltag做区分 |
||||
*/ |
||||
public abstract class XmlRelationedBasicPane extends BasicPane{ |
||||
private String xmlTag; |
||||
|
||||
public XmlRelationedBasicPane(String xmlTag) { |
||||
this.xmlTag = xmlTag; |
||||
} |
||||
|
||||
public String getXmlTag() { |
||||
return xmlTag; |
||||
} |
||||
} |
@ -0,0 +1,45 @@
|
||||
package com.fr.design.widget.ui.designer.mobile.component; |
||||
|
||||
import com.fr.base.iofile.attr.AttrMarkFactory; |
||||
import com.fr.base.iofile.attr.FormBodyPaddingAttrMark; |
||||
import com.fr.design.foldablepane.UIExpandablePane; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.widget.ui.designer.XmlRelationedBasicPane; |
||||
import com.fr.design.widget.ui.designer.component.PaddingBoundPane; |
||||
import com.fr.form.ui.RichStyleWidgetProvider; |
||||
|
||||
import java.awt.BorderLayout; |
||||
|
||||
/** |
||||
* 只有内边距设置的高级设置 |
||||
*/ |
||||
public class MobileComponentAdvancePane extends XmlRelationedBasicPane { |
||||
private PaddingBoundPane paddingBound; |
||||
|
||||
public MobileComponentAdvancePane(String xmlTag) { |
||||
super(xmlTag); |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
paddingBound = new PaddingBoundPane(FormBodyPaddingAttrMark.DEFAULT_SIZE, FormBodyPaddingAttrMark.DEFAULT_SIZE, FormBodyPaddingAttrMark.DEFAULT_SIZE, FormBodyPaddingAttrMark.DEFAULT_SIZE); |
||||
UIExpandablePane advanceExpandablePane = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Advanced"), 280, 20, paddingBound); |
||||
this.add(advanceExpandablePane, BorderLayout.NORTH); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return "ComponentAdvancePane"; |
||||
} |
||||
|
||||
public void update(RichStyleWidgetProvider marginWidget) { |
||||
FormBodyPaddingAttrMark attrMark = marginWidget.getWidgetAttrMark(getXmlTag()); |
||||
attrMark = attrMark == null ? (FormBodyPaddingAttrMark) AttrMarkFactory.createAttrMark(getXmlTag()) : attrMark; |
||||
attrMark.setPaddingMargin(paddingBound.updateBean()); |
||||
marginWidget.addWidgetAttrMark(attrMark); |
||||
} |
||||
|
||||
public void populate(RichStyleWidgetProvider marginWidget) { |
||||
FormBodyPaddingAttrMark attrMark = marginWidget.getWidgetAttrMark(getXmlTag()); |
||||
if (attrMark != null) { |
||||
paddingBound.populateBean(attrMark.getPaddingMargin()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,71 @@
|
||||
package com.fr.design.widget.ui.designer.mobile.component; |
||||
|
||||
import com.fr.base.iofile.attr.AttrMarkFactory; |
||||
import com.fr.base.iofile.attr.FormBodyPaddingAttrMark; |
||||
import com.fr.design.designer.IntervalConstants; |
||||
import com.fr.design.foldablepane.UIExpandablePane; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.gui.ispinner.UISpinner; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.layout.TableLayout; |
||||
import com.fr.design.layout.TableLayoutHelper; |
||||
import com.fr.design.utils.gui.UIComponentUtils; |
||||
import com.fr.design.widget.FRWidgetFactory; |
||||
import com.fr.design.widget.ui.designer.XmlRelationedBasicPane; |
||||
import com.fr.form.ui.RichStyleWidgetProvider; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JPanel; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Component; |
||||
|
||||
/** |
||||
* 只有组件间隔的布局设置 |
||||
*/ |
||||
public class MobileComponentLayoutIntervalPane extends XmlRelationedBasicPane { |
||||
private UISpinner componentIntervel; |
||||
|
||||
public MobileComponentLayoutIntervalPane(String xmlTag) { |
||||
super(xmlTag); |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
UILabel intervalLabel = FRWidgetFactory.createLineWrapLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Component_Interval")); |
||||
|
||||
double f = TableLayout.FILL; |
||||
double p = TableLayout.PREFERRED; |
||||
double[] rowSize = {p, p}; |
||||
double[] columnSize = {p, f}; |
||||
int[][] rowCount = {{1, 1}, {1, 1}}; |
||||
componentIntervel = new UISpinner(0, Integer.MAX_VALUE, 1, FormBodyPaddingAttrMark.DEFAULT_SIZE); |
||||
JPanel componentIntervelPane = UIComponentUtils.wrapWithBorderLayoutPane(componentIntervel); |
||||
|
||||
Component[][] components = new Component[][]{ |
||||
new Component[]{intervalLabel, componentIntervelPane} |
||||
}; |
||||
JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_W1, IntervalConstants.INTERVAL_L1); |
||||
centerPane.setBorder(BorderFactory.createEmptyBorder(IntervalConstants.INTERVAL_L1, IntervalConstants.INTERVAL_L5, 0, 0)); |
||||
JPanel holder = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
holder.add(centerPane, BorderLayout.NORTH); |
||||
UIExpandablePane layoutExpandablePane = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout"), 280, 20, holder); |
||||
this.add(layoutExpandablePane, BorderLayout.NORTH); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return "ComponentIntervelPane"; |
||||
} |
||||
|
||||
public void update(RichStyleWidgetProvider marginWidget) { |
||||
|
||||
FormBodyPaddingAttrMark attrMark = marginWidget.getWidgetAttrMark(getXmlTag()); |
||||
attrMark = attrMark == null ? (FormBodyPaddingAttrMark) AttrMarkFactory.createAttrMark(getXmlTag()) : attrMark; |
||||
attrMark.setInterval((int) componentIntervel.getValue()); |
||||
marginWidget.addWidgetAttrMark(attrMark); |
||||
} |
||||
|
||||
public void populate(RichStyleWidgetProvider marginWidget) { |
||||
FormBodyPaddingAttrMark attrMark = marginWidget.getWidgetAttrMark(getXmlTag()); |
||||
if (attrMark != null) { |
||||
componentIntervel.setValueWithoutEvent(attrMark.getInterval()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,152 @@
|
||||
package com.fr.design.mainframe.messagecollect.entity; |
||||
|
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.IOUtils; |
||||
import com.fr.general.http.HttpToolbox; |
||||
import com.fr.json.JSONArray; |
||||
import com.fr.json.JSONException; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.CommonUtils; |
||||
import com.fr.stable.EncodeConstants; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.jodd.datetime.JDateTime; |
||||
import com.fr.third.org.apache.http.HttpEntity; |
||||
import com.fr.third.org.apache.http.HttpResponse; |
||||
import com.fr.third.org.apache.http.client.HttpClient; |
||||
import com.fr.third.org.apache.http.client.methods.HttpPut; |
||||
import com.fr.third.org.apache.http.entity.FileEntity; |
||||
import com.fr.third.org.apache.http.impl.client.DefaultHttpClient; |
||||
import com.fr.third.org.apache.http.util.EntityUtils; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.UUID; |
||||
|
||||
import static com.fr.third.org.apache.http.HttpStatus.SC_OK; |
||||
|
||||
/** |
||||
* @author alex sung |
||||
* @date 2019/4/8 |
||||
*/ |
||||
public class FileEntityBuilder { |
||||
|
||||
private static final String INTELLI_OPERATION_URL = "intelli.operation.url"; |
||||
private static final String OPERATION_URL = "https://cloud.fanruan.com/config/protect/operation"; |
||||
private static final String ATTR_SIGNATURE = "signature"; |
||||
private static final String ATTR_KEY = "key"; |
||||
private static final String FOCUS_POINT_FILE_ROOT_PATH = "FocusPoint"; |
||||
|
||||
/** |
||||
* 文件夹路径 |
||||
*/ |
||||
private String folderName; |
||||
|
||||
public FileEntityBuilder(String folderName) { |
||||
this.folderName = folderName; |
||||
} |
||||
|
||||
public String getFolderName() { |
||||
return folderName; |
||||
} |
||||
|
||||
public void setFolderName(String folderName) { |
||||
this.folderName = folderName; |
||||
} |
||||
|
||||
public File generateZipFile(String pathName) { |
||||
File zipFile = null; |
||||
try { |
||||
zipFile = new File(pathName + ".zip"); |
||||
java.util.zip.ZipOutputStream zipOut = new java.util.zip.ZipOutputStream(new FileOutputStream(zipFile)); |
||||
IOUtils.zip(zipOut, new File(pathName)); |
||||
zipOut.close(); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return zipFile; |
||||
} |
||||
|
||||
public void generateFile(JSONArray jsonArray, String folderName) { |
||||
if (jsonArray.size() == 0) { |
||||
return; |
||||
} |
||||
try { |
||||
String content = jsonArray.toString(); |
||||
String fileName = String.valueOf(UUID.randomUUID()); |
||||
File file = new File(folderName + File.separator + fileName + ".json"); |
||||
StableUtils.makesureFileExist(file); |
||||
FileOutputStream out = new FileOutputStream(file); |
||||
InputStream in = new ByteArrayInputStream(content.getBytes(EncodeConstants.ENCODING_UTF_8)); |
||||
IOUtils.copyBinaryTo(in, out); |
||||
in.close(); |
||||
out.close(); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
public void deleteFileAndZipFile(File zipFile, String pathName) { |
||||
File file = new File(pathName); |
||||
CommonUtils.deleteFile(file); |
||||
CommonUtils.deleteFile(zipFile); |
||||
} |
||||
|
||||
/** |
||||
* 上传文件到云中心 |
||||
* @param file 待上传文件 |
||||
* @param keyFileName 目标文件 |
||||
* @throws IOException |
||||
*/ |
||||
public static void uploadFile(File file, String keyFileName) throws IOException { |
||||
String today = new JDateTime().toString("YYYY-MM-DD"); |
||||
HttpClient httpclient = new DefaultHttpClient(); |
||||
try { |
||||
String signedUrl = generateSignedUploadUrl(FOCUS_POINT_FILE_ROOT_PATH + File.separator + today + File.separator +keyFileName); |
||||
if(StringUtils.isEmpty(signedUrl)){ |
||||
FineLoggerFactory.getLogger().error("signedUrl is null."); |
||||
return; |
||||
} |
||||
HttpPut httpPost = new HttpPut(signedUrl); |
||||
httpPost.addHeader("Content-Type","application/octet-stream"); |
||||
FileEntity fileEntity = new FileEntity(file); |
||||
httpPost.setEntity(fileEntity); |
||||
HttpResponse response = httpclient.execute(httpPost); |
||||
|
||||
int statusCode = response.getStatusLine().getStatusCode(); |
||||
if (statusCode == SC_OK) { |
||||
HttpEntity resEntity = response.getEntity(); |
||||
EntityUtils.consume(resEntity); |
||||
} else { |
||||
HttpEntity entity = response.getEntity(); |
||||
String result = EntityUtils.toString(entity, "utf-8"); |
||||
FineLoggerFactory.getLogger().info("upload file result:" + result); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
private static String generateSignedUploadUrl(String fileKeyName) throws IOException { |
||||
String url = CloudCenter.getInstance().acquireUrlByKind(INTELLI_OPERATION_URL, OPERATION_URL); |
||||
Map<String, String> parameters = new HashMap<String, String>(); |
||||
parameters.put(ATTR_KEY, fileKeyName); |
||||
parameters.put(ATTR_SIGNATURE, String.valueOf(CommonUtils.signature())); |
||||
String responseText = HttpToolbox.get(url, parameters); |
||||
try { |
||||
JSONObject data = new JSONObject(responseText); |
||||
if ("success".equals(data.optString("status"))) { |
||||
return data.optString("url"); |
||||
} |
||||
} catch (JSONException e) { |
||||
FineLoggerFactory.getLogger().error("Illegal response text."+e, e.getMessage()); |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,133 @@
|
||||
package com.fr.design.mainframe.messagecollect.impl; |
||||
|
||||
import com.fr.design.mainframe.messagecollect.entity.FileEntityBuilder; |
||||
import com.fr.design.mainframe.messagecollect.utils.MessageCollectUtils; |
||||
import com.fr.intelli.record.MetricRegistry; |
||||
import com.fr.json.JSONArray; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.query.QueryFactory; |
||||
import com.fr.stable.query.condition.QueryCondition; |
||||
import com.fr.stable.query.data.DataList; |
||||
import com.fr.stable.query.restriction.RestrictionFactory; |
||||
import com.fr.stable.xml.XMLTools; |
||||
import com.fr.stable.xml.XMLable; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
|
||||
/** |
||||
* @author alex sung |
||||
* @date 2019/3/22 |
||||
*/ |
||||
public abstract class AbstractSendDataToCloud implements XMLable { |
||||
private static final String FILE_NAME = "messagecollect.info"; |
||||
private static final String COLUMN_TIME = "time"; |
||||
|
||||
protected String lastTime; |
||||
private static final int PAGE_SIZE = 10000; |
||||
private long totalCount = -1; |
||||
private FileEntityBuilder fileEntityBuilder; |
||||
|
||||
public FileEntityBuilder getFileEntityBuilder() { |
||||
return fileEntityBuilder; |
||||
} |
||||
|
||||
public void setFileEntityBuilder(FileEntityBuilder fileEntityBuilder) { |
||||
this.fileEntityBuilder = fileEntityBuilder; |
||||
} |
||||
|
||||
public String getLastTime() { |
||||
return lastTime; |
||||
} |
||||
|
||||
public void setLastTime(String lastTime) { |
||||
this.lastTime = lastTime; |
||||
} |
||||
|
||||
public void saveLastTime() { |
||||
setLastTime(MessageCollectUtils.dateToString()); |
||||
try { |
||||
FileOutputStream out = new FileOutputStream(getLastTimeFile()); |
||||
XMLTools.writeOutputStreamXML(this, out); |
||||
} catch (Exception ex) { |
||||
FineLoggerFactory.getLogger().error(ex.getMessage()); |
||||
} |
||||
} |
||||
|
||||
public static File getLastTimeFile() { |
||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), FILE_NAME)); |
||||
} |
||||
|
||||
public <T> void queryData(long currentTime, long lastTime, Class<T> tClass) { |
||||
queryAndSendOnePageFunctionContent(currentTime, lastTime, 0, tClass); |
||||
long page = (totalCount / PAGE_SIZE) + 1; |
||||
for (int i = 1; i < page; i++) { |
||||
queryAndSendOnePageFunctionContent(currentTime, lastTime, i, tClass); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Object clone() throws CloneNotSupportedException { |
||||
return super.clone(); |
||||
} |
||||
|
||||
private <T> void queryAndSendOnePageFunctionContent(long current, long last, int page, Class<T> tClass) { |
||||
QueryCondition condition = QueryFactory.create() |
||||
.skip(page * PAGE_SIZE) |
||||
.count(PAGE_SIZE) |
||||
.addSort(COLUMN_TIME, true) |
||||
.addRestriction(RestrictionFactory.lte(COLUMN_TIME, current)) |
||||
.addRestriction(RestrictionFactory.gte(COLUMN_TIME, last)); |
||||
try { |
||||
DataList<T> points = MetricRegistry.getMetric().find(tClass, condition); |
||||
//第一次查询获取总记录数
|
||||
if (page == 0) { |
||||
totalCount = points.getTotalCount(); |
||||
} |
||||
dealWithData(points); |
||||
|
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
public <T> void dealWithData(DataList<T> tDataList) throws Exception { |
||||
generateThisPageFile(tDataList); |
||||
} |
||||
|
||||
private <T> void generateThisPageFile(DataList<T> points) { |
||||
File file = null; |
||||
try { |
||||
JSONArray jsonArray = dealWithSendFunctionContent(points); |
||||
//生成json文件
|
||||
fileEntityBuilder.generateFile(jsonArray, getFileEntityBuilder().getFolderName()); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
public abstract <T> JSONArray dealWithSendFunctionContent(DataList<T> focusPoints); |
||||
|
||||
/** |
||||
* 生成zip并发送zip文件 |
||||
* @param pathName zip文件路径 |
||||
*/ |
||||
protected void sendZipFile(String pathName) { |
||||
|
||||
File file = null; |
||||
try { |
||||
file = fileEntityBuilder.generateZipFile(pathName); |
||||
if (file != null) { |
||||
fileEntityBuilder.uploadFile(file, file.getName()); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
return; |
||||
} |
||||
fileEntityBuilder.deleteFileAndZipFile(file, pathName); |
||||
} |
||||
|
||||
|
||||
} |