Browse Source
* commit 'c8f20b88b6f526304b7ded8f36fdb5e09fb7bdc4': (196 commits) 改一下label 继承 下actionlabel rt REPORT-14835 过滤逻辑修改 修改editor rt REPORT-14835 日期控件自定义 REPORT-17096 同步到10.0 REPORT-16985 先屏蔽开发者调试 REPORT-16567 设计器社区菜单修改 添加新子菜单 REPORT-16029 繁体版本启动画面改成英文 依然使用FileExtension 误删了sort REPORT-16997 FileExtension支持接口扩展 更新下topic encode一下,防止乱码 REPORT-15987 这边也一起改下 REPORT-14835 交互优化 update update update ...final/10.0
neil
6 years ago
202 changed files with 6717 additions and 1727 deletions
@ -0,0 +1,41 @@
|
||||
package com.fr.design.actions.community; |
||||
|
||||
import com.fr.design.menu.MenuKeySet; |
||||
import com.fr.design.utils.BrowseUtils; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.IOUtils; |
||||
|
||||
import javax.swing.KeyStroke; |
||||
import java.awt.event.ActionEvent; |
||||
|
||||
public class FacebookFansAction extends UpAction { |
||||
|
||||
public FacebookFansAction() { |
||||
this.setMenuKeySet(FACEBOOKFANS); |
||||
this.setName(getMenuKeySet().getMenuName()); |
||||
this.setMnemonic(getMenuKeySet().getMnemonic()); |
||||
this.setSmallIcon(IOUtils.readIcon("/com/fr/design/images/bbs/facebook.png")); |
||||
} |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent arg0) { |
||||
BrowseUtils.browser(CloudCenter.getInstance().acquireUrlByKind("facebook.fans.tw")); |
||||
} |
||||
|
||||
public static final MenuKeySet FACEBOOKFANS = new MenuKeySet() { |
||||
@Override |
||||
public char getMnemonic() { |
||||
return 'F'; |
||||
} |
||||
|
||||
@Override |
||||
public String getMenuName() { |
||||
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Community_FaceBook_Fans"); |
||||
} |
||||
|
||||
@Override |
||||
public KeyStroke getKeyStroke() { |
||||
return null; |
||||
} |
||||
}; |
||||
} |
@ -0,0 +1,17 @@
|
||||
package com.fr.design.bridge.exec; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-18 |
||||
* 用于标记一个方法是用于和JS做桥接的,避免被误删除 |
||||
*/ |
||||
@Target(ElementType.METHOD) |
||||
@Retention(RetentionPolicy.SOURCE) |
||||
public @interface JSBridge { |
||||
} |
@ -0,0 +1,18 @@
|
||||
package com.fr.design.bridge.exec; |
||||
|
||||
/** |
||||
* Created by ibm on 2017/5/27. |
||||
*/ |
||||
public class JSCallback { |
||||
|
||||
private JSExecutor executeScript; |
||||
|
||||
public JSCallback(JSExecutor jsExecutor) { |
||||
this.executeScript = jsExecutor; |
||||
} |
||||
|
||||
public void execute(String newValue) { |
||||
executeScript.executor(newValue); |
||||
} |
||||
} |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.extra.exe.callback; |
||||
package com.fr.design.bridge.exec; |
||||
|
||||
/** |
||||
* Created by ibm on 2017/6/21. |
@ -0,0 +1,42 @@
|
||||
package com.fr.design.extra; |
||||
|
||||
import com.fr.design.bridge.exec.JSExecutor; |
||||
import com.fr.design.bridge.exec.JSUtils; |
||||
import javafx.application.Platform; |
||||
import javafx.scene.web.WebEngine; |
||||
import netscape.javascript.JSObject; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-18 |
||||
*/ |
||||
public class PluginJavaFxExecutor implements JSExecutor { |
||||
|
||||
public static PluginJavaFxExecutor create(WebEngine webEngine, JSObject callback) { |
||||
return new PluginJavaFxExecutor(webEngine, callback); |
||||
} |
||||
|
||||
private WebEngine webEngine; |
||||
private JSObject callback; |
||||
|
||||
private PluginJavaFxExecutor(WebEngine webEngine, JSObject callback) { |
||||
this.webEngine = webEngine; |
||||
this.callback = callback; |
||||
} |
||||
|
||||
@Override |
||||
public void executor(final String newValue) { |
||||
Platform.runLater(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
String fun = "(" + callback + ")(\"" + JSUtils.trimText(newValue) + "\")"; |
||||
try { |
||||
webEngine.executeScript(fun); |
||||
} catch (Exception e) { |
||||
webEngine.executeScript("alert(\"" + e.getMessage() + "\")"); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,38 @@
|
||||
package com.fr.design.fun; |
||||
|
||||
import com.fr.design.menu.MenuDef; |
||||
import com.fr.start.SplashStrategy; |
||||
|
||||
import java.awt.image.BufferedImage; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 设计器Oem接口 |
||||
*/ |
||||
public interface OemProcessor { |
||||
public static final String MARK_STRING = "OemProcessor"; |
||||
|
||||
/** |
||||
* 启动动画,如果不替换则返回null |
||||
* |
||||
* @return |
||||
*/ |
||||
SplashStrategy createSplashStrategy(); |
||||
|
||||
/** |
||||
* 替换标题图标--DesignerFrame.initTitleIcon |
||||
* 如果不替换则返回null |
||||
* |
||||
* @return |
||||
*/ |
||||
List<BufferedImage> createTitleIcon(); |
||||
|
||||
/** |
||||
* 处理设计器菜单(增删改) |
||||
* |
||||
* @param menuDefs 已加载的菜单 |
||||
* @return 新的菜单数组 |
||||
*/ |
||||
MenuDef[] dealWithMenuDef(MenuDef[] menuDefs); |
||||
|
||||
} |
@ -0,0 +1,25 @@
|
||||
package com.fr.design.fun.impl; |
||||
|
||||
import com.fr.design.fun.OemProcessor; |
||||
import com.fr.design.menu.MenuDef; |
||||
import com.fr.start.SplashStrategy; |
||||
|
||||
import java.awt.image.BufferedImage; |
||||
import java.util.List; |
||||
|
||||
public abstract class AbstractOemProcessor implements OemProcessor{ |
||||
@Override |
||||
public MenuDef[] dealWithMenuDef(MenuDef[] menuDefs) { |
||||
return menuDefs; |
||||
} |
||||
|
||||
@Override |
||||
public List<BufferedImage> createTitleIcon() { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public SplashStrategy createSplashStrategy() { |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,129 @@
|
||||
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; |
||||
} |
||||
|
||||
/** |
||||
* 设计器在 dayCount 时间内启动超过 X 次(目前定的 X = 3) |
||||
*/ |
||||
boolean isOpenEnoughTimesInPeriod(int dayCount) { |
||||
boolean enoughTimes = StringUtils.isNotEmpty(history[LENGTH - 1]); |
||||
if (!enoughTimes) { |
||||
return false; |
||||
} |
||||
return getHistorySpanDayCount() < dayCount; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取历史记录中囊括的日子数。即最早的历史记录 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().isOpenEnoughTimesInPeriod(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,252 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.base.io.XMLReadHelper; |
||||
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.third.org.apache.commons.io.FileUtils; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
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(); |
||||
|
||||
List<String> removeLaterList = new ArrayList<>(); |
||||
|
||||
for (String key : templateInfoMap.keySet()) { |
||||
TemplateInfo templateInfo = templateInfoMap.get(key); |
||||
if (templateInfo.isReadyForSend()) { |
||||
if (SendHelper.sendTemplateInfo(templateInfo)) { |
||||
removeLaterList.add(key); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 清空记录
|
||||
for (String key : removeLaterList) { |
||||
removeFromTemplateInfoList(key); |
||||
} |
||||
|
||||
saveInfo(); |
||||
} |
||||
|
||||
/** |
||||
* 获取缓存文件存放路径 |
||||
*/ |
||||
private static File getInfoFile() { |
||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), XML_FILE_NAME)); |
||||
} |
||||
|
||||
void loadFromFile() { |
||||
if (!getInfoFile().exists()) { |
||||
return; |
||||
} |
||||
|
||||
XMLableReader reader = null; |
||||
try (InputStream in = new FileInputStream(getInfoFile())) { |
||||
// XMLableReader 还是应该考虑实现 Closable 接口的,这样就能使用 try-with 语句了
|
||||
reader = XMLReadHelper.createXMLableReader(in, XMLPrintWriter.XML_ENCODER); |
||||
reader.readXMLObject(this); |
||||
} catch (FileNotFoundException e) { |
||||
// do nothing
|
||||
} catch (XMLStreamException | IOException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} finally { |
||||
try { |
||||
if (reader != null) { |
||||
reader.close(); |
||||
} |
||||
} catch (XMLStreamException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
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 { |
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); |
||||
XMLTools.writeOutputStreamXML(this, out); |
||||
out.flush(); |
||||
out.close(); |
||||
String fileContent = new String(out.toByteArray(), StandardCharsets.UTF_8); |
||||
FileUtils.writeStringToFile(getInfoFile(), fileContent, StandardCharsets.UTF_8); |
||||
} catch (Exception ex) { |
||||
FineLoggerFactory.getLogger().error(ex.getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 更新 day_count:打开设计器却未编辑模板的连续日子 |
||||
*/ |
||||
private void addIdleDayCount() { |
||||
// 判断今天是否第一次打开设计器,为了防止同一天内,多次 addIdleDayCount
|
||||
if (designerOpenHistory.hasOpenedToday()) { |
||||
return; |
||||
} |
||||
for (TemplateInfo templateInfo : templateInfoMap.values()) { |
||||
templateInfo.addIdleDayCountByOne(); |
||||
} |
||||
designerOpenHistory.update(); |
||||
} |
||||
|
||||
// 删除所有已完成的测试模版
|
||||
private void removeTestTemplates() { |
||||
ArrayList<String> testTemplateKeys = new ArrayList<>(); // 保存测试模板的key
|
||||
for (String key : templateInfoMap.keySet()) { |
||||
if (templateInfoMap.get(key).isTestTemplate()) { |
||||
testTemplateKeys.add(key); |
||||
} |
||||
} |
||||
// 删除测试模板
|
||||
for (String key : testTemplateKeys) { |
||||
removeFromTemplateInfoList(key); |
||||
} |
||||
} |
||||
|
||||
private void removeFromTemplateInfoList(String key) { |
||||
templateInfoMap.remove(key); |
||||
} |
||||
|
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (reader.isChildNode()) { |
||||
try { |
||||
String name = reader.getTagName(); |
||||
if (DesignerOpenHistory.XML_TAG.equals(name)) { |
||||
reader.readXMLObject(designerOpenHistory); |
||||
} else if (TemplateInfo.XML_TAG.equals(name)) { |
||||
TemplateInfo templateInfo = TemplateInfo.newInstanceByRead(reader); |
||||
templateInfoMap.put(templateInfo.getTemplateID(), templateInfo); |
||||
} |
||||
} catch (Exception ex) { |
||||
// 什么也不做,使用默认值
|
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TAG); |
||||
|
||||
designerOpenHistory.writeXML(writer); |
||||
|
||||
writer.startTAG(XML_TEMPLATE_INFO_LIST); |
||||
for (TemplateInfo templateInfo : templateInfoMap.values()) { |
||||
templateInfo.writeXML(writer); |
||||
} |
||||
writer.end(); |
||||
|
||||
writer.end(); |
||||
} |
||||
} |
@ -1,10 +1,14 @@
|
||||
package com.fr.design.mainframe.templateinfo; |
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
import com.fr.base.io.BaseBook; |
||||
|
||||
/** |
||||
* Created by plough on 2017/3/17. |
||||
*/ |
||||
// todo: 重构
|
||||
// 1. 命名不好,表意不清晰。
|
||||
// 2. 逻辑混乱,到底是一个 Info 类,还是一个 InfoCollector 类?
|
||||
// 3. 耦合太强,用组合替代继承
|
||||
public abstract class TemplateProcessInfo<T extends BaseBook> { |
||||
|
||||
protected T template; |
@ -0,0 +1,69 @@
|
||||
package com.fr.design.mainframe.template.info; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/19. |
||||
*/ |
||||
public class TimeConsumeTimer { |
||||
private static final int ONE_THOUSAND = 1000; |
||||
private enum State { |
||||
RUNNING, STOPPED |
||||
} |
||||
private int timeConsume; // 单位 s
|
||||
private long startMS; // 单位 ms
|
||||
private long stopMS; |
||||
private State state; |
||||
private boolean enabled; |
||||
|
||||
public TimeConsumeTimer() { |
||||
reset(); |
||||
} |
||||
|
||||
public boolean isEnabled() { |
||||
return enabled; |
||||
} |
||||
|
||||
public void setEnabled(boolean enabled) { |
||||
this.enabled = enabled; |
||||
} |
||||
|
||||
public void start() { |
||||
if (!isEnabled() || isRunning()) { |
||||
return; |
||||
} |
||||
startMS = System.currentTimeMillis(); |
||||
state = State.RUNNING; |
||||
} |
||||
|
||||
public void stop() { |
||||
if (!isEnabled() || !isRunning()) { |
||||
return; |
||||
} |
||||
stopMS = System.currentTimeMillis(); |
||||
|
||||
timeConsume += ((stopMS - startMS) / ONE_THOUSAND); |
||||
startMS = 0; |
||||
stopMS = 0; |
||||
state = State.STOPPED; |
||||
} |
||||
|
||||
public int popTime() { |
||||
if (!isEnabled()) { |
||||
return 0; |
||||
} |
||||
stop(); |
||||
int result = timeConsume; |
||||
reset(); |
||||
return result; |
||||
} |
||||
|
||||
private boolean isRunning() { |
||||
return state == State.RUNNING; |
||||
} |
||||
|
||||
private void reset() { |
||||
timeConsume = 0; |
||||
startMS = 0; |
||||
stopMS = 0; |
||||
state = State.STOPPED; |
||||
} |
||||
} |
@ -1,550 +0,0 @@
|
||||
package com.fr.design.mainframe.templateinfo; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.base.io.BaseBook; |
||||
import com.fr.config.MarketConfig; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.JTemplate; |
||||
import com.fr.design.mainframe.SiteCenterToken; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.general.IOUtils; |
||||
import com.fr.general.http.HttpClient; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.EncodeConstants; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLTools; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
||||
import com.fr.workspace.WorkContext; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.Serializable; |
||||
import java.io.UnsupportedEncodingException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.ArrayList; |
||||
import java.util.Calendar; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 做模板的过程和耗时收集,辅助类 |
||||
* Created by plough on 2017/2/21. |
||||
*/ |
||||
public class TemplateInfoCollector<T extends BaseBook> implements Serializable, XMLReadable, XMLWriter { |
||||
static final long serialVersionUID = 2007L; |
||||
private static final String FILE_NAME = "tpl.info"; |
||||
private static final String OBJECT_FILE_NAME = "tplInfo.ser"; |
||||
private static final int VALID_CELL_COUNT = 5; // 有效报表模板的格子数
|
||||
private static final int VALID_WIDGET_COUNT = 5; // 有效报表模板的控件数
|
||||
private static final int COMPLETE_DAY_COUNT = 15; // 判断模板是否完成的天数
|
||||
private static final int ONE_THOUSAND = 1000; |
||||
private static final String XML_DESIGNER_OPEN_DATE = "DesignerOpenDate"; |
||||
private static final String XML_TEMPLATE_INFO_LIST = "TemplateInfoList"; |
||||
private static final String XML_TEMPLATE_INFO = "TemplateInfo"; |
||||
private static final String XML_PROCESS_MAP = "processMap"; |
||||
private static final String XML_CONSUMING_MAP = "consumingMap"; |
||||
private static final String ATTR_DAY_COUNT = "day_count"; |
||||
private static final String ATTR_TEMPLATE_ID = "templateID"; |
||||
private static final String ATTR_PROCESS = "process"; |
||||
private static final String ATTR_FLOAT_COUNT = "float_count"; |
||||
private static final String ATTR_WIDGET_COUNT = "widget_count"; |
||||
private static final String ATTR_CELL_COUNT = "cell_count"; |
||||
private static final String ATTR_BLOCK_COUNT = "block_count"; |
||||
private static final String ATTR_REPORT_TYPE = "report_type"; |
||||
private static final String ATTR_ACTIVITYKEY = "activitykey"; |
||||
private static final String ATTR_JAR_TIME = "jar_time"; |
||||
private static final String ATTR_CREATE_TIME = "create_time"; |
||||
private static final String ATTR_UUID = "uuid"; |
||||
private static final String ATTR_TIME_CONSUME = "time_consume"; |
||||
private static final String ATTR_VERSION = "version"; |
||||
private static final String ATTR_USERNAME = "username"; |
||||
private static final String JSON_CONSUMING_MAP = "jsonConsumingMap"; |
||||
private static final String JSON_PROCESS_MAP = "jsonProcessMap"; |
||||
private static TemplateInfoCollector instance; |
||||
private Map<String, HashMap<String, Object>> templateInfoList; |
||||
private String designerOpenDate; //设计器最近一次打开日期
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private TemplateInfoCollector() { |
||||
templateInfoList = new HashMap<>(); |
||||
setDesignerOpenDate(); |
||||
} |
||||
|
||||
/** |
||||
* 获取缓存文件存放路径 |
||||
*/ |
||||
private static File getInfoFile() { |
||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), FILE_NAME)); |
||||
} |
||||
|
||||
private static File getObjectInfoFile() { |
||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), OBJECT_FILE_NAME)); |
||||
} |
||||
|
||||
public static TemplateInfoCollector getInstance() { |
||||
if (instance == null) { |
||||
instance = new TemplateInfoCollector(); |
||||
readXMLFile(instance, getInfoFile()); |
||||
// 兼容过渡。如果没有新文件,则从老文件读取数据。以后都是读写新的 xml 文件
|
||||
if (!getInfoFile().exists() && getObjectInfoFile().exists()) { |
||||
try { |
||||
ObjectInputStream is = new ObjectInputStream(new FileInputStream(getObjectInfoFile())); |
||||
instance = (TemplateInfoCollector) is.readObject(); |
||||
} catch (Exception ex) { |
||||
// 什么也不做,instance 使用新值
|
||||
} |
||||
} |
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
private static void readXMLFile(XMLReadable xmlReadable, File xmlFile) { |
||||
if (xmlFile == null || !xmlFile.exists()) { |
||||
return; |
||||
} |
||||
String charset = EncodeConstants.ENCODING_UTF_8; |
||||
try { |
||||
String fileContent = getFileContent(xmlFile); |
||||
InputStream xmlInputStream = new ByteArrayInputStream(fileContent.getBytes(charset)); |
||||
InputStreamReader inputStreamReader = new InputStreamReader(xmlInputStream, charset); |
||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(inputStreamReader); |
||||
|
||||
if (xmlReader != null) { |
||||
xmlReader.readXMLObject(xmlReadable); |
||||
} |
||||
xmlInputStream.close(); |
||||
} catch (FileNotFoundException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} catch (IOException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} catch (XMLStreamException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static String getFileContent(File xmlFile) throws FileNotFoundException, UnsupportedEncodingException { |
||||
InputStream is = new FileInputStream(xmlFile); |
||||
return IOUtils.inputStream2String(is); |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
TemplateInfoCollector tic = TemplateInfoCollector.getInstance(); |
||||
tic.sendTemplateInfo(); |
||||
} |
||||
|
||||
/** |
||||
* 把设计器最近打开日期设定为当前日期 |
||||
*/ |
||||
private void setDesignerOpenDate() { |
||||
designerOpenDate = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
||||
} |
||||
|
||||
/** |
||||
* 判断今天是否第一次打开设计器 |
||||
*/ |
||||
private boolean designerOpenFirstTime() { |
||||
String today = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
||||
return !ComparatorUtils.equals(today, designerOpenDate); |
||||
} |
||||
|
||||
private boolean shouldCollectInfo() { |
||||
//只收集本地环境的
|
||||
if (!WorkContext.getCurrent().isLocal()) { |
||||
return false; |
||||
} |
||||
return DesignerEnvManager.getEnvManager().isJoinProductImprove() && FRContext.isChineseEnv(); |
||||
} |
||||
|
||||
public void appendProcess(String log) { |
||||
if (!shouldCollectInfo()) { |
||||
return; |
||||
} |
||||
// 获取当前编辑的模板
|
||||
JTemplate jt = DesignerContext.getDesignerFrame().getSelectedJTemplate(); |
||||
// 追加过程记录
|
||||
jt.appendProcess(log); |
||||
} |
||||
|
||||
/** |
||||
* 加载已经存储的模板过程 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public String loadProcess(T t) { |
||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfoList.get(t.getTemplateID()).get(XML_PROCESS_MAP); |
||||
return (String) processMap.get(ATTR_PROCESS); |
||||
} |
||||
|
||||
/** |
||||
* 根据模板ID是否在收集列表中,判断是否需要收集当前模板的信息 |
||||
*/ |
||||
public boolean inList(T t) { |
||||
return templateInfoList.containsKey(t.getTemplateID()); |
||||
} |
||||
|
||||
/** |
||||
* 将包含所有信息的对象保存到文件 |
||||
*/ |
||||
private void saveInfo() { |
||||
try { |
||||
FileOutputStream out = new FileOutputStream(getInfoFile()); |
||||
XMLTools.writeOutputStreamXML(this, out); |
||||
} catch (Exception ex) { |
||||
FineLoggerFactory.getLogger().error(ex.getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 更新 day_count:打开设计器却未编辑模板的连续日子 |
||||
*/ |
||||
private void addDayCount() { |
||||
if (designerOpenFirstTime()) { |
||||
for (String key : templateInfoList.keySet()) { |
||||
HashMap<String, Object> templateInfo = templateInfoList.get(key); |
||||
int dayCount = (int) templateInfo.get(ATTR_DAY_COUNT) + 1; |
||||
templateInfo.put(ATTR_DAY_COUNT, dayCount); |
||||
} |
||||
setDesignerOpenDate(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 收集模板信息。如果之前没有记录,则新增;如果已有记录,则更新。 |
||||
* 同时将最新数据保存到文件中。 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public void collectInfo(T t, JTemplate jt, long openTime, long saveTime) { |
||||
if (!shouldCollectInfo()) { |
||||
return; |
||||
} |
||||
|
||||
HashMap<String, Object> templateInfo; |
||||
|
||||
long timeConsume = ((saveTime - openTime) / ONE_THOUSAND); // 制作模板耗时(单位:s)
|
||||
String templateID = t.getTemplateID(); |
||||
|
||||
if (inList(t)) { // 已有记录
|
||||
templateInfo = templateInfoList.get(templateID); |
||||
// 更新 conusmingMap
|
||||
HashMap<String, Object> consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
||||
timeConsume += (long) consumingMap.get(ATTR_TIME_CONSUME); // 加上之前的累计编辑时间
|
||||
consumingMap.put(ATTR_TIME_CONSUME, timeConsume); |
||||
} else { // 新增
|
||||
templateInfo = new HashMap<>(); |
||||
templateInfo.put(XML_CONSUMING_MAP, getNewConsumingMap(templateID, openTime, timeConsume)); |
||||
} |
||||
|
||||
// 直接覆盖 processMap
|
||||
templateInfo.put(XML_PROCESS_MAP, getProcessMap(templateID, jt)); |
||||
|
||||
// 保存模板时,让 day_count 归零
|
||||
templateInfo.put(ATTR_DAY_COUNT, 0); |
||||
|
||||
templateInfoList.put(templateID, templateInfo); |
||||
|
||||
saveInfo(); // 每次更新之后,都同步到暂存文件中
|
||||
} |
||||
|
||||
private HashMap<String, Object> getNewConsumingMap(String templateID, long openTime, long timeConsume) { |
||||
HashMap<String, Object> consumingMap = new HashMap<>(); |
||||
|
||||
String username = MarketConfig.getInstance().getBbsUsername(); |
||||
String uuid = DesignerEnvManager.getEnvManager().getUUID(); |
||||
String activitykey = DesignerEnvManager.getEnvManager().getActivationKey(); |
||||
String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(Calendar.getInstance().getTime()); |
||||
String jarTime = GeneralUtils.readBuildNO(); |
||||
String version = ProductConstants.VERSION; |
||||
consumingMap.put(ATTR_USERNAME, username); |
||||
consumingMap.put(ATTR_UUID, uuid); |
||||
consumingMap.put(ATTR_ACTIVITYKEY, activitykey); |
||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
consumingMap.put(ATTR_CREATE_TIME, createTime); |
||||
consumingMap.put(ATTR_TIME_CONSUME, timeConsume); |
||||
consumingMap.put(ATTR_JAR_TIME, jarTime); |
||||
consumingMap.put(ATTR_VERSION, version); |
||||
|
||||
return consumingMap; |
||||
} |
||||
|
||||
private HashMap<String, Object> getProcessMap(String templateID, JTemplate jt) { |
||||
HashMap<String, Object> processMap = new HashMap<>(); |
||||
|
||||
processMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
processMap.put(ATTR_PROCESS, jt.getProcess()); |
||||
|
||||
TemplateProcessInfo info = jt.getProcessInfo(); |
||||
processMap.put(ATTR_REPORT_TYPE, info.getReportType()); |
||||
processMap.put(ATTR_CELL_COUNT, info.getCellCount()); |
||||
processMap.put(ATTR_FLOAT_COUNT, info.getFloatCount()); |
||||
processMap.put(ATTR_BLOCK_COUNT, info.getBlockCount()); |
||||
processMap.put(ATTR_WIDGET_COUNT, info.getWidgetCount()); |
||||
|
||||
return processMap; |
||||
} |
||||
|
||||
/** |
||||
* 发送本地模板信息到服务器 |
||||
*/ |
||||
public void sendTemplateInfo() { |
||||
addDayCount(); |
||||
String consumingUrl = CloudCenter.getInstance().acquireUrlByKind("tempinfo.consuming") + "/single"; |
||||
String processUrl = CloudCenter.getInstance().acquireUrlByKind("tempinfo.process") + "/single"; |
||||
ArrayList<HashMap<String, String>> completeTemplatesInfo = getCompleteTemplatesInfo(); |
||||
for (HashMap<String, String> templateInfo : completeTemplatesInfo) { |
||||
String jsonConsumingMap = templateInfo.get(JSON_CONSUMING_MAP); |
||||
String jsonProcessMap = templateInfo.get(JSON_PROCESS_MAP); |
||||
if (sendSingleTemplateInfo(consumingUrl, jsonConsumingMap) && sendSingleTemplateInfo(processUrl, jsonProcessMap)) { |
||||
// 清空记录
|
||||
removeFromTemplateInfoList(templateInfo.get(ATTR_TEMPLATE_ID)); |
||||
} |
||||
} |
||||
saveInfo(); |
||||
} |
||||
|
||||
private boolean sendSingleTemplateInfo(String url, String content) { |
||||
HashMap<String, String> para = new HashMap<>(); |
||||
para.put("token", SiteCenterToken.generateToken()); |
||||
para.put("content", content); |
||||
HttpClient httpClient = new HttpClient(url, para, true); |
||||
httpClient.setTimeout(5000); |
||||
httpClient.asGet(); |
||||
|
||||
if (!httpClient.isServerAlive()) { |
||||
return false; |
||||
} |
||||
|
||||
String res = httpClient.getResponseText(); |
||||
boolean success; |
||||
try { |
||||
success = ComparatorUtils.equals(new JSONObject(res).get("status"), "success"); |
||||
} catch (Exception ex) { |
||||
success = false; |
||||
} |
||||
return success; |
||||
} |
||||
|
||||
/** |
||||
* 返回已完成的模板信息 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
private ArrayList<HashMap<String, String>> getCompleteTemplatesInfo() { |
||||
ArrayList<HashMap<String, String>> completeTemplatesInfo = new ArrayList<>(); |
||||
ArrayList<String> testTemplateKeys = new ArrayList<>(); // 保存测试模板的key
|
||||
for (String key : templateInfoList.keySet()) { |
||||
HashMap<String, Object> templateInfo = templateInfoList.get(key); |
||||
if ((int) templateInfo.get(ATTR_DAY_COUNT) <= COMPLETE_DAY_COUNT) { // 未完成模板
|
||||
continue; |
||||
} |
||||
if (isTestTemplate(templateInfo)) { |
||||
testTemplateKeys.add(key); |
||||
continue; |
||||
} |
||||
HashMap<String, Object> consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
||||
String jsonConsumingMap = new JSONObject(consumingMap).toString(); |
||||
String jsonProcessMap = new JSONObject(processMap).toString(); |
||||
HashMap<String, String> jsonTemplateInfo = new HashMap<>(); |
||||
jsonTemplateInfo.put(JSON_CONSUMING_MAP, jsonConsumingMap); |
||||
jsonTemplateInfo.put(JSON_PROCESS_MAP, jsonProcessMap); |
||||
jsonTemplateInfo.put(ATTR_TEMPLATE_ID, key); |
||||
completeTemplatesInfo.add(jsonTemplateInfo); |
||||
} |
||||
// 删除测试模板
|
||||
for (String key : testTemplateKeys) { |
||||
removeFromTemplateInfoList(key); |
||||
} |
||||
return completeTemplatesInfo; |
||||
} |
||||
|
||||
private void removeFromTemplateInfoList(String key) { |
||||
templateInfoList.remove(key); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private boolean isTestTemplate(HashMap<String, Object> templateInfo) { |
||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
||||
int reportType = (int) processMap.get(ATTR_REPORT_TYPE); |
||||
int cellCount = (int) processMap.get(ATTR_CELL_COUNT); |
||||
int floatCount = (int) processMap.get(ATTR_FLOAT_COUNT); |
||||
int blockCount = (int) processMap.get(ATTR_BLOCK_COUNT); |
||||
int widgetCount = (int) processMap.get(ATTR_WIDGET_COUNT); |
||||
boolean isTestTemplate = false; |
||||
if (reportType == 0) { // 普通报表
|
||||
isTestTemplate = cellCount <= VALID_CELL_COUNT && floatCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
||||
} else if (reportType == 1) { // 聚合报表
|
||||
isTestTemplate = blockCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
||||
} else { // 表单(reportType == 2)
|
||||
isTestTemplate = widgetCount <= 1; |
||||
} |
||||
return isTestTemplate; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (reader.isChildNode()) { |
||||
try { |
||||
String name = reader.getTagName(); |
||||
if (XML_DESIGNER_OPEN_DATE.equals(name)) { |
||||
this.designerOpenDate = reader.getElementValue(); |
||||
} else if (XML_TEMPLATE_INFO_LIST.equals(name)) { |
||||
readTemplateInfoList(reader); |
||||
} |
||||
} catch (Exception ex) { |
||||
// 什么也不做,使用默认值
|
||||
} |
||||
} |
||||
} |
||||
|
||||
private void readTemplateInfoList(XMLableReader reader) { |
||||
reader.readXMLObject(new XMLReadable() { |
||||
public void readXML(XMLableReader reader) { |
||||
if (XML_TEMPLATE_INFO.equals(reader.getTagName())) { |
||||
TemplateInfo templateInfo = new TemplateInfo(); |
||||
reader.readXMLObject(templateInfo); |
||||
templateInfoList.put(templateInfo.getTemplateID(), templateInfo.getTemplateInfo()); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG("TplInfo"); |
||||
|
||||
writer.startTAG(XML_DESIGNER_OPEN_DATE); |
||||
writer.textNode(designerOpenDate); |
||||
writer.end(); |
||||
|
||||
writeTemplateInfoList(writer); |
||||
|
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeTemplateInfoList(XMLPrintWriter writer) { |
||||
//启停
|
||||
writer.startTAG(XML_TEMPLATE_INFO_LIST); |
||||
for (String templateID : templateInfoList.keySet()) { |
||||
new TemplateInfo(templateInfoList.get(templateID)).writeXML(writer); |
||||
} |
||||
writer.end(); |
||||
} |
||||
|
||||
private class TemplateInfo implements XMLReadable, XMLWriter { |
||||
|
||||
private int dayCount; |
||||
private String templateID; |
||||
private HashMap<String, Object> processMap = new HashMap<>(); |
||||
private HashMap<String, Object> consumingMap = new HashMap<>(); |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public TemplateInfo(HashMap<String, Object> templateInfo) { |
||||
this.dayCount = (int) templateInfo.get(ATTR_DAY_COUNT); |
||||
this.processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
||||
this.consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
||||
this.templateID = (String) processMap.get(ATTR_TEMPLATE_ID); |
||||
} |
||||
|
||||
public TemplateInfo() { |
||||
} |
||||
|
||||
public String getTemplateID() { |
||||
return templateID; |
||||
} |
||||
|
||||
public HashMap<String, Object> getTemplateInfo() { |
||||
HashMap<String, Object> templateInfo = new HashMap<>(); |
||||
templateInfo.put(XML_PROCESS_MAP, processMap); |
||||
templateInfo.put(XML_CONSUMING_MAP, consumingMap); |
||||
templateInfo.put(ATTR_DAY_COUNT, dayCount); |
||||
return templateInfo; |
||||
} |
||||
|
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TEMPLATE_INFO); |
||||
if (StringUtils.isNotEmpty(templateID)) { |
||||
writer.attr(ATTR_TEMPLATE_ID, this.templateID); |
||||
} |
||||
if (dayCount >= 0) { |
||||
writer.attr(ATTR_DAY_COUNT, this.dayCount); |
||||
} |
||||
writeProcessMap(writer); |
||||
writeConsumingMap(writer); |
||||
|
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeProcessMap(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_PROCESS_MAP); |
||||
writer.attr(ATTR_PROCESS, (String) processMap.get(ATTR_PROCESS)); |
||||
writer.attr(ATTR_FLOAT_COUNT, (int) processMap.get(ATTR_FLOAT_COUNT)); |
||||
writer.attr(ATTR_WIDGET_COUNT, (int) processMap.get(ATTR_WIDGET_COUNT)); |
||||
writer.attr(ATTR_CELL_COUNT, (int) processMap.get(ATTR_CELL_COUNT)); |
||||
writer.attr(ATTR_BLOCK_COUNT, (int) processMap.get(ATTR_BLOCK_COUNT)); |
||||
writer.attr(ATTR_REPORT_TYPE, (int) processMap.get(ATTR_REPORT_TYPE)); |
||||
writer.end(); |
||||
} |
||||
|
||||
private void writeConsumingMap(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_CONSUMING_MAP); |
||||
writer.attr(ATTR_ACTIVITYKEY, (String) consumingMap.get(ATTR_ACTIVITYKEY)); |
||||
writer.attr(ATTR_JAR_TIME, (String) consumingMap.get(ATTR_JAR_TIME)); |
||||
writer.attr(ATTR_CREATE_TIME, (String) consumingMap.get(ATTR_CREATE_TIME)); |
||||
writer.attr(ATTR_UUID, (String) consumingMap.get(ATTR_UUID)); |
||||
writer.attr(ATTR_TIME_CONSUME, (long) consumingMap.get(ATTR_TIME_CONSUME)); |
||||
writer.attr(ATTR_VERSION, (String) consumingMap.get(ATTR_VERSION)); |
||||
writer.attr(ATTR_USERNAME, (String) consumingMap.get(ATTR_USERNAME)); |
||||
writer.end(); |
||||
} |
||||
|
||||
public void readXML(XMLableReader reader) { |
||||
if (!reader.isChildNode()) { |
||||
dayCount = reader.getAttrAsInt(ATTR_DAY_COUNT, 0); |
||||
templateID = reader.getAttrAsString(ATTR_TEMPLATE_ID, StringUtils.EMPTY); |
||||
} else { |
||||
try { |
||||
String name = reader.getTagName(); |
||||
if (XML_PROCESS_MAP.equals(name)) { |
||||
processMap.put(ATTR_PROCESS, reader.getAttrAsString(ATTR_PROCESS, StringUtils.EMPTY)); |
||||
processMap.put(ATTR_FLOAT_COUNT, reader.getAttrAsInt(ATTR_FLOAT_COUNT, 0)); |
||||
processMap.put(ATTR_WIDGET_COUNT, reader.getAttrAsInt(ATTR_WIDGET_COUNT, 0)); |
||||
processMap.put(ATTR_CELL_COUNT, reader.getAttrAsInt(ATTR_CELL_COUNT, 0)); |
||||
processMap.put(ATTR_BLOCK_COUNT, reader.getAttrAsInt(ATTR_BLOCK_COUNT, 0)); |
||||
processMap.put(ATTR_REPORT_TYPE, reader.getAttrAsInt(ATTR_REPORT_TYPE, 0)); |
||||
processMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
} else if (XML_CONSUMING_MAP.equals(name)) { |
||||
consumingMap.put(ATTR_ACTIVITYKEY, reader.getAttrAsString(ATTR_ACTIVITYKEY, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_JAR_TIME, reader.getAttrAsString(ATTR_JAR_TIME, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_CREATE_TIME, reader.getAttrAsString(ATTR_CREATE_TIME, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
||||
consumingMap.put(ATTR_UUID, reader.getAttrAsString(ATTR_UUID, StringUtils.EMPTY)); |
||||
consumingMap.put(ATTR_TIME_CONSUME, reader.getAttrAsLong(ATTR_TIME_CONSUME, 0)); |
||||
consumingMap.put(ATTR_VERSION, reader.getAttrAsString(ATTR_VERSION, "8.0")); |
||||
consumingMap.put(ATTR_USERNAME, reader.getAttrAsString(ATTR_USERNAME, StringUtils.EMPTY)); |
||||
} |
||||
} catch (Exception ex) { |
||||
// 什么也不做,使用默认值
|
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,74 @@
|
||||
package com.fr.design.mainframe.vcs; |
||||
|
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
|
||||
/** |
||||
* Created by XiaXiang on 2019/4/26. |
||||
*/ |
||||
public class VcsConfigManager implements XMLReadable, XMLWriter { |
||||
public static final String XML_TAG = "VcsConfigManager"; |
||||
private static volatile VcsConfigManager instance = new VcsConfigManager(); |
||||
private boolean vcsEnable = true; |
||||
private boolean saveCommit = true; |
||||
private boolean useInterval = true; |
||||
private int saveInterval = 60; |
||||
|
||||
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,75 @@
|
||||
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.WorkResourceOutputStream; |
||||
import com.fr.workspace.server.lock.TplOperator; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
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() throws Exception { |
||||
if (node == null) { |
||||
return null; |
||||
} |
||||
|
||||
String envPath = node.getEnvPath(); |
||||
// envPath必须以vcs开头
|
||||
if (!envPath.startsWith(VcsHelper.VCS_CACHE_DIR)) { |
||||
return null; |
||||
} |
||||
|
||||
InputStream in = new ByteArrayInputStream( |
||||
WorkContext.getCurrent().get(TplOperator.class).readAndLockFile( |
||||
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,177 @@
|
||||
package com.fr.design.mainframe.vcs.common; |
||||
|
||||
import com.fr.cluster.engine.base.FineClusterConfig; |
||||
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.JTemplateActionListener; |
||||
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 implements JTemplateActionListener { |
||||
|
||||
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_MEDIUM = new EmptyBorder(5, 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"); |
||||
public final static int OFFSET = 2; |
||||
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"; |
||||
private static final VcsHelper instance = new VcsHelper(); |
||||
|
||||
public static VcsHelper getInstance() { |
||||
return instance; |
||||
} |
||||
|
||||
private 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; |
||||
} |
||||
|
||||
public String getCurrentUsername() { |
||||
return WorkContext.getCurrent().isLocal() |
||||
? Toolkit.i18nText("Fine-Design_Vcs_Local_User") |
||||
: WorkContext.getCurrent().getConnection().getUserName(); |
||||
} |
||||
|
||||
private int selectedTemplateCounts() { |
||||
TemplateFileTree fileTree = TemplateTreePane.getInstance().getTemplateFileTree(); |
||||
if (fileTree.getSelectionPaths() == null) { |
||||
return 0; |
||||
} |
||||
|
||||
return fileTree.getSelectedTemplatePaths().length; |
||||
} |
||||
|
||||
public boolean isUnSelectedTemplate() { |
||||
return containsFolderCounts() + selectedTemplateCounts() != 1; |
||||
} |
||||
|
||||
private 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; |
||||
} |
||||
|
||||
private boolean needDeleteVersion(VcsEntity entity) { |
||||
VcsConfigManager configManager = DesignerEnvManager.getEnvManager().getVcsConfigManager(); |
||||
if (entity == null || !configManager.isUseInterval()) { |
||||
return false; |
||||
} |
||||
if (configManager.isSaveCommit() && StringUtils.isNotBlank(entity.getCommitMsg())) { |
||||
return false; |
||||
} |
||||
return new Date().getTime() - entity.getTime().getTime() < DesignerEnvManager.getEnvManager().getVcsConfigManager().getSaveInterval() * MINUTE; |
||||
} |
||||
|
||||
public boolean needInit() { |
||||
PluginContext context = PluginManager.getContext(VCS_PLUGIN_ID); |
||||
return context == null || !context.isRunning(); |
||||
} |
||||
|
||||
/** |
||||
* 版本控制 |
||||
* |
||||
* @param jt |
||||
*/ |
||||
public void fireVcs(final JTemplate jt) { |
||||
new Thread(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
|
||||
String fileName = 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(getCurrentUsername(), 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(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1); |
||||
} |
||||
VcsEntity oldEntity = WorkContext.getCurrent().get(VcsOperator.class).getFileVersionByIndexAndUsername(fileName, getCurrentUsername(), 1); |
||||
if (needDeleteVersion(oldEntity)) { |
||||
operator.deleteVersion(oldEntity.getFilename(), oldEntity.getVersion()); |
||||
} |
||||
|
||||
} |
||||
}).start(); |
||||
|
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void templateOpened(JTemplate<?, ?> jt) { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 模板保存时 处理. |
||||
* |
||||
* @param jt 模板 |
||||
*/ |
||||
@Override |
||||
public void templateSaved(JTemplate<?, ?> jt) { |
||||
if (needInit() && DesignerEnvManager.getEnvManager().getVcsConfigManager().isVcsEnable() && !FineClusterConfig.getInstance().isCluster()) { |
||||
fireVcs(jt); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void templateClosed(JTemplate<?, ?> jt) { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,104 @@
|
||||
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.mainframe.DesignerFrameFileDealerPane; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
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.JPanel; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Component; |
||||
import java.awt.FlowLayout; |
||||
import java.awt.Frame; |
||||
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()); |
||||
WorkContext.getCurrent().get(VcsOperator.class).updateVersion(entity); |
||||
setVisible(false); |
||||
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); |
||||
FileVersionTable table = FileVersionTable.getInstance(); |
||||
table.updateModel(table.getSelectedRow(), WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", StringUtils.EMPTY))); |
||||
} |
||||
}); |
||||
|
||||
cancel.addActionListener(new ActionListener() { |
||||
public void actionPerformed(ActionEvent e) { |
||||
doCancel(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void checkValid() throws Exception { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,80 @@
|
||||
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.general.ComparatorUtils; |
||||
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; |
||||
VcsOperator vcsOperator = WorkContext.getCurrent().get(VcsOperator.class); |
||||
Component editor = row == 0 ? firstRowPanel : renderAndEditor; |
||||
if (isSelected) { |
||||
return editor; |
||||
} else if (row == 0) { |
||||
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); |
||||
fileOfVersion = vcsOperator.getFileOfCurrent(path.replaceFirst("/", "")); |
||||
} else { |
||||
renderAndEditor.update((VcsEntity) value); |
||||
fileOfVersion = vcsOperator.getFileOfFileVersion(((VcsEntity) value).getFilename(), ((VcsEntity) value).getVersion()); |
||||
|
||||
} |
||||
|
||||
editor.setBackground(VcsHelper.TABLE_SELECT_BACKGROUND); |
||||
if (StringUtils.isNotEmpty(fileOfVersion)) { |
||||
//先关闭当前打开的模板版本
|
||||
JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); |
||||
jt.stopEditing(); |
||||
//只有模板路径一致时关闭当前模板
|
||||
if (ComparatorUtils.equals(fileOfVersion, jt.getPath())) { |
||||
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 + VcsHelper.OFFSET); |
||||
} |
||||
return editor; |
||||
} |
||||
|
||||
@Override |
||||
public Object getCellEditorValue() { |
||||
return renderAndEditor.getVcsEntity(); |
||||
} |
||||
} |
@ -0,0 +1,44 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.design.mainframe.vcs.common.VcsHelper; |
||||
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 + VcsHelper.OFFSET); |
||||
} |
||||
return editor; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,112 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.analysis.cloud.DateUtils; |
||||
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.BorderFactory; |
||||
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, final String fileName) { |
||||
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 VcsDateEditor(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 editorDate = dateEditor.getValue(); |
||||
Date start = editorDate == null ? new Date(0) : editorDate; |
||||
Date end = editorDate == null ? DateUtils.getLastHour() : new Date(start.getTime() + DELAY); |
||||
List<VcsEntity> vcsEntities = WorkContext.getCurrent().get(VcsOperator.class).getFilterVersions(fileName, start, end, textField.getText()); |
||||
FileVersionTable.getInstance().updateModel(1, vcsEntities); |
||||
|
||||
} |
||||
}); |
||||
cancelBtn.addActionListener(new AbstractAction() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
FileVersionDialog.this.setVisible(false); |
||||
} |
||||
}); |
||||
VcsLabel resetLabel = new VcsLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_resetValue"), VcsHelper.COPY_VERSION_BTN_COLOR); |
||||
resetLabel.setBorder(BorderFactory.createEmptyBorder(10, 160, 0, 10)); |
||||
resetLabel.addActionListener(new ActionListener() { |
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
dateEditor.setValue(null); |
||||
textField.setText(null); |
||||
FileVersionDialog.this.repaint(); |
||||
} |
||||
}); |
||||
panel.add(upBox, BorderLayout.NORTH); |
||||
panel.add(downBox, BorderLayout.CENTER); |
||||
panel.add(buttonPane, BorderLayout.SOUTH); |
||||
JPanel filterPane = new JPanel(new BorderLayout()); |
||||
filterPane.add(resetLabel, BorderLayout.NORTH); |
||||
filterPane.add(panel, BorderLayout.CENTER); |
||||
add(filterPane); |
||||
setSize(new Dimension(230, 125)); |
||||
centerWindow(frame); |
||||
} |
||||
|
||||
private void centerWindow(Window window) { |
||||
this.setLocation(window.getX(), 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_Current"))); |
||||
add(upPane, BorderLayout.CENTER); |
||||
} |
||||
} |
@ -0,0 +1,151 @@
|
||||
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_MEDIUM); |
||||
upPane.add(versionLabel); |
||||
upPane.add(Box.createHorizontalGlue()); |
||||
|
||||
|
||||
// msg
|
||||
msgLabel.setBorder(VcsHelper.EMPTY_BORDER_MEDIUM); |
||||
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) { |
||||
vcsEntity.setUsername(VcsHelper.getInstance().getCurrentUsername()); |
||||
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,201 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.base.GraphHelper; |
||||
import com.fr.design.base.mode.DesignModeContext; |
||||
import com.fr.design.base.mode.DesignerMode; |
||||
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.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() { |
||||
String savePath = templatePath.startsWith("/") ? templatePath.substring(1) : templatePath; |
||||
versionDialog = new FileVersionDialog(DesignerContext.getDesignerFrame(), savePath); |
||||
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 ? DesignerMode.NORMAL : 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); |
||||
} |
||||
} |
@ -0,0 +1,37 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
import com.fr.design.editor.editor.DateEditor; |
||||
import com.fr.log.FineLoggerFactory; |
||||
|
||||
import java.text.ParseException; |
||||
import java.util.Date; |
||||
|
||||
/** |
||||
* Created by XiaXiang on 2019/5/14. |
||||
*/ |
||||
public class VcsDateEditor extends DateEditor { |
||||
private Date tempValue; |
||||
|
||||
public VcsDateEditor(Date value, boolean format, String name, int dateFormat) { |
||||
super(value, format, name, dateFormat); |
||||
this.tempValue = value; |
||||
} |
||||
|
||||
@Override |
||||
public Date getValue() { |
||||
if (tempValue == null) { |
||||
return null; |
||||
} |
||||
return super.getValue(); |
||||
} |
||||
|
||||
@Override |
||||
public void setValue(Date value) { |
||||
this.tempValue = value; |
||||
try { |
||||
getUiDatePicker().setSelectedDate(value); |
||||
} catch (ParseException parseException) { |
||||
FineLoggerFactory.getLogger().error(parseException.getMessage(), parseException); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,32 @@
|
||||
package com.fr.design.mainframe.vcs.ui; |
||||
|
||||
|
||||
import com.fr.design.gui.ilable.ActionLabel; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
|
||||
import java.awt.Color; |
||||
import java.awt.Graphics; |
||||
|
||||
/** |
||||
* Created by XiaXiang on 2019/5/15. |
||||
*/ |
||||
public class VcsLabel extends ActionLabel { |
||||
|
||||
|
||||
public VcsLabel(String text, Color color) { |
||||
super(text); |
||||
this.setForeground(color); |
||||
} |
||||
|
||||
public void paintComponent(Graphics g) { |
||||
if (ui != null) { |
||||
Graphics scratchGraphics = (g == null) ? null : g.create(); |
||||
try { |
||||
ui.update(scratchGraphics, this); |
||||
} |
||||
finally { |
||||
scratchGraphics.dispose(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,9 +1,9 @@
|
||||
package com.fr.design.onlineupdate.actions; |
||||
package com.fr.design.update.actions; |
||||
|
||||
import com.fr.design.onlineupdate.domain.UpdateConstants; |
||||
import com.fr.design.update.domain.UpdateConstants; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.design.onlineupdate.domain.DownloadItem; |
||||
import com.fr.design.update.domain.DownloadItem; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StableUtils; |
||||
|
@ -1,10 +1,9 @@
|
||||
package com.fr.design.onlineupdate.actions; |
||||
package com.fr.design.update.actions; |
||||
|
||||
import com.fr.base.BaseUtils; |
||||
import com.fr.design.actions.UpdateAction; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.onlineupdate.ui.dialog.UpdateMainDialog; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import com.fr.design.update.ui.dialog.UpdateMainDialog; |
||||
|
||||
import java.awt.event.ActionEvent; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.domain; |
||||
package com.fr.design.update.domain; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.json.JSONObject; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.domain; |
||||
package com.fr.design.update.domain; |
||||
|
||||
/** |
||||
* Created by XINZAI on 2018/8/21. |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.domain; |
||||
package com.fr.design.update.domain; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.factory; |
||||
package com.fr.design.update.factory; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.ArrayUtils; |
@ -0,0 +1,61 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.xml.XMLPrintWriter; |
||||
import com.fr.stable.xml.XMLReadable; |
||||
import com.fr.stable.xml.XMLWriter; |
||||
import com.fr.stable.xml.XMLableReader; |
||||
|
||||
/** |
||||
* 持久化与设计器自动推送更新相关的配置 |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { |
||||
public static final String XML_TAG = "DesignerPushUpdateConfigManager"; |
||||
private static DesignerPushUpdateConfigManager singleton; |
||||
|
||||
private boolean autoPushUpdateEnabled = true; // 是否开启自动推送更新
|
||||
private String lastIgnoredVersion = StringUtils.EMPTY; // 最近一次跳过的更新版本
|
||||
|
||||
private DesignerPushUpdateConfigManager() { |
||||
} |
||||
|
||||
public static DesignerPushUpdateConfigManager getInstance() { |
||||
if (singleton == null) { |
||||
singleton = new DesignerPushUpdateConfigManager(); |
||||
} |
||||
return singleton; |
||||
} |
||||
|
||||
@Override |
||||
public void readXML(XMLableReader reader) { |
||||
if (reader.isAttr()) { |
||||
this.setAutoPushUpdateEnabled(reader.getAttrAsBoolean("autoPushUpdateEnabled", true)); |
||||
this.setLastIgnoredVersion(reader.getAttrAsString("lastIgnoredVersion", StringUtils.EMPTY)); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void writeXML(XMLPrintWriter writer) { |
||||
writer.startTAG(XML_TAG); |
||||
writer.attr("autoPushUpdateEnabled", autoPushUpdateEnabled); |
||||
writer.attr("lastIgnoredVersion", lastIgnoredVersion); |
||||
writer.end(); |
||||
} |
||||
|
||||
public boolean isAutoPushUpdateEnabled() { |
||||
return autoPushUpdateEnabled; |
||||
} |
||||
|
||||
public void setAutoPushUpdateEnabled(boolean autoPushUpdateEnabled) { |
||||
this.autoPushUpdateEnabled = autoPushUpdateEnabled; |
||||
} |
||||
|
||||
public String getLastIgnoredVersion() { |
||||
return lastIgnoredVersion; |
||||
} |
||||
|
||||
public void setLastIgnoredVersion(String lastIgnoredVersion) { |
||||
this.lastIgnoredVersion = lastIgnoredVersion; |
||||
} |
||||
} |
@ -0,0 +1,196 @@
|
||||
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 javax.swing.SwingUtilities; |
||||
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(final Frame parent, final DesignerUpdateInfo updateInfo) { |
||||
SwingUtilities.invokeLater(new Runnable() { |
||||
public void run() { |
||||
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.getLatestVersion()); |
||||
model.setContent(updateInfo.getPushContent()); |
||||
model.setMoreInfoUrl(updateInfo.getMoreInfoUrl()); |
||||
model.setBackgroundUrl(updateInfo.getBackgroundUrl()); |
||||
return model; |
||||
} |
||||
|
||||
@Override |
||||
public void checkValid() throws Exception { |
||||
// do nothing
|
||||
} |
||||
|
||||
/** |
||||
* 显示窗口 |
||||
*/ |
||||
private void showDialog() { |
||||
setSize(DEFAULT); |
||||
setUndecorated(true); |
||||
GUICoreUtils.centerWindow(this); |
||||
setVisible(true); |
||||
} |
||||
|
||||
public class Model { |
||||
private String version; |
||||
private String content; |
||||
private String moreInfoUrl; |
||||
private String backgroundUrl; |
||||
|
||||
public String getVersion() { |
||||
return version; |
||||
} |
||||
|
||||
public void setVersion(String version) { |
||||
this.version = version; |
||||
} |
||||
|
||||
public String getContent() { |
||||
return content; |
||||
} |
||||
|
||||
public void setContent(String content) { |
||||
this.content = content; |
||||
} |
||||
|
||||
public void browseMoreInfoUrl() { |
||||
if (StringUtils.isNotEmpty(moreInfoUrl)) { |
||||
BrowseUtils.browser(moreInfoUrl); |
||||
} |
||||
} |
||||
|
||||
public void setMoreInfoUrl(String moreInfoUrl) { |
||||
this.moreInfoUrl = moreInfoUrl; |
||||
} |
||||
|
||||
public String getBackgroundUrl() { |
||||
return backgroundUrl; |
||||
} |
||||
|
||||
public void setBackgroundUrl(String backgroundUrl) { |
||||
this.backgroundUrl = backgroundUrl; |
||||
} |
||||
|
||||
public void updateNow() { |
||||
DesignerPushUpdateManager.getInstance().doUpdate(); |
||||
FocusPointManager.submit(FocusPointManager.OperateType.UPDATE); |
||||
exit(); |
||||
} |
||||
|
||||
public void remindNextTime() { |
||||
FocusPointManager.submit(FocusPointManager.OperateType.REMIND_NEXT_TIME); |
||||
exit(); |
||||
} |
||||
|
||||
public void skipThisVersion() { |
||||
DesignerPushUpdateManager.getInstance().skipCurrentPushVersion(); |
||||
FocusPointManager.submit(FocusPointManager.OperateType.SKIP); |
||||
exit(); |
||||
} |
||||
|
||||
public void closeWindow() { |
||||
FocusPointManager.submit(FocusPointManager.OperateType.CLOSE_WINDOW); |
||||
exit(); |
||||
} |
||||
|
||||
public String i18nText(String key) { |
||||
return com.fr.design.i18n.Toolkit.i18nText(key); |
||||
} |
||||
|
||||
private void exit() { |
||||
DesignerPushUpdateDialog.this.dialogExit(); |
||||
} |
||||
} |
||||
|
||||
private static class FocusPointManager { |
||||
|
||||
private static final String ID = "com.fr.update.push"; |
||||
private static final String TITLE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Push_Update_Focus_Point"); |
||||
|
||||
private enum OperateType { |
||||
CLOSE_WINDOW(0), UPDATE(1), REMIND_NEXT_TIME(2), SKIP(3); |
||||
private int index; |
||||
OperateType(int index) { |
||||
this.index = index; |
||||
} |
||||
private String toText() { |
||||
return String.valueOf(this.index); |
||||
} |
||||
} |
||||
|
||||
private static void submit(OperateType opType) { |
||||
FocusPoint focusPoint = FocusPoint.create(ID, opType.toText(), Original.EMBED); |
||||
focusPoint.setTitle(TITLE); |
||||
MetricRegistry.getMetric().submit(focusPoint); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,168 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.design.event.DesignerOpenedListener; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.DesignerFrame; |
||||
import com.fr.design.update.ui.dialog.UpdateMainDialog; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.GeneralContext; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.general.http.HttpToolbox; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
public class DesignerPushUpdateManager { |
||||
private static final String SPLIT_CHAR = "-"; |
||||
private static DesignerPushUpdateManager singleton; |
||||
|
||||
private DesignerUpdateInfo updateInfo; |
||||
|
||||
static { |
||||
if (DesignerPushUpdateConfigManager.getInstance().isAutoPushUpdateEnabled()) { |
||||
DesignerContext.getDesignerFrame().addDesignerOpenedListener(new DesignerOpenedListener() { |
||||
@Override |
||||
public void designerOpened() { |
||||
getInstance().checkAndPop(); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
private DesignerPushUpdateManager() { |
||||
} |
||||
|
||||
public static DesignerPushUpdateManager getInstance() { |
||||
if (singleton == null) { |
||||
singleton = new DesignerPushUpdateManager(); |
||||
} |
||||
return singleton; |
||||
} |
||||
|
||||
private void initUpdateInfo(String currentVersion, String latestVersion) { |
||||
String lastIgnoredVersion = DesignerPushUpdateConfigManager.getInstance().getLastIgnoredVersion(); |
||||
String updatePushInfo = CloudCenter.getInstance().acquireUrlByKind("update.push"); |
||||
JSONObject pushData = new JSONObject(updatePushInfo); |
||||
|
||||
updateInfo = new DesignerUpdateInfo(currentVersion, latestVersion, lastIgnoredVersion, pushData); |
||||
} |
||||
|
||||
private String getFullLatestVersion() { |
||||
try { |
||||
String res = HttpToolbox.get(CloudCenter.getInstance().acquireUrlByKind("jar10.update")); |
||||
return new JSONObject(res).optString("buildNO"); |
||||
} catch (Throwable e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return StringUtils.EMPTY; |
||||
} |
||||
|
||||
private String getVersionByFullNO(String fullNO) { |
||||
if (fullNO.contains(SPLIT_CHAR)) { |
||||
fullNO = fullNO.substring(fullNO.lastIndexOf(SPLIT_CHAR) + 1); |
||||
} |
||||
return fullNO; |
||||
} |
||||
|
||||
private String getPrefixByFullNO(String fullNO) { |
||||
if (fullNO.contains(SPLIT_CHAR)) { |
||||
return fullNO.substring(0, fullNO.lastIndexOf(SPLIT_CHAR)); |
||||
} |
||||
return StringUtils.EMPTY; |
||||
} |
||||
|
||||
/** |
||||
* "自动更新推送"选项是否生效 |
||||
*/ |
||||
public boolean isAutoPushUpdateSupported() { |
||||
boolean isLocalEnv = WorkContext.getCurrent().isLocal(); |
||||
boolean isChineseEnv = GeneralContext.isChineseEnv(); |
||||
|
||||
return isAutoPushUpdateSupported(isLocalEnv, isChineseEnv); |
||||
} |
||||
|
||||
private boolean isAutoPushUpdateSupported(boolean isLocalEnv, boolean isChineseEnv) { |
||||
// 远程设计和非中文环境,都不生效
|
||||
return isLocalEnv && isChineseEnv; |
||||
} |
||||
|
||||
/** |
||||
* 检查更新,如果有合适的更新版本,则弹窗 |
||||
*/ |
||||
private void checkAndPop() { |
||||
new Thread() { |
||||
@Override |
||||
public void run() { |
||||
if (!shouldPopUp()) { |
||||
FineLoggerFactory.getLogger().debug("skip push update"); |
||||
return; |
||||
} |
||||
final DesignerFrame designerFrame = DesignerContext.getDesignerFrame(); |
||||
DesignerPushUpdateDialog.createAndShow(designerFrame, updateInfo); |
||||
} |
||||
}.start(); |
||||
} |
||||
|
||||
private boolean shouldPopUp() { |
||||
if (updateInfo == null) { |
||||
String fullCurrentVersion = GeneralUtils.readFullBuildNO(); |
||||
|
||||
String fullLatestVersion = getFullLatestVersion(); |
||||
boolean isValidJarVersion = isValidJarVersion(fullCurrentVersion, fullLatestVersion); |
||||
if (!isValidJarVersion) { |
||||
FineLoggerFactory.getLogger().info("Jar version is not valid for push update."); |
||||
return false; |
||||
} else { |
||||
String currentVersion = getVersionByFullNO(fullCurrentVersion); |
||||
String latestVersion = getVersionByFullNO(fullLatestVersion); |
||||
initUpdateInfo(currentVersion, latestVersion); |
||||
} |
||||
} |
||||
|
||||
return isAutoPushUpdateSupported() && updateInfo.hasNewPushVersion(); |
||||
} |
||||
|
||||
private boolean isValidJarVersion(String fullCurrentVersion, String fullLatestVersion) { |
||||
// todo: 目前设定的逻辑是 feature/release/stable 都弹,且不区分版本号。后期肯定要变的,注释代码先留着
|
||||
// // 无效的情况:
|
||||
// // 1. 版本号格式有误
|
||||
// // 2. 当前用的是 release 或 feature 的 jar 包
|
||||
// // 3. 代码启动的
|
||||
// String prefix = getPrefixByFullNO(fullLatestVersion);
|
||||
// return StringUtils.isNotEmpty(prefix) && fullCurrentVersion.startsWith(prefix);
|
||||
|
||||
// 无效的情况:
|
||||
// 1. 版本号格式有误(正常情况下都有前缀,只有异常的时候才可能出现)
|
||||
// 2. 代码启动的(fullCurrentVersion 为"不是安装版本")
|
||||
String prefix = getPrefixByFullNO(fullLatestVersion); |
||||
return StringUtils.isNotEmpty(prefix) && fullCurrentVersion.contains(SPLIT_CHAR); |
||||
} |
||||
|
||||
/** |
||||
* 跳转到更新升级窗口,并自动开始更新 |
||||
*/ |
||||
void doUpdate() { |
||||
new Thread() { |
||||
@Override |
||||
public void run() { |
||||
UpdateMainDialog dialog = new UpdateMainDialog(DesignerContext.getDesignerFrame()); |
||||
dialog.setAutoUpdateAfterInit(); |
||||
dialog.showDialog(); |
||||
} |
||||
}.start(); |
||||
} |
||||
|
||||
/** |
||||
* 跳过当前的推送版本 |
||||
*/ |
||||
void skipCurrentPushVersion() { |
||||
if (updateInfo == null) { |
||||
return; |
||||
} |
||||
DesignerPushUpdateConfigManager.getInstance().setLastIgnoredVersion(updateInfo.getPushVersion()); |
||||
} |
||||
} |
@ -0,0 +1,91 @@
|
||||
package com.fr.design.update.push; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import java.security.InvalidParameterException; |
||||
|
||||
/** |
||||
* Created by plough on 2019/4/8. |
||||
*/ |
||||
class DesignerUpdateInfo { |
||||
private static final String KEY_VERSION = "version"; |
||||
private static final String KEY_CONTENT = "content"; |
||||
private static final String KEY_BACKGROUND_URL = "background"; |
||||
private static final String KEY_MORE_INFO_URL = "more"; |
||||
|
||||
private final String currentVersion; // 当前版本
|
||||
private final String latestVersion; // 最新版本
|
||||
private final String lastIgnoredVersion; // 最近一次跳过的版本
|
||||
|
||||
private final String pushVersion; // 推送版本
|
||||
private final String pushContent; // 推送更新内容
|
||||
private final String backgroundUrl; // 推送背景图片 url
|
||||
private final String moreInfoUrl; // 更多新特性
|
||||
|
||||
DesignerUpdateInfo(String currentVersion, String latestVersion, String lastIgnoredVersion, JSONObject pushData) { |
||||
this.currentVersion = currentVersion; |
||||
this.latestVersion = latestVersion; |
||||
this.lastIgnoredVersion = lastIgnoredVersion; |
||||
|
||||
this.pushVersion = pushData.optString(KEY_VERSION); |
||||
this.pushContent = pushData.optString(KEY_CONTENT); |
||||
this.backgroundUrl = pushData.optString(KEY_BACKGROUND_URL); |
||||
this.moreInfoUrl = pushData.optString(KEY_MORE_INFO_URL); |
||||
|
||||
// 简单做下参数校验
|
||||
if (hasEmptyField()) { |
||||
throw new InvalidParameterException(); |
||||
} |
||||
} |
||||
|
||||
private boolean hasEmptyField() { |
||||
// lastIgnoredVersion 可以为空
|
||||
return StringUtils.isEmpty(currentVersion) |
||||
|| StringUtils.isEmpty(latestVersion) |
||||
|| StringUtils.isEmpty(pushVersion) |
||||
|| StringUtils.isEmpty(pushContent) |
||||
|| StringUtils.isEmpty(backgroundUrl) |
||||
|| StringUtils.isEmpty(moreInfoUrl); |
||||
} |
||||
|
||||
String getCurrentVersion() { |
||||
return currentVersion; |
||||
} |
||||
|
||||
String getLatestVersion() { |
||||
return latestVersion; |
||||
} |
||||
|
||||
String getLastIgnoredVersion() { |
||||
return lastIgnoredVersion; |
||||
} |
||||
|
||||
String getPushVersion() { |
||||
return pushVersion; |
||||
} |
||||
|
||||
String getPushContent() { |
||||
return pushContent; |
||||
} |
||||
|
||||
String getBackgroundUrl() { |
||||
return backgroundUrl; |
||||
} |
||||
|
||||
String getMoreInfoUrl() { |
||||
return moreInfoUrl; |
||||
} |
||||
|
||||
boolean hasNewPushVersion() { |
||||
boolean result = ComparatorUtils.compare(pushVersion, currentVersion) > 0 |
||||
&& ComparatorUtils.compare(pushVersion, latestVersion) <= 0; |
||||
if (StringUtils.isNotEmpty(lastIgnoredVersion)) { |
||||
result = result && ComparatorUtils.compare(pushVersion, lastIgnoredVersion) > 0; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
} |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.dialog; |
||||
package com.fr.design.update.ui.dialog; |
||||
|
||||
|
||||
import java.io.File; |
@ -1,13 +1,12 @@
|
||||
package com.fr.design.onlineupdate.ui.dialog; |
||||
package com.fr.design.update.ui.dialog; |
||||
|
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.onlineupdate.domain.UpdateConstants; |
||||
import com.fr.design.onlineupdate.factory.DirectoryOperationFactory; |
||||
import com.fr.design.onlineupdate.ui.widget.ColorfulCellRender; |
||||
import com.fr.design.update.domain.UpdateConstants; |
||||
import com.fr.design.update.factory.DirectoryOperationFactory; |
||||
import com.fr.design.update.ui.widget.ColorfulCellRender; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StableUtils; |
||||
|
@ -1,10 +1,10 @@
|
||||
package com.fr.design.onlineupdate.ui.dialog; |
||||
package com.fr.design.update.ui.dialog; |
||||
|
||||
import com.fr.design.RestartHelper; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.onlineupdate.domain.UpdateConstants; |
||||
import com.fr.design.update.domain.UpdateConstants; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.stable.ProductConstants; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.JList; |
||||
import javax.swing.JPanel; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.general.IOUtils; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.JTable; |
||||
import javax.swing.table.TableModel; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.stable.StringUtils; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.table.AbstractTableModel; |
||||
import java.util.List; |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.onlineupdate.ui.widget; |
||||
package com.fr.design.update.ui.widget; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JTable; |
@ -0,0 +1,406 @@
|
||||
package com.fr.design.upm; |
||||
|
||||
import com.fr.base.passport.FinePassportManager; |
||||
import com.fr.config.MarketConfig; |
||||
import com.fr.decision.webservice.v10.plugin.helper.category.impl.UpmResourceLoader; |
||||
import com.fr.design.bridge.exec.JSBridge; |
||||
import com.fr.design.bridge.exec.JSCallback; |
||||
import com.fr.design.extra.PluginOperateUtils; |
||||
import com.fr.design.extra.PluginUtils; |
||||
import com.fr.design.extra.exe.GetInstalledPluginsExecutor; |
||||
import com.fr.design.extra.exe.GetPluginCategoriesExecutor; |
||||
import com.fr.design.extra.exe.GetPluginFromStoreExecutor; |
||||
import com.fr.design.extra.exe.PluginLoginExecutor; |
||||
import com.fr.design.extra.exe.ReadUpdateOnlineExecutor; |
||||
import com.fr.design.extra.exe.SearchOnlineExecutor; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.upm.event.CertificateEvent; |
||||
import com.fr.design.upm.event.DownloadEvent; |
||||
import com.fr.design.upm.exec.UpmBrowserExecutor; |
||||
import com.fr.design.upm.task.UpmTaskWorker; |
||||
import com.fr.event.EventDispatcher; |
||||
import com.fr.general.CloudCenter; |
||||
import com.fr.general.GeneralUtils; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.context.PluginMarker; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.teamdev.jxbrowser.chromium.Browser; |
||||
import com.teamdev.jxbrowser.chromium.JSArray; |
||||
import com.teamdev.jxbrowser.chromium.JSFunction; |
||||
import com.teamdev.jxbrowser.chromium.JSObject; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.filechooser.FileNameExtensionFilter; |
||||
import java.awt.*; |
||||
import java.io.File; |
||||
import java.net.URI; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.concurrent.Callable; |
||||
import java.util.concurrent.FutureTask; |
||||
import java.util.concurrent.RunnableFuture; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-12 |
||||
* 桥接Java和JavaScript的类 |
||||
*/ |
||||
public class UpmBridge { |
||||
|
||||
public static UpmBridge getBridge(Browser browser) { |
||||
return new UpmBridge(browser); |
||||
} |
||||
|
||||
private JSObject window; |
||||
|
||||
private UpmBridge(Browser browser) { |
||||
this.window = browser.executeJavaScriptAndReturnValue("window").asObject(); |
||||
} |
||||
|
||||
public void startDownload(final JSFunction callback) { |
||||
|
||||
new SwingWorker<Void, Void>(){ |
||||
@Override |
||||
protected Void doInBackground() throws Exception { |
||||
callback.invoke(window, Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start")); |
||||
UpmResourceLoader.INSTANCE.download(); |
||||
UpmResourceLoader.INSTANCE.install(); |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected void done() { |
||||
try { |
||||
get(); |
||||
callback.invoke(window, Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Success")); |
||||
EventDispatcher.fire(DownloadEvent.SUCCESS, "success"); |
||||
} catch (Exception e) { |
||||
callback.invoke(window, Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Error")); |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
EventDispatcher.fire(DownloadEvent.ERROR, "error"); |
||||
} |
||||
} |
||||
}.execute(); |
||||
} |
||||
|
||||
@JSBridge |
||||
public String i18nText(String key) { |
||||
return Toolkit.i18nText(key); |
||||
} |
||||
|
||||
@JSBridge |
||||
public void closeWindow() { |
||||
UpmFinder.closeWindow(); |
||||
} |
||||
|
||||
|
||||
@JSBridge |
||||
public boolean isDesigner() { |
||||
return true; |
||||
} |
||||
|
||||
@JSBridge |
||||
public void getPackInfo(final JSFunction callback) { |
||||
callback.invoke(window, StringUtils.EMPTY); |
||||
} |
||||
|
||||
/** |
||||
* 在线获取插件分类 |
||||
* |
||||
* @param callback 回调函数 |
||||
*/ |
||||
@JSBridge |
||||
public void getPluginCategories(final JSFunction callback) { |
||||
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new GetPluginCategoriesExecutor()); |
||||
task.execute(); |
||||
} |
||||
|
||||
/** |
||||
* 根据条件获取在线插件 |
||||
* |
||||
* @param info 插件信息 |
||||
* @param callback 回调函数 |
||||
*/ |
||||
@JSBridge |
||||
public void getPluginFromStoreNew(String info, final JSFunction callback) { |
||||
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new GetPluginFromStoreExecutor(new JSONObject(info))); |
||||
task.execute(); |
||||
} |
||||
|
||||
/** |
||||
* 已安装插件检查更新 |
||||
*/ |
||||
@JSBridge |
||||
public void readUpdateOnline(final JSFunction callback) { |
||||
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new ReadUpdateOnlineExecutor()); |
||||
task.execute(); |
||||
} |
||||
|
||||
/** |
||||
* 获取已经安装的插件的数组 |
||||
*/ |
||||
@JSBridge |
||||
public void getInstalledPlugins(final JSFunction callback) { |
||||
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new GetInstalledPluginsExecutor()); |
||||
task.execute(); |
||||
} |
||||
|
||||
/** |
||||
* 从插件服务器上更新选中的插件 |
||||
* |
||||
* @param pluginIDs 插件集合 |
||||
*/ |
||||
@JSBridge |
||||
public void updatePluginOnline(Object pluginIDs, final JSFunction callback) { |
||||
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); |
||||
List<PluginMarker> pluginMarkerList = new ArrayList<>(); |
||||
if (pluginIDs instanceof String) { |
||||
pluginMarkerList.add(PluginUtils.createPluginMarker(pluginIDs.toString())); |
||||
} else if (pluginIDs instanceof JSArray) { |
||||
JSArray pluginInfos = (JSArray) pluginIDs; |
||||
for (int i = 0, len = pluginInfos.length(); i < len; i++) { |
||||
String value = pluginInfos.get(i).asString().getValue(); |
||||
pluginMarkerList.add(PluginUtils.createPluginMarker(value)); |
||||
} |
||||
} |
||||
PluginOperateUtils.updatePluginOnline(pluginMarkerList, jsCallback); |
||||
} |
||||
|
||||
/** |
||||
* 搜索在线插件 |
||||
* |
||||
* @param keyword 关键字 |
||||
*/ |
||||
@JSBridge |
||||
public void searchPlugin(String keyword, final JSFunction callback) { |
||||
UpmTaskWorker<Void> worker = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new SearchOnlineExecutor(keyword)); |
||||
worker.execute(); |
||||
} |
||||
|
||||
/** |
||||
* 从磁盘上选择插件安装包进行安装 |
||||
* |
||||
* @param filePath 插件包的路径 |
||||
*/ |
||||
@JSBridge |
||||
public void installPluginFromDisk(final String filePath, final JSFunction callback) { |
||||
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); |
||||
File file = new File(filePath); |
||||
PluginOperateUtils.installPluginFromDisk(file, jsCallback); |
||||
} |
||||
|
||||
/** |
||||
* 卸载当前选中的插件 |
||||
* |
||||
* @param pluginInfo 插件信息 |
||||
*/ |
||||
@JSBridge |
||||
public void uninstallPlugin(final String pluginInfo, final boolean isForce, final JSFunction callback) { |
||||
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); |
||||
PluginOperateUtils.uninstallPlugin(pluginInfo, isForce, jsCallback); |
||||
} |
||||
|
||||
/** |
||||
* 从插件服务器上安装插件 |
||||
* |
||||
* @param pluginInfo 插件的ID |
||||
* @param callback 回调函数 |
||||
*/ |
||||
@JSBridge |
||||
public void installPluginOnline(final String pluginInfo, final JSFunction callback) { |
||||
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); |
||||
PluginMarker pluginMarker = PluginUtils.createPluginMarker(pluginInfo); |
||||
PluginOperateUtils.installPluginOnline(pluginMarker, jsCallback); |
||||
} |
||||
|
||||
/** |
||||
* 从磁盘上选择插件安装包进行插件升级 |
||||
* |
||||
* @param filePath 插件包的路径 |
||||
*/ |
||||
public void updatePluginFromDisk(String filePath, final JSFunction callback) { |
||||
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); |
||||
File file = new File(filePath); |
||||
PluginOperateUtils.updatePluginFromDisk(file, jsCallback); |
||||
} |
||||
|
||||
/** |
||||
* 修改选中的插件的活跃状态 |
||||
* |
||||
* @param pluginID 插件ID |
||||
*/ |
||||
@JSBridge |
||||
public void setPluginActive(String pluginID, final JSFunction callback) { |
||||
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); |
||||
PluginOperateUtils.setPluginActive(pluginID, jsCallback); |
||||
} |
||||
|
||||
/** |
||||
* 选择文件对话框 |
||||
* |
||||
* @return 选择的文件的路径 |
||||
*/ |
||||
@JSBridge |
||||
public String showFileChooser() { |
||||
return showFileChooserWithFilter(StringUtils.EMPTY, StringUtils.EMPTY); |
||||
} |
||||
|
||||
/** |
||||
* 选择文件对话框 |
||||
* |
||||
* @param des 过滤文件描述 |
||||
* @param filter 文件的后缀 |
||||
* @return 选择的文件的路径 |
||||
* 这里换用JFileChooser会卡死,不知道为什么 |
||||
*/ |
||||
@JSBridge |
||||
public String showFileChooserWithFilter(final String des, final String filter) { |
||||
RunnableFuture<String> future = new FutureTask<>(new Callable<String>() { |
||||
@Override |
||||
public String call() { |
||||
JFileChooser fileChooser = new JFileChooser(); |
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); |
||||
|
||||
if (StringUtils.isNotEmpty(filter)) { |
||||
fileChooser.setFileFilter(new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(filter))); |
||||
} |
||||
|
||||
int result = fileChooser.showOpenDialog(UpmFinder.getDialog()); |
||||
if (result == JFileChooser.APPROVE_OPTION) { |
||||
return fileChooser.getSelectedFile().getAbsolutePath(); |
||||
} |
||||
return null; |
||||
} |
||||
}); |
||||
SwingUtilities.invokeLater(future); |
||||
try { |
||||
return future.get(); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 选择文件对话框 |
||||
* |
||||
* @param des 过滤文件描述 |
||||
* @param args 文件的后缀 |
||||
* @return 选择的文件的路径 |
||||
*/ |
||||
@JSBridge |
||||
public String showFileChooserWithFilters(final String des, final Object args) { |
||||
RunnableFuture<String> future = new FutureTask<>(new Callable<String>() { |
||||
@Override |
||||
public String call() { |
||||
JFileChooser fileChooser = new JFileChooser(); |
||||
List<String> filterList = new ArrayList<>(); |
||||
if (args instanceof String) { |
||||
filterList.add(GeneralUtils.objectToString(args)); |
||||
} else if (args instanceof JSArray) { |
||||
JSArray array = (JSArray)args; |
||||
for (int i = 0, len = array.length(); i < len; i ++) { |
||||
filterList.add(array.get(i).getStringValue()); |
||||
} |
||||
} |
||||
String[] filters = filterList.toArray(new String[0]); |
||||
if (ArrayUtils.isNotEmpty(filters)) { |
||||
FileNameExtensionFilter filter = new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(filters)); |
||||
fileChooser.setFileFilter(filter); |
||||
} |
||||
int result = fileChooser.showOpenDialog(UpmFinder.getDialog()); |
||||
if (result == JFileChooser.APPROVE_OPTION) { |
||||
return fileChooser.getSelectedFile().getAbsolutePath(); |
||||
} |
||||
return null; |
||||
} |
||||
}); |
||||
SwingUtilities.invokeLater(future); |
||||
try { |
||||
return future.get(); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
////////登录相关///////
|
||||
|
||||
/** |
||||
* 获取系统登录的用户名 |
||||
*/ |
||||
@JSBridge |
||||
public String getLoginInfo(final JSFunction callback) { |
||||
registerLoginInfo(callback); |
||||
return MarketConfig.getInstance().getBbsUsername(); |
||||
} |
||||
|
||||
/** |
||||
* 系统登录注册 |
||||
* |
||||
* @param callback 回调函数 |
||||
*/ |
||||
@JSBridge |
||||
public void registerLoginInfo(final JSFunction callback) { |
||||
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); |
||||
String username = MarketConfig.getInstance().getBbsUsername(); |
||||
if (StringUtils.isEmpty(username)) { |
||||
jsCallback.execute(StringUtils.EMPTY); |
||||
EventDispatcher.fire(CertificateEvent.LOGOUT, StringUtils.EMPTY); |
||||
} else { |
||||
jsCallback.execute(username); |
||||
EventDispatcher.fire(CertificateEvent.LOGIN, username); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 设计器端的用户登录 |
||||
* |
||||
* @param username 用户名 |
||||
* @param password 密码 |
||||
* @param callback 回调函数 |
||||
*/ |
||||
@JSBridge |
||||
public void defaultLogin(String username, String password, final JSFunction callback) { |
||||
UpmTaskWorker<Void> worker = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new PluginLoginExecutor(username, password)); |
||||
worker.execute(); |
||||
} |
||||
|
||||
/** |
||||
* 清除用户信息 |
||||
*/ |
||||
public void clearUserInfo() { |
||||
MarketConfig.getInstance().setInShowBBsName(StringUtils.EMPTY); |
||||
FinePassportManager.getInstance().logout(); |
||||
EventDispatcher.fire(CertificateEvent.LOGOUT, StringUtils.EMPTY); |
||||
} |
||||
|
||||
/** |
||||
* 打开论坛消息界面 |
||||
*/ |
||||
@JSBridge |
||||
public void getPriviteMessage() { |
||||
try { |
||||
String loginUrl = CloudCenter.getInstance().acquireUrlByKind("bbs.default"); |
||||
Desktop.getDesktop().browse(new URI(loginUrl)); |
||||
} catch (Exception exp) { |
||||
FineLoggerFactory.getLogger().info(exp.getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 忘记密码 |
||||
*/ |
||||
@JSBridge |
||||
public void forgetHref() { |
||||
try { |
||||
Desktop.getDesktop().browse(new URI(CloudCenter.getInstance().acquireUrlByKind("bbs.reset"))); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().info(e.getMessage()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,68 @@
|
||||
package com.fr.design.upm; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.design.dialog.UIDialog; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.event.Event; |
||||
import com.fr.event.EventDispatcher; |
||||
import com.fr.event.Listener; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.workspace.Workspace; |
||||
import com.fr.workspace.WorkspaceEvent; |
||||
|
||||
import javax.swing.*; |
||||
import java.io.File; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-12 |
||||
*/ |
||||
public class UpmFinder { |
||||
|
||||
private static final String UPM_DIR = "/upm"; |
||||
private static final String MAIN_RESOURCE_PATH = UPM_DIR + "/plugin_design.html"; |
||||
|
||||
public static String installHome = FRContext.getCommonOperator().getWebRootPath(); |
||||
|
||||
private static UIDialog dialog = null; |
||||
|
||||
static { |
||||
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener<Workspace>() { |
||||
@Override |
||||
public void on(Event event, Workspace param) { |
||||
installHome = FRContext.getCommonOperator().getWebRootPath(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public static boolean checkUPMResourcesExist() { |
||||
String mainJsPath = StableUtils.pathJoin(installHome, MAIN_RESOURCE_PATH); |
||||
File file = new File(mainJsPath); |
||||
return file.exists(); |
||||
} |
||||
|
||||
public static String getMainResourcePath() { |
||||
return "file:///" + StableUtils.pathJoin(installHome, MAIN_RESOURCE_PATH); |
||||
} |
||||
|
||||
public static UIDialog getDialog() { |
||||
return dialog; |
||||
} |
||||
|
||||
public static void showUPMDialog() { |
||||
UpmShowPane upmPane = new UpmShowPane(); |
||||
if (dialog == null) { |
||||
dialog = new UpmShowDialog(DesignerContext.getDesignerFrame(), upmPane); |
||||
} |
||||
dialog.setVisible(true); |
||||
} |
||||
|
||||
public static void closeWindow() { |
||||
if (dialog != null) { |
||||
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); |
||||
dialog.setVisible(false); |
||||
dialog = null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
package com.fr.design.upm; |
||||
|
||||
import com.fr.design.dialog.BasicPane; |
||||
import com.fr.design.dialog.UIDialog; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
import com.fr.stable.StableUtils; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-12 |
||||
*/ |
||||
public class UpmShowDialog extends UIDialog { |
||||
|
||||
private static final Dimension DEFAULT_SHOP = new Dimension(900, 700); |
||||
|
||||
public UpmShowDialog(Frame frame, BasicPane pane) { |
||||
super(frame); |
||||
setUndecorated(true); |
||||
JPanel panel = (JPanel) getContentPane(); |
||||
panel.setLayout(new BorderLayout()); |
||||
add(pane, BorderLayout.CENTER); |
||||
setSize(DEFAULT_SHOP); |
||||
GUICoreUtils.centerWindow(this); |
||||
setResizable(false); |
||||
} |
||||
|
||||
@Override |
||||
public void checkValid() throws Exception { |
||||
} |
||||
} |
@ -0,0 +1,63 @@
|
||||
package com.fr.design.upm; |
||||
|
||||
import com.fr.design.dialog.BasicPane; |
||||
import com.fr.design.ui.ModernUIPane; |
||||
import com.fr.design.upm.event.DownloadEvent; |
||||
import com.fr.event.Event; |
||||
import com.fr.event.EventDispatcher; |
||||
import com.fr.event.Listener; |
||||
import com.teamdev.jxbrowser.chromium.JSValue; |
||||
import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter; |
||||
import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent; |
||||
|
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-12 |
||||
* Update Plugin Manager容器 |
||||
*/ |
||||
public class UpmShowPane extends BasicPane { |
||||
|
||||
private ModernUIPane<Object> modernUIPane; |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return "UPM"; |
||||
} |
||||
|
||||
public UpmShowPane() { |
||||
setLayout(new BorderLayout()); |
||||
if (UpmFinder.checkUPMResourcesExist()) { |
||||
modernUIPane = new ModernUIPane.Builder<>() |
||||
.prepare(new ScriptContextAdapter() { |
||||
@Override |
||||
public void onScriptContextCreated(ScriptContextEvent event) { |
||||
JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); |
||||
window.asObject().setProperty("PluginHelper", UpmBridge.getBridge(event.getBrowser())); |
||||
} |
||||
}) |
||||
.withURL(UpmFinder.getMainResourcePath()) |
||||
.build(); |
||||
} else { |
||||
modernUIPane = new ModernUIPane.Builder<>() |
||||
.withComponent(WarnComponent.KEY) |
||||
.prepare(new ScriptContextAdapter() { |
||||
@Override |
||||
public void onScriptContextCreated(ScriptContextEvent event) { |
||||
JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); |
||||
window.asObject().setProperty("PluginHelper", UpmBridge.getBridge(event.getBrowser())); |
||||
} |
||||
}).build(); |
||||
EventDispatcher.listen(DownloadEvent.SUCCESS, new Listener<String>() { |
||||
@Override |
||||
public void on(Event event, String param) { |
||||
modernUIPane.redirect(UpmFinder.getMainResourcePath()); |
||||
} |
||||
}); |
||||
} |
||||
add(modernUIPane, BorderLayout.CENTER); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,21 @@
|
||||
package com.fr.design.upm; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-18 |
||||
*/ |
||||
public class UpmUtils { |
||||
|
||||
public static String[] findMatchedExtension(String... extensions) { |
||||
List<String> list = new ArrayList<>(); |
||||
for (String ext : extensions) { |
||||
String[] arr = ext.split("\\."); |
||||
list.add(arr[arr.length - 1]); |
||||
} |
||||
return list.toArray(new String[0]); |
||||
} |
||||
} |
@ -0,0 +1,33 @@
|
||||
package com.fr.design.upm; |
||||
|
||||
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.impl.FineUI; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-12 |
||||
*/ |
||||
public class WarnComponent extends AssembleComponent { |
||||
|
||||
public static final WarnComponent KEY = new WarnComponent(); |
||||
|
||||
private WarnComponent() { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public ScriptPath script(RequestClient req) { |
||||
return ScriptPath.build("com/fr/design/upm/warn.js"); |
||||
} |
||||
|
||||
@Override |
||||
public Atom[] refer() { |
||||
return new Atom[]{ |
||||
FineUI.KEY |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,12 @@
|
||||
package com.fr.design.upm.event; |
||||
|
||||
import com.fr.event.Event; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-18 |
||||
*/ |
||||
public enum CertificateEvent implements Event<String> { |
||||
LOGIN,LOGOUT |
||||
} |
@ -0,0 +1,13 @@
|
||||
package com.fr.design.upm.event; |
||||
|
||||
import com.fr.event.Event; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-12 |
||||
*/ |
||||
public enum DownloadEvent implements Event<String> { |
||||
|
||||
SUCCESS, ERROR |
||||
} |
@ -0,0 +1,30 @@
|
||||
package com.fr.design.upm.exec; |
||||
|
||||
import com.fr.design.bridge.exec.JSExecutor; |
||||
import com.teamdev.jxbrowser.chromium.JSFunction; |
||||
import com.teamdev.jxbrowser.chromium.JSObject; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-18 |
||||
*/ |
||||
public class UpmBrowserExecutor implements JSExecutor { |
||||
|
||||
public static UpmBrowserExecutor create(JSObject window, JSFunction callback) { |
||||
return new UpmBrowserExecutor(window, callback); |
||||
} |
||||
|
||||
private JSObject window; |
||||
private JSFunction callback; |
||||
|
||||
private UpmBrowserExecutor(JSObject window, JSFunction callback) { |
||||
this.window = window; |
||||
this.callback = callback; |
||||
} |
||||
|
||||
@Override |
||||
public void executor(String newValue) { |
||||
callback.invoke(window, newValue); |
||||
} |
||||
} |
@ -0,0 +1,27 @@
|
||||
package com.fr.design.upm.loader; |
||||
|
||||
import com.fr.decision.webservice.bean.plugin.store.ProjectInfoBean; |
||||
import com.fr.decision.webservice.v10.plugin.helper.category.impl.BaseResourceLoader; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-18 |
||||
*/ |
||||
public class UpmDesignResourceLoader extends BaseResourceLoader { |
||||
|
||||
@Override |
||||
public String getPluginPath() { |
||||
return "upm/plugin_design.html"; |
||||
} |
||||
|
||||
@Override |
||||
public void checkResourceExist(ProjectInfoBean projectInfoBean) throws Exception { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public String getDownloadPath() throws Exception { |
||||
return "http://fanruan-market.oss-cn-shanghai.aliyuncs.com/upm/1.0/upm-10.0.zip"; |
||||
} |
||||
} |
@ -0,0 +1,52 @@
|
||||
package com.fr.design.upm.task; |
||||
|
||||
import com.fr.design.bridge.exec.JSCallback; |
||||
import com.fr.design.bridge.exec.JSUtils; |
||||
import com.fr.design.extra.Process; |
||||
import com.fr.design.extra.exe.Command; |
||||
import com.fr.design.extra.exe.Executor; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.*; |
||||
|
||||
/** |
||||
* @author richie |
||||
* @version 10.0 |
||||
* Created by richie on 2019-04-17 |
||||
*/ |
||||
public class UpmTaskWorker<V> extends SwingWorker<V, String> { |
||||
|
||||
private Executor executor; |
||||
private JSCallback callback; |
||||
|
||||
public UpmTaskWorker(final JSCallback callback, final Executor executor) { |
||||
this.executor = executor; |
||||
this.callback = callback; |
||||
} |
||||
|
||||
@Override |
||||
protected V doInBackground() throws Exception { |
||||
Command[] commands = executor.getCommands(); |
||||
for (Command command : commands) { |
||||
String message = command.getExecuteMessage(); |
||||
if (StringUtils.isNotBlank(message)) { |
||||
publish(message); |
||||
} |
||||
command.run(new Process<String>() { |
||||
@Override |
||||
public void process(String s) { |
||||
if (StringUtils.isNotBlank(s)) { |
||||
publish(JSUtils.trimText(s)); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected void done() { |
||||
String result = executor.getTaskFinishMessage(); |
||||
callback.execute(result); |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
package com.fr.design.utils; |
||||
|
||||
/** |
||||
* 为的就是能替换 DesignPort.class 实现多开,因此避免编译器常量编译展开优化 |
||||
*/ |
||||
public class DesignerPort { |
||||
private DesignerPort() { |
||||
} |
||||
|
||||
/** |
||||
* 设计器端口,避免编译期常量优化展开 |
||||
*/ |
||||
public static final int MESSAGE_PORT = getMessagePort(); |
||||
/** |
||||
* 设计器端口,避免编译期常量优化展开 |
||||
*/ |
||||
public static final int DEBUG_MESSAGE_PORT = getDebugMessagePort(); |
||||
|
||||
private static int getMessagePort() { |
||||
return 51462; |
||||
} |
||||
|
||||
private static int getDebugMessagePort() { |
||||
return 51463; |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue