* commit '720f0516a2c9cd1c34879c4701a236a05eaead4a': (87 commits) ct c ct ct 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 模板信息收集, 设计器启动有报错 ...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; |
import com.fr.base.io.BaseBook; |
||||||
|
|
||||||
/** |
/** |
||||||
* Created by plough on 2017/3/17. |
* Created by plough on 2017/3/17. |
||||||
*/ |
*/ |
||||||
|
// todo: 重构
|
||||||
|
// 1. 命名不好,表意不清晰。
|
||||||
|
// 2. 逻辑混乱,到底是一个 Info 类,还是一个 InfoCollector 类?
|
||||||
|
// 3. 耦合太强,用组合替代继承
|
||||||
public abstract class TemplateProcessInfo<T extends BaseBook> { |
public abstract class TemplateProcessInfo<T extends BaseBook> { |
||||||
|
|
||||||
protected T template; |
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.locale.InterProviderFactory; |
||||||
import com.fr.log.FineLoggerFactory; |
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.ArrayUtils; |
||||||
import com.fr.stable.StableUtils; |
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.base.BaseUtils; |
||||||
import com.fr.design.actions.UpdateAction; |
import com.fr.design.actions.UpdateAction; |
||||||
import com.fr.design.mainframe.DesignerContext; |
import com.fr.design.mainframe.DesignerContext; |
||||||
import com.fr.design.onlineupdate.ui.dialog.UpdateMainDialog; |
import com.fr.design.update.ui.dialog.UpdateMainDialog; |
||||||
import com.fr.locale.InterProviderFactory; |
|
||||||
|
|
||||||
import java.awt.event.ActionEvent; |
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.general.ComparatorUtils; |
||||||
import com.fr.json.JSONObject; |
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. |
* 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; |
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.log.FineLoggerFactory; |
||||||
import com.fr.stable.ArrayUtils; |
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; |
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.gui.ibutton.UIButton; |
||||||
import com.fr.design.layout.FRGUIPaneFactory; |
import com.fr.design.layout.FRGUIPaneFactory; |
||||||
import com.fr.design.mainframe.DesignerContext; |
import com.fr.design.mainframe.DesignerContext; |
||||||
import com.fr.design.onlineupdate.domain.UpdateConstants; |
import com.fr.design.update.domain.UpdateConstants; |
||||||
import com.fr.design.onlineupdate.factory.DirectoryOperationFactory; |
import com.fr.design.update.factory.DirectoryOperationFactory; |
||||||
import com.fr.design.onlineupdate.ui.widget.ColorfulCellRender; |
import com.fr.design.update.ui.widget.ColorfulCellRender; |
||||||
import com.fr.design.utils.gui.GUICoreUtils; |
import com.fr.design.utils.gui.GUICoreUtils; |
||||||
import com.fr.locale.InterProviderFactory; |
|
||||||
import com.fr.stable.ArrayUtils; |
import com.fr.stable.ArrayUtils; |
||||||
import com.fr.stable.StableUtils; |
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.JList; |
||||||
import javax.swing.JPanel; |
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.design.gui.ilable.UILabel; |
||||||
import com.fr.general.IOUtils; |
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; |
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.JTable; |
||||||
import javax.swing.table.TableModel; |
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.general.ComparatorUtils; |
||||||
import com.fr.stable.StringUtils; |
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 javax.swing.table.AbstractTableModel; |
||||||
import java.util.List; |
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.BorderFactory; |
||||||
import javax.swing.JTable; |
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.main.Form; |
||||||
import com.fr.form.ui.container.WLayout; |
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()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |