Browse Source
* commit '00ab918ae0bf7dcd2230f59dd44284bb95c2792f': (198 commits) REPORT-16985 屏蔽新插件管理器开启选项 REPORT-16567 添加台版教学视频链接 改一下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 ...persist/10.0
Kara
6 years ago
203 changed files with 6723 additions and 1706 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. |
* 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; |
import com.fr.base.io.BaseBook; |
||||||
|
|
||||||
/** |
/** |
||||||
* Created by plough on 2017/3/17. |
* Created by plough on 2017/3/17. |
||||||
*/ |
*/ |
||||||
|
// todo: 重构
|
||||||
|
// 1. 命名不好,表意不清晰。
|
||||||
|
// 2. 逻辑混乱,到底是一个 Info 类,还是一个 InfoCollector 类?
|
||||||
|
// 3. 耦合太强,用组合替代继承
|
||||||
public abstract class TemplateProcessInfo<T extends BaseBook> { |
public abstract class TemplateProcessInfo<T extends BaseBook> { |
||||||
|
|
||||||
protected T template; |
protected T template; |
@ -0,0 +1,69 @@ |
|||||||
|
package com.fr.design.mainframe.template.info; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by plough on 2019/4/19. |
||||||
|
*/ |
||||||
|
public class TimeConsumeTimer { |
||||||
|
private static final int ONE_THOUSAND = 1000; |
||||||
|
private enum State { |
||||||
|
RUNNING, STOPPED |
||||||
|
} |
||||||
|
private int timeConsume; // 单位 s
|
||||||
|
private long startMS; // 单位 ms
|
||||||
|
private long stopMS; |
||||||
|
private State state; |
||||||
|
private boolean enabled; |
||||||
|
|
||||||
|
public TimeConsumeTimer() { |
||||||
|
reset(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isEnabled() { |
||||||
|
return enabled; |
||||||
|
} |
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) { |
||||||
|
this.enabled = enabled; |
||||||
|
} |
||||||
|
|
||||||
|
public void start() { |
||||||
|
if (!isEnabled() || isRunning()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
startMS = System.currentTimeMillis(); |
||||||
|
state = State.RUNNING; |
||||||
|
} |
||||||
|
|
||||||
|
public void stop() { |
||||||
|
if (!isEnabled() || !isRunning()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
stopMS = System.currentTimeMillis(); |
||||||
|
|
||||||
|
timeConsume += ((stopMS - startMS) / ONE_THOUSAND); |
||||||
|
startMS = 0; |
||||||
|
stopMS = 0; |
||||||
|
state = State.STOPPED; |
||||||
|
} |
||||||
|
|
||||||
|
public int popTime() { |
||||||
|
if (!isEnabled()) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
stop(); |
||||||
|
int result = timeConsume; |
||||||
|
reset(); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isRunning() { |
||||||
|
return state == State.RUNNING; |
||||||
|
} |
||||||
|
|
||||||
|
private void reset() { |
||||||
|
timeConsume = 0; |
||||||
|
startMS = 0; |
||||||
|
stopMS = 0; |
||||||
|
state = State.STOPPED; |
||||||
|
} |
||||||
|
} |
@ -1,550 +0,0 @@ |
|||||||
package com.fr.design.mainframe.templateinfo; |
|
||||||
|
|
||||||
import com.fr.base.FRContext; |
|
||||||
import com.fr.base.io.BaseBook; |
|
||||||
import com.fr.config.MarketConfig; |
|
||||||
import com.fr.design.DesignerEnvManager; |
|
||||||
import com.fr.design.mainframe.DesignerContext; |
|
||||||
import com.fr.design.mainframe.JTemplate; |
|
||||||
import com.fr.design.mainframe.SiteCenterToken; |
|
||||||
import com.fr.general.CloudCenter; |
|
||||||
import com.fr.general.ComparatorUtils; |
|
||||||
import com.fr.general.GeneralUtils; |
|
||||||
import com.fr.general.IOUtils; |
|
||||||
import com.fr.general.http.HttpClient; |
|
||||||
import com.fr.json.JSONObject; |
|
||||||
import com.fr.log.FineLoggerFactory; |
|
||||||
import com.fr.stable.EncodeConstants; |
|
||||||
import com.fr.stable.ProductConstants; |
|
||||||
import com.fr.stable.StableUtils; |
|
||||||
import com.fr.stable.StringUtils; |
|
||||||
import com.fr.stable.xml.XMLPrintWriter; |
|
||||||
import com.fr.stable.xml.XMLReadable; |
|
||||||
import com.fr.stable.xml.XMLTools; |
|
||||||
import com.fr.stable.xml.XMLWriter; |
|
||||||
import com.fr.stable.xml.XMLableReader; |
|
||||||
import com.fr.third.javax.xml.stream.XMLStreamException; |
|
||||||
import com.fr.workspace.WorkContext; |
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream; |
|
||||||
import java.io.File; |
|
||||||
import java.io.FileInputStream; |
|
||||||
import java.io.FileNotFoundException; |
|
||||||
import java.io.FileOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStream; |
|
||||||
import java.io.InputStreamReader; |
|
||||||
import java.io.ObjectInputStream; |
|
||||||
import java.io.Serializable; |
|
||||||
import java.io.UnsupportedEncodingException; |
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Calendar; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* 做模板的过程和耗时收集,辅助类 |
|
||||||
* Created by plough on 2017/2/21. |
|
||||||
*/ |
|
||||||
public class TemplateInfoCollector<T extends BaseBook> implements Serializable, XMLReadable, XMLWriter { |
|
||||||
static final long serialVersionUID = 2007L; |
|
||||||
private static final String FILE_NAME = "tpl.info"; |
|
||||||
private static final String OBJECT_FILE_NAME = "tplInfo.ser"; |
|
||||||
private static final int VALID_CELL_COUNT = 5; // 有效报表模板的格子数
|
|
||||||
private static final int VALID_WIDGET_COUNT = 5; // 有效报表模板的控件数
|
|
||||||
private static final int COMPLETE_DAY_COUNT = 15; // 判断模板是否完成的天数
|
|
||||||
private static final int ONE_THOUSAND = 1000; |
|
||||||
private static final String XML_DESIGNER_OPEN_DATE = "DesignerOpenDate"; |
|
||||||
private static final String XML_TEMPLATE_INFO_LIST = "TemplateInfoList"; |
|
||||||
private static final String XML_TEMPLATE_INFO = "TemplateInfo"; |
|
||||||
private static final String XML_PROCESS_MAP = "processMap"; |
|
||||||
private static final String XML_CONSUMING_MAP = "consumingMap"; |
|
||||||
private static final String ATTR_DAY_COUNT = "day_count"; |
|
||||||
private static final String ATTR_TEMPLATE_ID = "templateID"; |
|
||||||
private static final String ATTR_PROCESS = "process"; |
|
||||||
private static final String ATTR_FLOAT_COUNT = "float_count"; |
|
||||||
private static final String ATTR_WIDGET_COUNT = "widget_count"; |
|
||||||
private static final String ATTR_CELL_COUNT = "cell_count"; |
|
||||||
private static final String ATTR_BLOCK_COUNT = "block_count"; |
|
||||||
private static final String ATTR_REPORT_TYPE = "report_type"; |
|
||||||
private static final String ATTR_ACTIVITYKEY = "activitykey"; |
|
||||||
private static final String ATTR_JAR_TIME = "jar_time"; |
|
||||||
private static final String ATTR_CREATE_TIME = "create_time"; |
|
||||||
private static final String ATTR_UUID = "uuid"; |
|
||||||
private static final String ATTR_TIME_CONSUME = "time_consume"; |
|
||||||
private static final String ATTR_VERSION = "version"; |
|
||||||
private static final String ATTR_USERNAME = "username"; |
|
||||||
private static final String JSON_CONSUMING_MAP = "jsonConsumingMap"; |
|
||||||
private static final String JSON_PROCESS_MAP = "jsonProcessMap"; |
|
||||||
private static TemplateInfoCollector instance; |
|
||||||
private Map<String, HashMap<String, Object>> templateInfoList; |
|
||||||
private String designerOpenDate; //设计器最近一次打开日期
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
private TemplateInfoCollector() { |
|
||||||
templateInfoList = new HashMap<>(); |
|
||||||
setDesignerOpenDate(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取缓存文件存放路径 |
|
||||||
*/ |
|
||||||
private static File getInfoFile() { |
|
||||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), FILE_NAME)); |
|
||||||
} |
|
||||||
|
|
||||||
private static File getObjectInfoFile() { |
|
||||||
return new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), OBJECT_FILE_NAME)); |
|
||||||
} |
|
||||||
|
|
||||||
public static TemplateInfoCollector getInstance() { |
|
||||||
if (instance == null) { |
|
||||||
instance = new TemplateInfoCollector(); |
|
||||||
readXMLFile(instance, getInfoFile()); |
|
||||||
// 兼容过渡。如果没有新文件,则从老文件读取数据。以后都是读写新的 xml 文件
|
|
||||||
if (!getInfoFile().exists() && getObjectInfoFile().exists()) { |
|
||||||
try { |
|
||||||
ObjectInputStream is = new ObjectInputStream(new FileInputStream(getObjectInfoFile())); |
|
||||||
instance = (TemplateInfoCollector) is.readObject(); |
|
||||||
} catch (Exception ex) { |
|
||||||
// 什么也不做,instance 使用新值
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return instance; |
|
||||||
} |
|
||||||
|
|
||||||
private static void readXMLFile(XMLReadable xmlReadable, File xmlFile) { |
|
||||||
if (xmlFile == null || !xmlFile.exists()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
String charset = EncodeConstants.ENCODING_UTF_8; |
|
||||||
try { |
|
||||||
String fileContent = getFileContent(xmlFile); |
|
||||||
InputStream xmlInputStream = new ByteArrayInputStream(fileContent.getBytes(charset)); |
|
||||||
InputStreamReader inputStreamReader = new InputStreamReader(xmlInputStream, charset); |
|
||||||
XMLableReader xmlReader = XMLableReader.createXMLableReader(inputStreamReader); |
|
||||||
|
|
||||||
if (xmlReader != null) { |
|
||||||
xmlReader.readXMLObject(xmlReadable); |
|
||||||
} |
|
||||||
xmlInputStream.close(); |
|
||||||
} catch (FileNotFoundException e) { |
|
||||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
||||||
} catch (IOException e) { |
|
||||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
||||||
} catch (XMLStreamException e) { |
|
||||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private static String getFileContent(File xmlFile) throws FileNotFoundException, UnsupportedEncodingException { |
|
||||||
InputStream is = new FileInputStream(xmlFile); |
|
||||||
return IOUtils.inputStream2String(is); |
|
||||||
} |
|
||||||
|
|
||||||
public static void main(String[] args) { |
|
||||||
TemplateInfoCollector tic = TemplateInfoCollector.getInstance(); |
|
||||||
tic.sendTemplateInfo(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 把设计器最近打开日期设定为当前日期 |
|
||||||
*/ |
|
||||||
private void setDesignerOpenDate() { |
|
||||||
designerOpenDate = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断今天是否第一次打开设计器 |
|
||||||
*/ |
|
||||||
private boolean designerOpenFirstTime() { |
|
||||||
String today = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); |
|
||||||
return !ComparatorUtils.equals(today, designerOpenDate); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean shouldCollectInfo() { |
|
||||||
//只收集本地环境的
|
|
||||||
if (!WorkContext.getCurrent().isLocal()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
return DesignerEnvManager.getEnvManager().isJoinProductImprove() && FRContext.isChineseEnv(); |
|
||||||
} |
|
||||||
|
|
||||||
public void appendProcess(String log) { |
|
||||||
if (!shouldCollectInfo()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
// 获取当前编辑的模板
|
|
||||||
JTemplate jt = DesignerContext.getDesignerFrame().getSelectedJTemplate(); |
|
||||||
// 追加过程记录
|
|
||||||
jt.appendProcess(log); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 加载已经存储的模板过程 |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public String loadProcess(T t) { |
|
||||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfoList.get(t.getTemplateID()).get(XML_PROCESS_MAP); |
|
||||||
return (String) processMap.get(ATTR_PROCESS); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根据模板ID是否在收集列表中,判断是否需要收集当前模板的信息 |
|
||||||
*/ |
|
||||||
public boolean inList(T t) { |
|
||||||
return templateInfoList.containsKey(t.getTemplateID()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 将包含所有信息的对象保存到文件 |
|
||||||
*/ |
|
||||||
private void saveInfo() { |
|
||||||
try { |
|
||||||
FileOutputStream out = new FileOutputStream(getInfoFile()); |
|
||||||
XMLTools.writeOutputStreamXML(this, out); |
|
||||||
} catch (Exception ex) { |
|
||||||
FineLoggerFactory.getLogger().error(ex.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 更新 day_count:打开设计器却未编辑模板的连续日子 |
|
||||||
*/ |
|
||||||
private void addDayCount() { |
|
||||||
if (designerOpenFirstTime()) { |
|
||||||
for (String key : templateInfoList.keySet()) { |
|
||||||
HashMap<String, Object> templateInfo = templateInfoList.get(key); |
|
||||||
int dayCount = (int) templateInfo.get(ATTR_DAY_COUNT) + 1; |
|
||||||
templateInfo.put(ATTR_DAY_COUNT, dayCount); |
|
||||||
} |
|
||||||
setDesignerOpenDate(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 收集模板信息。如果之前没有记录,则新增;如果已有记录,则更新。 |
|
||||||
* 同时将最新数据保存到文件中。 |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public void collectInfo(T t, JTemplate jt, long openTime, long saveTime) { |
|
||||||
if (!shouldCollectInfo()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
HashMap<String, Object> templateInfo; |
|
||||||
|
|
||||||
long timeConsume = ((saveTime - openTime) / ONE_THOUSAND); // 制作模板耗时(单位:s)
|
|
||||||
String templateID = t.getTemplateID(); |
|
||||||
|
|
||||||
if (inList(t)) { // 已有记录
|
|
||||||
templateInfo = templateInfoList.get(templateID); |
|
||||||
// 更新 conusmingMap
|
|
||||||
HashMap<String, Object> consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
|
||||||
timeConsume += (long) consumingMap.get(ATTR_TIME_CONSUME); // 加上之前的累计编辑时间
|
|
||||||
consumingMap.put(ATTR_TIME_CONSUME, timeConsume); |
|
||||||
} else { // 新增
|
|
||||||
templateInfo = new HashMap<>(); |
|
||||||
templateInfo.put(XML_CONSUMING_MAP, getNewConsumingMap(templateID, openTime, timeConsume)); |
|
||||||
} |
|
||||||
|
|
||||||
// 直接覆盖 processMap
|
|
||||||
templateInfo.put(XML_PROCESS_MAP, getProcessMap(templateID, jt)); |
|
||||||
|
|
||||||
// 保存模板时,让 day_count 归零
|
|
||||||
templateInfo.put(ATTR_DAY_COUNT, 0); |
|
||||||
|
|
||||||
templateInfoList.put(templateID, templateInfo); |
|
||||||
|
|
||||||
saveInfo(); // 每次更新之后,都同步到暂存文件中
|
|
||||||
} |
|
||||||
|
|
||||||
private HashMap<String, Object> getNewConsumingMap(String templateID, long openTime, long timeConsume) { |
|
||||||
HashMap<String, Object> consumingMap = new HashMap<>(); |
|
||||||
|
|
||||||
String username = MarketConfig.getInstance().getBbsUsername(); |
|
||||||
String uuid = DesignerEnvManager.getEnvManager().getUUID(); |
|
||||||
String activitykey = DesignerEnvManager.getEnvManager().getActivationKey(); |
|
||||||
String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(Calendar.getInstance().getTime()); |
|
||||||
String jarTime = GeneralUtils.readBuildNO(); |
|
||||||
String version = ProductConstants.VERSION; |
|
||||||
consumingMap.put(ATTR_USERNAME, username); |
|
||||||
consumingMap.put(ATTR_UUID, uuid); |
|
||||||
consumingMap.put(ATTR_ACTIVITYKEY, activitykey); |
|
||||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
|
||||||
consumingMap.put(ATTR_CREATE_TIME, createTime); |
|
||||||
consumingMap.put(ATTR_TIME_CONSUME, timeConsume); |
|
||||||
consumingMap.put(ATTR_JAR_TIME, jarTime); |
|
||||||
consumingMap.put(ATTR_VERSION, version); |
|
||||||
|
|
||||||
return consumingMap; |
|
||||||
} |
|
||||||
|
|
||||||
private HashMap<String, Object> getProcessMap(String templateID, JTemplate jt) { |
|
||||||
HashMap<String, Object> processMap = new HashMap<>(); |
|
||||||
|
|
||||||
processMap.put(ATTR_TEMPLATE_ID, templateID); |
|
||||||
processMap.put(ATTR_PROCESS, jt.getProcess()); |
|
||||||
|
|
||||||
TemplateProcessInfo info = jt.getProcessInfo(); |
|
||||||
processMap.put(ATTR_REPORT_TYPE, info.getReportType()); |
|
||||||
processMap.put(ATTR_CELL_COUNT, info.getCellCount()); |
|
||||||
processMap.put(ATTR_FLOAT_COUNT, info.getFloatCount()); |
|
||||||
processMap.put(ATTR_BLOCK_COUNT, info.getBlockCount()); |
|
||||||
processMap.put(ATTR_WIDGET_COUNT, info.getWidgetCount()); |
|
||||||
|
|
||||||
return processMap; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 发送本地模板信息到服务器 |
|
||||||
*/ |
|
||||||
public void sendTemplateInfo() { |
|
||||||
addDayCount(); |
|
||||||
String consumingUrl = CloudCenter.getInstance().acquireUrlByKind("tempinfo.consuming") + "/single"; |
|
||||||
String processUrl = CloudCenter.getInstance().acquireUrlByKind("tempinfo.process") + "/single"; |
|
||||||
ArrayList<HashMap<String, String>> completeTemplatesInfo = getCompleteTemplatesInfo(); |
|
||||||
for (HashMap<String, String> templateInfo : completeTemplatesInfo) { |
|
||||||
String jsonConsumingMap = templateInfo.get(JSON_CONSUMING_MAP); |
|
||||||
String jsonProcessMap = templateInfo.get(JSON_PROCESS_MAP); |
|
||||||
if (sendSingleTemplateInfo(consumingUrl, jsonConsumingMap) && sendSingleTemplateInfo(processUrl, jsonProcessMap)) { |
|
||||||
// 清空记录
|
|
||||||
removeFromTemplateInfoList(templateInfo.get(ATTR_TEMPLATE_ID)); |
|
||||||
} |
|
||||||
} |
|
||||||
saveInfo(); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean sendSingleTemplateInfo(String url, String content) { |
|
||||||
HashMap<String, String> para = new HashMap<>(); |
|
||||||
para.put("token", SiteCenterToken.generateToken()); |
|
||||||
para.put("content", content); |
|
||||||
HttpClient httpClient = new HttpClient(url, para, true); |
|
||||||
httpClient.setTimeout(5000); |
|
||||||
httpClient.asGet(); |
|
||||||
|
|
||||||
if (!httpClient.isServerAlive()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
String res = httpClient.getResponseText(); |
|
||||||
boolean success; |
|
||||||
try { |
|
||||||
success = ComparatorUtils.equals(new JSONObject(res).get("status"), "success"); |
|
||||||
} catch (Exception ex) { |
|
||||||
success = false; |
|
||||||
} |
|
||||||
return success; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 返回已完成的模板信息 |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
private ArrayList<HashMap<String, String>> getCompleteTemplatesInfo() { |
|
||||||
ArrayList<HashMap<String, String>> completeTemplatesInfo = new ArrayList<>(); |
|
||||||
ArrayList<String> testTemplateKeys = new ArrayList<>(); // 保存测试模板的key
|
|
||||||
for (String key : templateInfoList.keySet()) { |
|
||||||
HashMap<String, Object> templateInfo = templateInfoList.get(key); |
|
||||||
if ((int) templateInfo.get(ATTR_DAY_COUNT) <= COMPLETE_DAY_COUNT) { // 未完成模板
|
|
||||||
continue; |
|
||||||
} |
|
||||||
if (isTestTemplate(templateInfo)) { |
|
||||||
testTemplateKeys.add(key); |
|
||||||
continue; |
|
||||||
} |
|
||||||
HashMap<String, Object> consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
|
||||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
|
||||||
String jsonConsumingMap = new JSONObject(consumingMap).toString(); |
|
||||||
String jsonProcessMap = new JSONObject(processMap).toString(); |
|
||||||
HashMap<String, String> jsonTemplateInfo = new HashMap<>(); |
|
||||||
jsonTemplateInfo.put(JSON_CONSUMING_MAP, jsonConsumingMap); |
|
||||||
jsonTemplateInfo.put(JSON_PROCESS_MAP, jsonProcessMap); |
|
||||||
jsonTemplateInfo.put(ATTR_TEMPLATE_ID, key); |
|
||||||
completeTemplatesInfo.add(jsonTemplateInfo); |
|
||||||
} |
|
||||||
// 删除测试模板
|
|
||||||
for (String key : testTemplateKeys) { |
|
||||||
removeFromTemplateInfoList(key); |
|
||||||
} |
|
||||||
return completeTemplatesInfo; |
|
||||||
} |
|
||||||
|
|
||||||
private void removeFromTemplateInfoList(String key) { |
|
||||||
templateInfoList.remove(key); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
private boolean isTestTemplate(HashMap<String, Object> templateInfo) { |
|
||||||
HashMap<String, Object> processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
|
||||||
int reportType = (int) processMap.get(ATTR_REPORT_TYPE); |
|
||||||
int cellCount = (int) processMap.get(ATTR_CELL_COUNT); |
|
||||||
int floatCount = (int) processMap.get(ATTR_FLOAT_COUNT); |
|
||||||
int blockCount = (int) processMap.get(ATTR_BLOCK_COUNT); |
|
||||||
int widgetCount = (int) processMap.get(ATTR_WIDGET_COUNT); |
|
||||||
boolean isTestTemplate = false; |
|
||||||
if (reportType == 0) { // 普通报表
|
|
||||||
isTestTemplate = cellCount <= VALID_CELL_COUNT && floatCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
|
||||||
} else if (reportType == 1) { // 聚合报表
|
|
||||||
isTestTemplate = blockCount <= 1 && widgetCount <= VALID_WIDGET_COUNT; |
|
||||||
} else { // 表单(reportType == 2)
|
|
||||||
isTestTemplate = widgetCount <= 1; |
|
||||||
} |
|
||||||
return isTestTemplate; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
@Override |
|
||||||
public void readXML(XMLableReader reader) { |
|
||||||
if (reader.isChildNode()) { |
|
||||||
try { |
|
||||||
String name = reader.getTagName(); |
|
||||||
if (XML_DESIGNER_OPEN_DATE.equals(name)) { |
|
||||||
this.designerOpenDate = reader.getElementValue(); |
|
||||||
} else if (XML_TEMPLATE_INFO_LIST.equals(name)) { |
|
||||||
readTemplateInfoList(reader); |
|
||||||
} |
|
||||||
} catch (Exception ex) { |
|
||||||
// 什么也不做,使用默认值
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void readTemplateInfoList(XMLableReader reader) { |
|
||||||
reader.readXMLObject(new XMLReadable() { |
|
||||||
public void readXML(XMLableReader reader) { |
|
||||||
if (XML_TEMPLATE_INFO.equals(reader.getTagName())) { |
|
||||||
TemplateInfo templateInfo = new TemplateInfo(); |
|
||||||
reader.readXMLObject(templateInfo); |
|
||||||
templateInfoList.put(templateInfo.getTemplateID(), templateInfo.getTemplateInfo()); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void writeXML(XMLPrintWriter writer) { |
|
||||||
writer.startTAG("TplInfo"); |
|
||||||
|
|
||||||
writer.startTAG(XML_DESIGNER_OPEN_DATE); |
|
||||||
writer.textNode(designerOpenDate); |
|
||||||
writer.end(); |
|
||||||
|
|
||||||
writeTemplateInfoList(writer); |
|
||||||
|
|
||||||
writer.end(); |
|
||||||
} |
|
||||||
|
|
||||||
private void writeTemplateInfoList(XMLPrintWriter writer) { |
|
||||||
//启停
|
|
||||||
writer.startTAG(XML_TEMPLATE_INFO_LIST); |
|
||||||
for (String templateID : templateInfoList.keySet()) { |
|
||||||
new TemplateInfo(templateInfoList.get(templateID)).writeXML(writer); |
|
||||||
} |
|
||||||
writer.end(); |
|
||||||
} |
|
||||||
|
|
||||||
private class TemplateInfo implements XMLReadable, XMLWriter { |
|
||||||
|
|
||||||
private int dayCount; |
|
||||||
private String templateID; |
|
||||||
private HashMap<String, Object> processMap = new HashMap<>(); |
|
||||||
private HashMap<String, Object> consumingMap = new HashMap<>(); |
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public TemplateInfo(HashMap<String, Object> templateInfo) { |
|
||||||
this.dayCount = (int) templateInfo.get(ATTR_DAY_COUNT); |
|
||||||
this.processMap = (HashMap<String, Object>) templateInfo.get(XML_PROCESS_MAP); |
|
||||||
this.consumingMap = (HashMap<String, Object>) templateInfo.get(XML_CONSUMING_MAP); |
|
||||||
this.templateID = (String) processMap.get(ATTR_TEMPLATE_ID); |
|
||||||
} |
|
||||||
|
|
||||||
public TemplateInfo() { |
|
||||||
} |
|
||||||
|
|
||||||
public String getTemplateID() { |
|
||||||
return templateID; |
|
||||||
} |
|
||||||
|
|
||||||
public HashMap<String, Object> getTemplateInfo() { |
|
||||||
HashMap<String, Object> templateInfo = new HashMap<>(); |
|
||||||
templateInfo.put(XML_PROCESS_MAP, processMap); |
|
||||||
templateInfo.put(XML_CONSUMING_MAP, consumingMap); |
|
||||||
templateInfo.put(ATTR_DAY_COUNT, dayCount); |
|
||||||
return templateInfo; |
|
||||||
} |
|
||||||
|
|
||||||
public void writeXML(XMLPrintWriter writer) { |
|
||||||
writer.startTAG(XML_TEMPLATE_INFO); |
|
||||||
if (StringUtils.isNotEmpty(templateID)) { |
|
||||||
writer.attr(ATTR_TEMPLATE_ID, this.templateID); |
|
||||||
} |
|
||||||
if (dayCount >= 0) { |
|
||||||
writer.attr(ATTR_DAY_COUNT, this.dayCount); |
|
||||||
} |
|
||||||
writeProcessMap(writer); |
|
||||||
writeConsumingMap(writer); |
|
||||||
|
|
||||||
writer.end(); |
|
||||||
} |
|
||||||
|
|
||||||
private void writeProcessMap(XMLPrintWriter writer) { |
|
||||||
writer.startTAG(XML_PROCESS_MAP); |
|
||||||
writer.attr(ATTR_PROCESS, (String) processMap.get(ATTR_PROCESS)); |
|
||||||
writer.attr(ATTR_FLOAT_COUNT, (int) processMap.get(ATTR_FLOAT_COUNT)); |
|
||||||
writer.attr(ATTR_WIDGET_COUNT, (int) processMap.get(ATTR_WIDGET_COUNT)); |
|
||||||
writer.attr(ATTR_CELL_COUNT, (int) processMap.get(ATTR_CELL_COUNT)); |
|
||||||
writer.attr(ATTR_BLOCK_COUNT, (int) processMap.get(ATTR_BLOCK_COUNT)); |
|
||||||
writer.attr(ATTR_REPORT_TYPE, (int) processMap.get(ATTR_REPORT_TYPE)); |
|
||||||
writer.end(); |
|
||||||
} |
|
||||||
|
|
||||||
private void writeConsumingMap(XMLPrintWriter writer) { |
|
||||||
writer.startTAG(XML_CONSUMING_MAP); |
|
||||||
writer.attr(ATTR_ACTIVITYKEY, (String) consumingMap.get(ATTR_ACTIVITYKEY)); |
|
||||||
writer.attr(ATTR_JAR_TIME, (String) consumingMap.get(ATTR_JAR_TIME)); |
|
||||||
writer.attr(ATTR_CREATE_TIME, (String) consumingMap.get(ATTR_CREATE_TIME)); |
|
||||||
writer.attr(ATTR_UUID, (String) consumingMap.get(ATTR_UUID)); |
|
||||||
writer.attr(ATTR_TIME_CONSUME, (long) consumingMap.get(ATTR_TIME_CONSUME)); |
|
||||||
writer.attr(ATTR_VERSION, (String) consumingMap.get(ATTR_VERSION)); |
|
||||||
writer.attr(ATTR_USERNAME, (String) consumingMap.get(ATTR_USERNAME)); |
|
||||||
writer.end(); |
|
||||||
} |
|
||||||
|
|
||||||
public void readXML(XMLableReader reader) { |
|
||||||
if (!reader.isChildNode()) { |
|
||||||
dayCount = reader.getAttrAsInt(ATTR_DAY_COUNT, 0); |
|
||||||
templateID = reader.getAttrAsString(ATTR_TEMPLATE_ID, StringUtils.EMPTY); |
|
||||||
} else { |
|
||||||
try { |
|
||||||
String name = reader.getTagName(); |
|
||||||
if (XML_PROCESS_MAP.equals(name)) { |
|
||||||
processMap.put(ATTR_PROCESS, reader.getAttrAsString(ATTR_PROCESS, StringUtils.EMPTY)); |
|
||||||
processMap.put(ATTR_FLOAT_COUNT, reader.getAttrAsInt(ATTR_FLOAT_COUNT, 0)); |
|
||||||
processMap.put(ATTR_WIDGET_COUNT, reader.getAttrAsInt(ATTR_WIDGET_COUNT, 0)); |
|
||||||
processMap.put(ATTR_CELL_COUNT, reader.getAttrAsInt(ATTR_CELL_COUNT, 0)); |
|
||||||
processMap.put(ATTR_BLOCK_COUNT, reader.getAttrAsInt(ATTR_BLOCK_COUNT, 0)); |
|
||||||
processMap.put(ATTR_REPORT_TYPE, reader.getAttrAsInt(ATTR_REPORT_TYPE, 0)); |
|
||||||
processMap.put(ATTR_TEMPLATE_ID, templateID); |
|
||||||
} else if (XML_CONSUMING_MAP.equals(name)) { |
|
||||||
consumingMap.put(ATTR_ACTIVITYKEY, reader.getAttrAsString(ATTR_ACTIVITYKEY, StringUtils.EMPTY)); |
|
||||||
consumingMap.put(ATTR_JAR_TIME, reader.getAttrAsString(ATTR_JAR_TIME, StringUtils.EMPTY)); |
|
||||||
consumingMap.put(ATTR_CREATE_TIME, reader.getAttrAsString(ATTR_CREATE_TIME, StringUtils.EMPTY)); |
|
||||||
consumingMap.put(ATTR_TEMPLATE_ID, templateID); |
|
||||||
consumingMap.put(ATTR_UUID, reader.getAttrAsString(ATTR_UUID, StringUtils.EMPTY)); |
|
||||||
consumingMap.put(ATTR_TIME_CONSUME, reader.getAttrAsLong(ATTR_TIME_CONSUME, 0)); |
|
||||||
consumingMap.put(ATTR_VERSION, reader.getAttrAsString(ATTR_VERSION, "8.0")); |
|
||||||
consumingMap.put(ATTR_USERNAME, reader.getAttrAsString(ATTR_USERNAME, StringUtils.EMPTY)); |
|
||||||
} |
|
||||||
} catch (Exception ex) { |
|
||||||
// 什么也不做,使用默认值
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,74 @@ |
|||||||
|
package com.fr.design.mainframe.vcs; |
||||||
|
|
||||||
|
import com.fr.stable.xml.XMLPrintWriter; |
||||||
|
import com.fr.stable.xml.XMLReadable; |
||||||
|
import com.fr.stable.xml.XMLWriter; |
||||||
|
import com.fr.stable.xml.XMLableReader; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by XiaXiang on 2019/4/26. |
||||||
|
*/ |
||||||
|
public class VcsConfigManager implements XMLReadable, XMLWriter { |
||||||
|
public static final String XML_TAG = "VcsConfigManager"; |
||||||
|
private static volatile VcsConfigManager instance = new VcsConfigManager(); |
||||||
|
private boolean vcsEnable = 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.locale.InterProviderFactory; |
||||||
import com.fr.log.FineLoggerFactory; |
import com.fr.log.FineLoggerFactory; |
||||||
import com.fr.design.onlineupdate.domain.DownloadItem; |
import com.fr.design.update.domain.DownloadItem; |
||||||
import com.fr.stable.ArrayUtils; |
import com.fr.stable.ArrayUtils; |
||||||
import com.fr.stable.StableUtils; |
import com.fr.stable.StableUtils; |
||||||
|
|
@ -1,10 +1,9 @@ |
|||||||
package com.fr.design.onlineupdate.actions; |
package com.fr.design.update.actions; |
||||||
|
|
||||||
import com.fr.base.BaseUtils; |
import com.fr.base.BaseUtils; |
||||||
import com.fr.design.actions.UpdateAction; |
import com.fr.design.actions.UpdateAction; |
||||||
import com.fr.design.mainframe.DesignerContext; |
import com.fr.design.mainframe.DesignerContext; |
||||||
import com.fr.design.onlineupdate.ui.dialog.UpdateMainDialog; |
import com.fr.design.update.ui.dialog.UpdateMainDialog; |
||||||
import com.fr.locale.InterProviderFactory; |
|
||||||
|
|
||||||
import java.awt.event.ActionEvent; |
import java.awt.event.ActionEvent; |
||||||
|
|
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.domain; |
package com.fr.design.update.domain; |
||||||
|
|
||||||
import com.fr.general.ComparatorUtils; |
import com.fr.general.ComparatorUtils; |
||||||
import com.fr.json.JSONObject; |
import com.fr.json.JSONObject; |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.domain; |
package com.fr.design.update.domain; |
||||||
|
|
||||||
/** |
/** |
||||||
* Created by XINZAI on 2018/8/21. |
* Created by XINZAI on 2018/8/21. |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.domain; |
package com.fr.design.update.domain; |
||||||
|
|
||||||
import com.fr.log.FineLoggerFactory; |
import com.fr.log.FineLoggerFactory; |
||||||
|
|
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.factory; |
package com.fr.design.update.factory; |
||||||
|
|
||||||
import com.fr.log.FineLoggerFactory; |
import com.fr.log.FineLoggerFactory; |
||||||
import com.fr.stable.ArrayUtils; |
import com.fr.stable.ArrayUtils; |
@ -0,0 +1,61 @@ |
|||||||
|
package com.fr.design.update.push; |
||||||
|
|
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
import com.fr.stable.xml.XMLPrintWriter; |
||||||
|
import com.fr.stable.xml.XMLReadable; |
||||||
|
import com.fr.stable.xml.XMLWriter; |
||||||
|
import com.fr.stable.xml.XMLableReader; |
||||||
|
|
||||||
|
/** |
||||||
|
* 持久化与设计器自动推送更新相关的配置 |
||||||
|
* Created by plough on 2019/4/8. |
||||||
|
*/ |
||||||
|
public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { |
||||||
|
public static final String XML_TAG = "DesignerPushUpdateConfigManager"; |
||||||
|
private static DesignerPushUpdateConfigManager singleton; |
||||||
|
|
||||||
|
private boolean autoPushUpdateEnabled = true; // 是否开启自动推送更新
|
||||||
|
private String lastIgnoredVersion = StringUtils.EMPTY; // 最近一次跳过的更新版本
|
||||||
|
|
||||||
|
private DesignerPushUpdateConfigManager() { |
||||||
|
} |
||||||
|
|
||||||
|
public static DesignerPushUpdateConfigManager getInstance() { |
||||||
|
if (singleton == null) { |
||||||
|
singleton = new DesignerPushUpdateConfigManager(); |
||||||
|
} |
||||||
|
return singleton; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void readXML(XMLableReader reader) { |
||||||
|
if (reader.isAttr()) { |
||||||
|
this.setAutoPushUpdateEnabled(reader.getAttrAsBoolean("autoPushUpdateEnabled", true)); |
||||||
|
this.setLastIgnoredVersion(reader.getAttrAsString("lastIgnoredVersion", StringUtils.EMPTY)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void writeXML(XMLPrintWriter writer) { |
||||||
|
writer.startTAG(XML_TAG); |
||||||
|
writer.attr("autoPushUpdateEnabled", autoPushUpdateEnabled); |
||||||
|
writer.attr("lastIgnoredVersion", lastIgnoredVersion); |
||||||
|
writer.end(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isAutoPushUpdateEnabled() { |
||||||
|
return autoPushUpdateEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAutoPushUpdateEnabled(boolean autoPushUpdateEnabled) { |
||||||
|
this.autoPushUpdateEnabled = autoPushUpdateEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
public String getLastIgnoredVersion() { |
||||||
|
return lastIgnoredVersion; |
||||||
|
} |
||||||
|
|
||||||
|
public void setLastIgnoredVersion(String lastIgnoredVersion) { |
||||||
|
this.lastIgnoredVersion = lastIgnoredVersion; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,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; |
import java.io.File; |
@ -1,13 +1,12 @@ |
|||||||
package com.fr.design.onlineupdate.ui.dialog; |
package com.fr.design.update.ui.dialog; |
||||||
|
|
||||||
import com.fr.design.gui.ibutton.UIButton; |
import com.fr.design.gui.ibutton.UIButton; |
||||||
import com.fr.design.layout.FRGUIPaneFactory; |
import com.fr.design.layout.FRGUIPaneFactory; |
||||||
import com.fr.design.mainframe.DesignerContext; |
import com.fr.design.mainframe.DesignerContext; |
||||||
import com.fr.design.onlineupdate.domain.UpdateConstants; |
import com.fr.design.update.domain.UpdateConstants; |
||||||
import com.fr.design.onlineupdate.factory.DirectoryOperationFactory; |
import com.fr.design.update.factory.DirectoryOperationFactory; |
||||||
import com.fr.design.onlineupdate.ui.widget.ColorfulCellRender; |
import com.fr.design.update.ui.widget.ColorfulCellRender; |
||||||
import com.fr.design.utils.gui.GUICoreUtils; |
import com.fr.design.utils.gui.GUICoreUtils; |
||||||
import com.fr.locale.InterProviderFactory; |
|
||||||
import com.fr.stable.ArrayUtils; |
import com.fr.stable.ArrayUtils; |
||||||
import com.fr.stable.StableUtils; |
import com.fr.stable.StableUtils; |
||||||
|
|
@ -1,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.RestartHelper; |
||||||
import com.fr.design.gui.ibutton.UIButton; |
import com.fr.design.gui.ibutton.UIButton; |
||||||
import com.fr.design.gui.ilable.UILabel; |
import com.fr.design.gui.ilable.UILabel; |
||||||
import com.fr.design.layout.FRGUIPaneFactory; |
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.design.utils.gui.GUICoreUtils; |
||||||
import com.fr.general.ComparatorUtils; |
import com.fr.general.ComparatorUtils; |
||||||
import com.fr.stable.ProductConstants; |
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.JList; |
||||||
import javax.swing.JPanel; |
import javax.swing.JPanel; |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.ui.widget; |
package com.fr.design.update.ui.widget; |
||||||
|
|
||||||
import com.fr.design.gui.ilable.UILabel; |
import com.fr.design.gui.ilable.UILabel; |
||||||
import com.fr.general.IOUtils; |
import com.fr.general.IOUtils; |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.ui.widget; |
package com.fr.design.update.ui.widget; |
||||||
|
|
||||||
import com.fr.design.gui.ilable.UILabel; |
import com.fr.design.gui.ilable.UILabel; |
||||||
|
|
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.ui.widget; |
package com.fr.design.update.ui.widget; |
||||||
|
|
||||||
import javax.swing.JTable; |
import javax.swing.JTable; |
||||||
import javax.swing.table.TableModel; |
import javax.swing.table.TableModel; |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.ui.widget; |
package com.fr.design.update.ui.widget; |
||||||
|
|
||||||
import com.fr.general.ComparatorUtils; |
import com.fr.general.ComparatorUtils; |
||||||
import com.fr.stable.StringUtils; |
import com.fr.stable.StringUtils; |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.ui.widget; |
package com.fr.design.update.ui.widget; |
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel; |
import javax.swing.table.AbstractTableModel; |
||||||
import java.util.List; |
import java.util.List; |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.onlineupdate.ui.widget; |
package com.fr.design.update.ui.widget; |
||||||
|
|
||||||
import javax.swing.BorderFactory; |
import javax.swing.BorderFactory; |
||||||
import javax.swing.JTable; |
import javax.swing.JTable; |
@ -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); |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue