From 4862eacfa598813ed85609697d8fce7991b650cb Mon Sep 17 00:00:00 2001 From: "Mata.Li" Date: Wed, 22 Aug 2018 14:30:02 +0800 Subject: [PATCH] REPORT-10763 & REPORT-10562 & REPORT-10541 --- .../connect/DatabaseConnectionPane.java | 31 - .../mainframe/toolbar/ToolBarMenuDock.java | 5 + .../onlineupdate/actions/FileDownloader.java | 118 +++ .../actions/SoftwareUpdateAction.java | 34 + .../onlineupdate/domain/DownloadItem.java | 102 +++ .../onlineupdate/domain/UpdateConstants.java | 55 ++ .../UpdateInfoCachePropertyManager.java | 41 + .../factory/DirectoryOperationFactory.java | 132 +++ .../onlineupdate/ui/dialog/RestoreDialog.java | 122 +++ .../ui/dialog/RestoreResultDialog.java | 182 ++++ .../ui/dialog/UpdateMainDialog.java | 821 ++++++++++++++++++ .../ui/widget/ColorfulCellRender.java | 65 ++ .../onlineupdate/ui/widget/LoadingLabel.java | 48 + .../ui/widget/UpdateActionLabel.java | 95 ++ .../ui/widget/UpdateInfoTable.java | 46 + .../ui/widget/UpdateInfoTableCellRender.java | 48 + .../ui/widget/UpdateInfoTableModel.java | 65 ++ .../widget/UpdateInfoTextAreaCellRender.java | 43 + .../src/main/java/com/fr/env/EnvListPane.java | 2 +- .../fr/design/images/update/busy-icon0.png | Bin 0 -> 3588 bytes .../fr/design/images/update/busy-icon1.png | Bin 0 -> 3585 bytes .../fr/design/images/update/busy-icon10.png | Bin 0 -> 3568 bytes .../fr/design/images/update/busy-icon11.png | Bin 0 -> 3581 bytes .../fr/design/images/update/busy-icon12.png | Bin 0 -> 3589 bytes .../fr/design/images/update/busy-icon13.png | Bin 0 -> 3586 bytes .../fr/design/images/update/busy-icon14.png | Bin 0 -> 3586 bytes .../fr/design/images/update/busy-icon2.png | Bin 0 -> 3585 bytes .../fr/design/images/update/busy-icon3.png | Bin 0 -> 3572 bytes .../fr/design/images/update/busy-icon4.png | Bin 0 -> 3576 bytes .../fr/design/images/update/busy-icon5.png | Bin 0 -> 3580 bytes .../fr/design/images/update/busy-icon6.png | Bin 0 -> 3581 bytes .../fr/design/images/update/busy-icon7.png | Bin 0 -> 3598 bytes .../fr/design/images/update/busy-icon8.png | Bin 0 -> 3594 bytes .../fr/design/images/update/busy-icon9.png | Bin 0 -> 3581 bytes .../fr/design/images/update/update_new.png | Bin 0 -> 1110 bytes .../onlineupdate/actions/FileDownloader.java | 7 + .../fr/onlineupdate/domain/DownloadItem.java | 7 + .../factory/DirectoryOperationFactory.java | 7 + 38 files changed, 2044 insertions(+), 32 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/actions/FileDownloader.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/actions/SoftwareUpdateAction.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/domain/DownloadItem.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateConstants.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateInfoCachePropertyManager.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/factory/DirectoryOperationFactory.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreDialog.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreResultDialog.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/UpdateMainDialog.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/ColorfulCellRender.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/LoadingLabel.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateActionLabel.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTable.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableCellRender.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableModel.java create mode 100644 designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTextAreaCellRender.java create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon0.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon1.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon10.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon11.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon12.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon13.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon14.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon2.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon3.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon4.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon5.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon6.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon7.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon8.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/busy-icon9.png create mode 100644 designer-base/src/main/resources/com/fr/design/images/update/update_new.png create mode 100644 designer-realize/src/main/java/com/fr/onlineupdate/actions/FileDownloader.java create mode 100644 designer-realize/src/main/java/com/fr/onlineupdate/domain/DownloadItem.java create mode 100644 designer-realize/src/main/java/com/fr/onlineupdate/factory/DirectoryOperationFactory.java diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java index 74cebeb5a..aa56e76b0 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java @@ -29,9 +29,6 @@ import java.awt.event.WindowEvent; */ public abstract class DatabaseConnectionPane extends BasicBeanPane { - // 编码转换. - private UIComboBox originalCharSetComboBox; - private UIComboBox newCharSetComboBox; private UILabel message; private UIButton okButton; private UIButton cancelButton; @@ -44,8 +41,6 @@ public abstract class DatabaseConnectionPane { + private static final int REPEAT_DOWNLOAD_TIMES = 3; + private DownloadItem[] files; + private String saveDir; + //已经完成的大小 + private long completeSize; + + public FileDownloader(DownloadItem[] files, String saveDir) { + this.files = files; + this.saveDir = saveDir; + } + + @Override + protected Boolean doInBackground() throws Exception { + if (ArrayUtils.isNotEmpty(files)) { + setCompleteSize(0L); + for (DownloadItem item : files) { + for (int i = 0; i < REPEAT_DOWNLOAD_TIMES; i++) { + item.setTotalLength(0); + item.setDownloadLength(0); + download(item); + if (item.getTotalLength() == item.getDownloadLength()) { + break; + } + } + if (item.getTotalLength() != item.getDownloadLength()) { + JOptionPane.showMessageDialog(null, + com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Download_Failed"), + com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Alert"), JOptionPane.ERROR_MESSAGE); + return false; + } else { + item.setDownloadLength(0); + completeSize += item.getTotalLength(); + } + } + } + return true; + } + + @Override + protected void done() { + boolean success = false; + try { + success = get(); + } catch (InterruptedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } catch (ExecutionException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + if (success) { + onDownloadSuccess(); + } else { + onDownloadFailed(); + } + } + + private void download(DownloadItem item) throws Exception { + URL url = new URL(item.getUrl()); + URLConnection connection = url.openConnection(); + int total = connection.getContentLength(); + item.setTotalLength(total); + InputStream reader = connection.getInputStream(); + File tempFile = new File(StableUtils.pathJoin(saveDir, item.getName())); + StableUtils.makesureFileExist(tempFile); + FileOutputStream writer = new FileOutputStream(tempFile); + byte[] buffer = new byte[UpdateConstants.BYTE]; + int bytesRead = 0; + int totalBytesRead = 0; + while ((bytesRead = reader.read(buffer)) != -1) { + writer.write(buffer, 0, bytesRead); + buffer = new byte[UpdateConstants.BYTE]; + totalBytesRead += bytesRead; + item.setDownloadLength(totalBytesRead); + publish(item); + } + reader.close(); + writer.close(); + } + + /** + * 下载成功 + */ + public abstract void onDownloadSuccess(); + + /** + * 下载失败 + */ + public abstract void onDownloadFailed(); + + public long getCompleteSize() { + return completeSize; + } + + public void setCompleteSize(long completeSize) { + this.completeSize = completeSize; + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/actions/SoftwareUpdateAction.java b/designer-base/src/main/java/com/fr/design/onlineupdate/actions/SoftwareUpdateAction.java new file mode 100644 index 000000000..eee2ab2f1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/actions/SoftwareUpdateAction.java @@ -0,0 +1,34 @@ +package com.fr.design.onlineupdate.actions; + +import com.fr.base.BaseUtils; +import com.fr.design.actions.UpdateAction; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.onlineupdate.ui.dialog.UpdateMainDialog; +import com.fr.locale.InterProviderFactory; + +import java.awt.event.ActionEvent; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class SoftwareUpdateAction extends UpdateAction { + + + public SoftwareUpdateAction() { + setName(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_UpdateAndUpgrade")); + setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/update/update_new.png")); + + } + + /** + * 事件响应 + * + * @param e 事件 + */ + @Override + public void actionPerformed(ActionEvent e) { + UpdateMainDialog dialog = new UpdateMainDialog(DesignerContext.getDesignerFrame()); + dialog.showDialog(); + } +} + diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/domain/DownloadItem.java b/designer-base/src/main/java/com/fr/design/onlineupdate/domain/DownloadItem.java new file mode 100644 index 000000000..6871190aa --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/domain/DownloadItem.java @@ -0,0 +1,102 @@ +package com.fr.design.onlineupdate.domain; + +import com.fr.general.ComparatorUtils; +import com.fr.json.JSONObject; + +import java.util.Date; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class DownloadItem { + + //显示为百分比 + private static final int PERCENTAGE_RATIO = 100; + //显示kB + private static final int BYTETOKB_RATIO = 1000; + + private String name; + private String url; + private long size; + + private int totalLength; + private int downloadLength; + + public DownloadItem(JSONObject json) { + this(json.optString("name"), json.optString("url"), json.optLong("size")); + } + + public DownloadItem(String name, String url, long size) { + this.name = name; + this.url = url; + this.size = size; + } + + public String getName() { + return name; + } + + public String getUrl() { + return url + "?v=" + new Date().getTime(); + } + + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public int getTotalLength() { + return totalLength; + } + + public int getDownloadLength() { + return downloadLength; + } + + public void setTotalLength(int totalLength) { + this.totalLength = totalLength; + } + + public void setDownloadLength(int downloadLength) { + this.downloadLength = downloadLength; + } + + public int getProgressValue() { + return (int) ((downloadLength / (double) totalLength) * PERCENTAGE_RATIO); + } + + public String getProgressString() { + return downloadLength / BYTETOKB_RATIO + "KB/" + totalLength / BYTETOKB_RATIO + "KB"; + } + + /** + * 转化为字符串 + * + * @return 字符串 + */ + @Override + public String toString() { + return "name:" + name + ";download:" + getProgressString(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DownloadItem + && ComparatorUtils.equals(((DownloadItem) obj).name, name) + && ComparatorUtils.equals(((DownloadItem) obj).url, url); + } + + /** + * 返回一个hash码 + * + * @return hash码 + */ + @Override + public int hashCode() { + return name.hashCode(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateConstants.java b/designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateConstants.java new file mode 100644 index 000000000..5bd360542 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateConstants.java @@ -0,0 +1,55 @@ +package com.fr.design.onlineupdate.domain; + +/** + * Created by XINZAI on 2018/8/21. + */ + +import java.awt.Color; + +/** + * 更新升级的常量 + */ +public interface UpdateConstants { + + String APPS_FOLDER_NAME = "webapps"; + + int CONNECTION_TIMEOUT = 1000 * 5; + Color BAR_COLOR = new Color(0x3384F0); + + String CHANGELOG_X_START = "2018-07-11"; + + String DEFAULT_APP_NAME = "FineReport"; + String DOWNLOAD_DIR = "update"; + String DESIGNER_BACKUP_DIR = "designerbackup"; + + String UPDATE_CACHE_CONFIG_X = "updateCacheConfig10"; + String UPDATE_CACHE_INFO_X = "updateCacheInfo10"; + + + int BYTE = 153600; + + String[] JARS_FOR_SERVER_X = new String[]{ + "fine-activator-10.0.jar", + "fine-core-10.0.jar", + "fine-report-engine-10.0.jar", + "fine-decision-10.0.jar", + "fine-decision-report-10.0.jar", + "fine-schedule-10.0.jar", + "fine-schedule-report-10.0.jar", + "fine-swift-log-adaptor-10.0.jar", + "fine-webui-10.0.jar", + "fine-datasource-10.0.jar", + "fine-third-10.0.jar" + }; + + String[] JARS_FOR_DESIGNER_X = new String[]{ + "fine-report-designer-10.0.jar", + "aspectjrt.jar" + }; + + + String[] LOG_TYPE = new String[]{ + "REPORT", "MOBILE", "CHART", "PFC", "BI" + }; + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateInfoCachePropertyManager.java b/designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateInfoCachePropertyManager.java new file mode 100644 index 000000000..7895c6913 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/domain/UpdateInfoCachePropertyManager.java @@ -0,0 +1,41 @@ +package com.fr.design.onlineupdate.domain; + +import com.fr.log.FineLoggerFactory; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Properties; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class UpdateInfoCachePropertyManager { + private Properties prop; + private String filePath; + + public UpdateInfoCachePropertyManager(String filePath) { + this.filePath = filePath; + prop = new Properties(); + try { + prop.load(new FileInputStream(filePath)); + } catch (Exception ignored) { + + } + } + + public void updateProperty(String keyName, String keyValue) { + try { + OutputStream fos = new FileOutputStream(filePath); + prop.setProperty(keyName, keyValue); + prop.store(fos, null); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + + public String readProperty(String keyName) { + return prop.getProperty(keyName); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/factory/DirectoryOperationFactory.java b/designer-base/src/main/java/com/fr/design/onlineupdate/factory/DirectoryOperationFactory.java new file mode 100644 index 000000000..9d929c095 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/factory/DirectoryOperationFactory.java @@ -0,0 +1,132 @@ +package com.fr.design.onlineupdate.factory; + +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.StableUtils; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class DirectoryOperationFactory { + /** + * 新建一个目录 + * + * @param dirPath 目录路径 + */ + public static void createNewDirectory(String dirPath) { + try { + File newDirPath = new File(dirPath); + if (!newDirPath.exists()) { + StableUtils.mkdirs(newDirPath); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + + /** + * 删除目录 + * + * @param dirPath 目录路径 + */ + public static void deleteDirectory(String dirPath) { + try { + File dir = new File(dirPath); + if (dir.isDirectory()) { + File[] file = dir.listFiles(); + for (File fileTemp : file) { + deleteDirectory(fileTemp.toString()); + fileTemp.delete(); + } + } else { + dir.delete(); + } + dir.delete(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + + /** + * 复制目录 + * + * @param oldDirPath 被复制目录 + * @param newDirPath 新目录 + */ + public static void copyDirectory(String oldDirPath, String newDirPath) { + File oldDir = new File(oldDirPath); + if (oldDir.isDirectory()) { + StableUtils.mkdirs(new File(newDirPath)); + File[] files = oldDir.listFiles(); + for (File fileTemp : files) { + copyDirectory(fileTemp.toString(), newDirPath + "/" + fileTemp.getName()); + } + } else { + try { + copy(oldDirPath, newDirPath); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + } + + private static void copy(String path1, String path2) throws IOException { + DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(path1))); + DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(path2))); + byte[] date = new byte[in.available()]; + + in.read(date); + out.write(date); + + in.close(); + out.close(); + } + + /** + * 移动目录 + * + * @param oldDirPath 被移动目录 + * @param newDirPath 新目录 + */ + public static void moveDirectory(String oldDirPath, String newDirPath) { + copyDirectory(oldDirPath, newDirPath); + deleteDirectory(oldDirPath); + } + + /** + * 列出过滤后的文件 + * + * @param installHome 安装目录 + * @param backupdir 备份目录 + * @return String数组 + */ + public static String[] listFilteredFiles(String installHome, String backupdir) { + File backupDir = new File(StableUtils.pathJoin(installHome, backupdir)); + StableUtils.mkdirs(backupDir); + File[] fileNames = backupDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + String[] jarFileName = new String[fileNames.length]; + int j = 0; + for (File fileName : fileNames) { + if ((fileName.isDirectory()) && (ArrayUtils.getLength(fileName.listFiles()) > 0)) {//判断备份文件夹中是否为空,为空不显示 + jarFileName[j++] = fileName.getName(); + } + } + return Arrays.copyOf(jarFileName, j); + } +} diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreDialog.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreDialog.java new file mode 100644 index 000000000..f197fd182 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreDialog.java @@ -0,0 +1,122 @@ +package com.fr.design.onlineupdate.ui.dialog; + +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.onlineupdate.domain.UpdateConstants; +import com.fr.design.onlineupdate.factory.DirectoryOperationFactory; +import com.fr.design.onlineupdate.ui.widget.ColorfulCellRender; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.locale.InterProviderFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.StableUtils; + +import javax.swing.BoxLayout; +import javax.swing.JDialog; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; +import java.awt.BorderLayout; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Arrays; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class RestoreDialog extends JDialog { + private static final int LISTCELLHEIGHT = 30; + private static final Dimension RESTOREJAR = new Dimension(523, 480); + private static final Dimension RESTOREJAR_NORTHPANE = new Dimension(500, 392); + //一个页面上最少显示13个元素 + private static final int NUMOFCELL_LEAST = 13; + + private UIButton okButton; + private UIButton cancelButton; + private JPanel buttonPanel; + private String jarSelected; + + public RestoreDialog(Dialog parent, boolean modal) { + super(parent, modal); + initComponents(); + } + + public RestoreDialog(Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + } + + private void initButton() { + okButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Ok")); + cancelButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Cancel")); + + okButton.setEnabled(false); + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + RestoreResultDialog dialog = new RestoreResultDialog(DesignerContext.getDesignerFrame(), true, jarSelected); + dialog.showDialog(); + } + }); + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + } + + private void initComponents() { + + this.setResizable(false); + JPanel pane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + this.setContentPane(pane); + + initButton(); + + buttonPanel = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); + buttonPanel.add(okButton); + buttonPanel.add(cancelButton); + pane.add(buttonPanel, BorderLayout.SOUTH); + + JPanel jarListPane = new JPanel(); + jarListPane.setLayout(new BoxLayout(jarListPane, BoxLayout.Y_AXIS)); + String[] jarBackupFiles = DirectoryOperationFactory.listFilteredFiles(StableUtils.getInstallHome(), UpdateConstants.DESIGNER_BACKUP_DIR); + + ArrayUtils.reverse(jarBackupFiles); + String[] jarFilesList = ((jarBackupFiles.length < NUMOFCELL_LEAST) ? Arrays.copyOf(jarBackupFiles, NUMOFCELL_LEAST) : jarBackupFiles); + final JList jarList = new JList(jarFilesList); + jarList.setFixedCellHeight(LISTCELLHEIGHT); + jarList.setCellRenderer(new ColorfulCellRender()); + jarList.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + jarSelected = (String) jarList.getSelectedValue(); + okButton.setEnabled((jarSelected != null)); + } + }); + + JScrollPane jsp = new JScrollPane(jarList, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jsp.setPreferredSize(RESTOREJAR_NORTHPANE); + pane.add(jsp, BorderLayout.NORTH); + + } + + /** + * 显示窗口 + */ + public void showDialog() { + this.setSize(RESTOREJAR); + this.setTitle(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Jar_Restore")); + GUICoreUtils.centerWindow(this); + this.setVisible(true); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreResultDialog.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreResultDialog.java new file mode 100644 index 000000000..da0401af9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/RestoreResultDialog.java @@ -0,0 +1,182 @@ +package com.fr.design.onlineupdate.ui.dialog; + +import com.fr.base.FRContext; +import com.fr.design.RestartHelper; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.onlineupdate.domain.UpdateConstants; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.ComparatorUtils; +import com.fr.locale.InterProviderFactory; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; + +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import java.awt.BorderLayout; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class RestoreResultDialog extends JDialog { + private static final Dimension RESTORE = new Dimension(340, 100); + + private static final Dimension RESTORE_OLD_VERSION = new Dimension(340, 135); + + private String jarRestoreDir; + + public RestoreResultDialog(Dialog parent, boolean modal) { + super(parent, modal); + initCommonComponents(); + } + + public RestoreResultDialog(Frame parent, boolean modal, String jarDir) { + super(parent, modal); + this.jarRestoreDir = jarDir; + if (ComparatorUtils.equals(jarDir, com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Restore_Old_Version"))) { + initOldVersionRestoreComps(); + } else { + initCommonComponents(); + } + } + + private void initCommonComponents() { + this.setResizable(false); + JPanel pane = new JPanel(); + pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10)); + pane.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.setContentPane(pane); + + UIButton restartButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Restart_Designer")); + UIButton restartLaterButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Restart_Later")); + + restartButton.setFont(new Font("Default", Font.PLAIN, 12)); + restartButton.setEnabled(false); + restartButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + RestartHelper.restart(); + } + }); + restartLaterButton.setFont(new Font("Default", Font.PLAIN, 12)); + restartLaterButton.setEnabled(false); + restartLaterButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + JPanel buttonPane = new JPanel(); + buttonPane.add(restartLaterButton); + buttonPane.add(restartButton); + pane.add(buttonPane, BorderLayout.SOUTH); + + JPanel progressLabelPane = new JPanel(new BorderLayout()); + UILabel jarProgressLabel = new UILabel((com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Restore_To")) + " " + jarRestoreDir + " " + (com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_WorksAfterRestart"))); + jarProgressLabel.setFont(new Font("Default", Font.PLAIN, 12)); + jarProgressLabel.setVisible(true); + progressLabelPane.add(jarProgressLabel); + pane.add(progressLabelPane, BorderLayout.CENTER); + + UpdateMainDialog.deletePreviousPropertyFile(); + + putJarBackupFiles(); + restartButton.setEnabled(true); + restartLaterButton.setEnabled(true); + this.setSize(RESTORE); + this.setTitle(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Jar_Restore")); + } + + private void initOldVersionRestoreComps() { + this.setResizable(false); + JPanel pane = new JPanel(); + pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10)); + pane.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.setContentPane(pane); + + UIButton okButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Ok")); + okButton.setFont(new Font("Default", Font.PLAIN, 12)); + okButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + + JPanel buttonPane = new JPanel(); + buttonPane.add(okButton); + pane.add(buttonPane, BorderLayout.SOUTH); + + JPanel infoPane = new JPanel(new BorderLayout()); + JTextArea jTextArea = new JTextArea( + com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Already_Backup_Old_Project") + + StringUtils.BLANK + + StableUtils.pathJoin(StableUtils.getInstallHome(), UpdateConstants.DESIGNER_BACKUP_DIR) + + com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Unzip_Replace_Restore") + ); + jTextArea.setLineWrap(true); + jTextArea.setEditable(false); + jTextArea.setBackground(null); + jTextArea.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0)); + jTextArea.setFont(new Font("Default", Font.PLAIN, 12)); + infoPane.add(jTextArea); + pane.add(infoPane, BorderLayout.CENTER); + + this.setSize(RESTORE_OLD_VERSION); + this.setTitle(com.fr.design.i18n.Toolkit.i18nText("FR-Designer_Updater_Restore_to_V8")); + } + + + /** + * 显示窗口 + */ + public void showDialog() { + GUICoreUtils.centerWindow(this); + this.setVisible(true); + } + + private void putJarBackupFiles() { + Map map = new HashMap(); + java.util.List list = new ArrayList(); + String installHome = StableUtils.getInstallHome(); + + putJarBackupFilesToInstallLib(installHome, map, list); + putJarBackupFilesToInstallEnv(installHome, map, list); + RestartHelper.saveFilesWhichToMove(map); + RestartHelper.saveFilesWhichToDelete(list.toArray(new String[list.size()])); + } + + private void putJarBackupFilesToInstallLib(String installHome, Map map, java.util.List list) { + String[] files = UpdateConstants.JARS_FOR_DESIGNER_X; + String backupDir = UpdateConstants.DESIGNER_BACKUP_DIR; + for (String file : files) { + map.put(StableUtils.pathJoin(installHome, backupDir, jarRestoreDir, file), + StableUtils.pathJoin(installHome, ProjectConstants.LIB_NAME, file)); + list.add(StableUtils.pathJoin(installHome, ProjectConstants.LIB_NAME, file)); + } + } + + private void putJarBackupFilesToInstallEnv(String installHome, Map map, java.util.List list) { + String[] files = UpdateConstants.JARS_FOR_SERVER_X; + String backupDir = UpdateConstants.DESIGNER_BACKUP_DIR; + for (String file : files) { + map.put(StableUtils.pathJoin(installHome, backupDir, jarRestoreDir, file), + StableUtils.pathJoin(installHome, UpdateConstants.APPS_FOLDER_NAME, FRContext.getCommonOperator().getAppName(), ProjectConstants.WEBINF_NAME, ProjectConstants.LIB_NAME, file)); + list.add(StableUtils.pathJoin(installHome, UpdateConstants.APPS_FOLDER_NAME, FRContext.getCommonOperator().getAppName(), ProjectConstants.WEBINF_NAME, ProjectConstants.LIB_NAME, file)); + } + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/UpdateMainDialog.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/UpdateMainDialog.java new file mode 100644 index 000000000..9ca0fccc0 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/dialog/UpdateMainDialog.java @@ -0,0 +1,821 @@ +package com.fr.design.onlineupdate.ui.dialog; + +import com.fr.base.FRContext; +import com.fr.design.RestartHelper; +import com.fr.design.constants.LayoutConstants; +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.itextfield.UITextField; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.onlineupdate.actions.FileDownloader; +import com.fr.design.onlineupdate.domain.DownloadItem; +import com.fr.design.onlineupdate.domain.UpdateConstants; +import com.fr.design.onlineupdate.domain.UpdateInfoCachePropertyManager; +import com.fr.design.onlineupdate.factory.DirectoryOperationFactory; +import com.fr.design.onlineupdate.ui.widget.LoadingLabel; +import com.fr.design.onlineupdate.ui.widget.UpdateActionLabel; +import com.fr.design.onlineupdate.ui.widget.UpdateInfoTable; +import com.fr.design.onlineupdate.ui.widget.UpdateInfoTableCellRender; +import com.fr.design.onlineupdate.ui.widget.UpdateInfoTableModel; +import com.fr.design.onlineupdate.ui.widget.UpdateInfoTextAreaCellRender; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.ComparatorUtils; +import com.fr.general.DateUtils; +import com.fr.general.GeneralUtils; +import com.fr.general.IOUtils; +import com.fr.general.SiteCenter; +import com.fr.general.http.HttpClient; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.ProductConstants; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; +import com.sun.java.swing.plaf.motif.MotifProgressBarUI; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.RowSorter; +import javax.swing.SortOrder; +import javax.swing.SwingConstants; +import javax.swing.SwingWorker; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.table.TableRowSorter; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class UpdateMainDialog extends UIDialog { + public static final Dimension DEFAULT = new Dimension(660, 620); + + private static final Dimension PROGRESSBAR = new Dimension(120, 15); + private static final Dimension UPDATE_BUTTON = new Dimension(80, 24); + private static final int UPDATE_PANE_ROW_SIZE = 30; + private static final int UPDATE_CONTENT_PANE_ROW_SIZE = 10; + private static final int UPDATE_CONTENT_PANE_COLUMN_SIZE = 10; + private static final int UPDATE_CONTENT_PANE_LABEL_COLUMN_SIZE = 100; + private static final int SEARCH_PANE_ROW_SIZE = 50; + private static final int SEARCH_PANE_TEXT_COLUMN = 130; + private static final int SEARCH_PANE_COLUMN_GAP = 3; + private static final int UPDATE_INFO_TABLE_HEADER_TIME_WIDTH = 120; + private static final int UPDATE_CONTENT_PANE_BORDER_COLOR = 0xCCCCCC; + private static final int RESTORE_LABEL_COLOR = 0x3384F0; + + private static final String UPDATE_CACHE_STATE_FAIL = "fail"; + private static final String UPDATE_CACHE_STATE_SUCCESS = "success"; + + private static final SimpleDateFormat CHANGELOG_FORMAT = new SimpleDateFormat("M/d/y, h:m:s a", Locale.ENGLISH); + private static final SimpleDateFormat UPDATE_INFO_TABLE_FORMAT = new SimpleDateFormat("yyyy.MM.dd"); + + private Set downloadItems = new HashSet(); + private JSONObject downloadFileConfig; + //最新版本标签 + private LoadingLabel loadingLabel; + //更新按钮 + private UIButton updateButton; + //有新版本提示标签 + private UILabel updateLabel; + + //jar包版本信息面板,包括当前版本和最新版本 + private JPanel jarVersionInfoPane; + //jar包更新信息面板,包括每个版本更新的信息 + private JPanel jarUpdateInfoPane; + //jar包更新操作面板,包括更新重启按钮和进度条 + private JPanel updateActionPane; + //进度条 + private JProgressBar progressBar; + //更新版本提示面板 + private JPanel updateVersionReminderPane; + //jar包版本标签 + private UILabel jarCurrentLabel; + //jar包还原标签 + private UILabel jarRestoreLabel; + //更新信息搜索按钮 + private UIButton searchUpdateInfoBtn; + //搜索更新信息关键词文本框 + private UITextField searchUpdateInfoKeyword; + + private boolean updateSuccessful; + + private UpdateInfoTable updateInfoTable; + + private ArrayList updateInfoList; + + private boolean getUpdateInfoSuccess; + + private UpdateInfoCachePropertyManager cacheProperty; + private String lastUpdateCacheTime; + private String lastUpdateCacheState = UPDATE_CACHE_STATE_FAIL; + + public UpdateMainDialog(Dialog parent) { + super(parent); + initComponents(); + } + + public UpdateMainDialog(Frame parent) { + super(parent); + setModal(true); + initComponents(); + } + + private void initUpdateActionPane() { + double[] rowUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_ROW_SIZE, TableLayout.PREFERRED, UPDATE_CONTENT_PANE_ROW_SIZE}; + double[] rowUpdateContentPaneSize = {TableLayout.PREFERRED}; + double[] columnUpdateSubContentPaneProgressSize = {TableLayout.FILL, TableLayout.PREFERRED}; + double[] columnUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_COLUMN_SIZE, TableLayout.FILL, TableLayout.PREFERRED}; + JPanel progressBarPane = new JPanel(new BorderLayout()); + + progressBar = new JProgressBar(); + progressBar.setUI(new MotifProgressBarUI()); + progressBar.setForeground(UpdateConstants.BAR_COLOR); + progressBar.setVisible(false); + progressBar.setStringPainted(true); + progressBar.setPreferredSize(PROGRESSBAR); + + updateLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_New_Version_Available")); + updateLabel.setHorizontalAlignment(SwingConstants.RIGHT); + updateLabel.setVisible(false); + + progressBarPane.add(GUICoreUtils.createBorderLayoutPane( + progressBar, BorderLayout.CENTER, + updateLabel, BorderLayout.EAST + ), BorderLayout.CENTER); + + updateActionPane = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ + new Component[]{new UILabel(), new UILabel(), new UILabel()}, + new Component[]{new UILabel(), initPaneContent(getBackground(), rowUpdateContentPaneSize, columnUpdateSubContentPaneProgressSize, progressBarPane, updateButton), new UILabel()}, + new Component[]{new UILabel(), new UILabel(), new UILabel()} + }, rowUpdateSubContentPaneSize, columnUpdateSubContentPaneSize, LayoutConstants.VGAP_LARGE); + } + + private JPanel initPaneContent(Color color, double[] row, double[] column, Component... var) { + JPanel paneContent = TableLayoutHelper.createTableLayoutPane(new Component[][]{var}, row, column); + paneContent.setBackground(color); + return paneContent; + } + + private void initJarVersionInfoPane() { + double[] rowUpdatePaneSize = {UPDATE_PANE_ROW_SIZE, TableLayout.PREFERRED, TableLayout.PREFERRED}; + double[] columnUpdatePaneSize = {TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED}; + double[] rowUpdateContentPaneSize = {TableLayout.PREFERRED}; + double[] columnUpdateContentPaneSize = {TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED}; + double[] rowUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_ROW_SIZE, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, UPDATE_CONTENT_PANE_ROW_SIZE}; + double[] columnUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_COLUMN_SIZE, TableLayout.FILL, TableLayout.PREFERRED}; + double[] columnUpdateSubContentPaneLabelSize = {UPDATE_CONTENT_PANE_LABEL_COLUMN_SIZE, TableLayout.PREFERRED}; + + JPanel jarUpdateContentPane = new JPanel(); + jarUpdateContentPane.setLayout(new BorderLayout()); + jarUpdateContentPane.setBorder(BorderFactory.createLineBorder(new Color(UPDATE_CONTENT_PANE_BORDER_COLOR))); + + JPanel jarUpdateContentPane2 = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ + new Component[]{new UILabel(), new UILabel(), new UILabel()}, + new Component[]{new UILabel(), updateVersionReminderPane, new UILabel()}, + new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_JAR_Version")), jarCurrentLabel), new UILabel()}, + new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Latest_JAR")), loadingLabel), new UILabel()}, + new Component[]{new UILabel(), new UILabel(), new UILabel()} + }, rowUpdateSubContentPaneSize, columnUpdateSubContentPaneSize, LayoutConstants.VGAP_LARGE); + jarUpdateContentPane2.setBackground(Color.WHITE); + jarUpdateContentPane.add(jarUpdateContentPane2); + jarVersionInfoPane = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ + new Component[]{new UILabel(), new UILabel(), new UILabel()}, + new Component[]{new UILabel(), initPaneContent(getBackground(), rowUpdateContentPaneSize, columnUpdateContentPaneSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_JarUpdate")), new UILabel(), jarRestoreLabel), new UILabel()}, + new Component[]{new UILabel(), jarUpdateContentPane, new UILabel()} + }, rowUpdatePaneSize, columnUpdatePaneSize, LayoutConstants.VGAP_LARGE); + } + + private void initJarUpdateInfoPane() { + double[] rowUpdatePaneSize = {SEARCH_PANE_ROW_SIZE, TableLayout.FILL}; + double[] columnUpdatePaneSize = {TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED}; + + double[] searchRow = {UPDATE_CONTENT_PANE_ROW_SIZE, TableLayout.PREFERRED, SEARCH_PANE_COLUMN_GAP * 2}; + double[] searchColumn = {TableLayout.FILL, SEARCH_PANE_TEXT_COLUMN, TableLayout.PREFERRED}; + initUpdateInfoSearchPane(); + JPanel searchPane = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ + new Component[]{new UILabel(), new UILabel(), new UILabel()}, + new Component[]{new UILabel(), searchUpdateInfoKeyword, searchUpdateInfoBtn}, + new Component[]{new UILabel(), new UILabel(), new UILabel()} + }, searchRow, searchColumn, LayoutConstants.VGAP_LARGE); + + String[] columnNames = {com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Date"), com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Content"), com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_SignHeader")}; + initUpdateInfoTable(columnNames); + + UIScrollPane uiScrollPane = new UIScrollPane(updateInfoTable); + jarUpdateInfoPane = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ + new Component[]{new UILabel(), searchPane, new UILabel()}, + new Component[]{new UILabel(), uiScrollPane, new UILabel()} + }, rowUpdatePaneSize, columnUpdatePaneSize, LayoutConstants.VGAP_LARGE); + } + + private void initUpdateInfoTable(String[] columnNames) { + int updateTimeColIndex = 0; + int updateTitleColIndex = 1; + int updateSignColIndex = 2; + + updateInfoTable = new UpdateInfoTable(columnNames); + + updateInfoTable.setShowGrid(false); + updateInfoTable.setCellSelectionEnabled(false); + TableRowSorter sorter = new TableRowSorter(updateInfoTable.getDataModel()); + sorter.setSortable(updateTimeColIndex, true); + sorter.setSortable(updateTitleColIndex, false); + sorter.setSortable(updateSignColIndex, false); + updateInfoTable.setRowSorter(sorter); + List sortKeys = new ArrayList(); + sortKeys.add(new RowSorter.SortKey(updateTimeColIndex, SortOrder.DESCENDING)); + sorter.setSortKeys(sortKeys); + + updateInfoTable.getTableHeader().setReorderingAllowed(false); + updateInfoTable.getColumnModel().getColumn(updateTimeColIndex).setMaxWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(updateTimeColIndex).setMinWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(updateSignColIndex).setMaxWidth(0); + updateInfoTable.getColumnModel().getColumn(updateSignColIndex).setMinWidth(0); + updateInfoTable.getTableHeader().getColumnModel().getColumn(updateSignColIndex).setMaxWidth(0); + updateInfoTable.getTableHeader().getColumnModel().getColumn(updateSignColIndex).setMinWidth(0); + updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Date")).setCellRenderer(new UpdateInfoTableCellRender()); + updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Content")).setCellRenderer(new UpdateInfoTextAreaCellRender()); + } + + private void initUpdateInfoSearchPane() { + searchUpdateInfoKeyword = new UITextField(); + searchUpdateInfoKeyword.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + } + + @Override + public void removeUpdate(DocumentEvent e) { + String keyword = searchUpdateInfoKeyword.getText(); + if (ComparatorUtils.equals(keyword, StringUtils.EMPTY) && getUpdateInfoSuccess) { + updateInfoList.clear(); + getUpdateInfo(keyword).execute(); + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + }); + searchUpdateInfoBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Search")); + searchUpdateInfoBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (getUpdateInfoSuccess) { + updateInfoList.clear(); + getUpdateInfo(searchUpdateInfoKeyword.getText()).execute(); + } + } + }); + } + + private void initButtonAndLabel() { + loadingLabel = new LoadingLabel(); + loadingLabel.setText(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Checking_Jar_Update")); + updateButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Update")); + updateButton.setPreferredSize(UPDATE_BUTTON); + updateButton.setEnabled(false); + + double[] rowSize = {TableLayout.PREFERRED}; + + double[] colSize = {UPDATE_CONTENT_PANE_LABEL_COLUMN_SIZE, TableLayout.PREFERRED}; + updateVersionReminderPane = initPaneContent( + Color.WHITE, rowSize, colSize, + new UILabel(com.fr.design.i18n.Toolkit.i18nText("FR-Designer-Updater_Designer_Version")), + new UILabel(UpdateConstants.DEFAULT_APP_NAME + StringUtils.BLANK + ProductConstants.VERSION) + ); + + + jarCurrentLabel = new UILabel(StringUtils.isEmpty(GeneralUtils.readBuildNO()) ? com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Not_Install_Version") : GeneralUtils.readBuildNO(), SwingConstants.CENTER); + UILabel noJarPreviousRevision = new UILabel(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_No_Previous_Version")); + UpdateActionLabel jarRestorePreviousRevision = new UpdateActionLabel(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Restore"), false); + jarRestorePreviousRevision.setForeground(new Color(RESTORE_LABEL_COLOR)); + jarRestorePreviousRevision.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + RestoreDialog dialog = new RestoreDialog(DesignerContext.getDesignerFrame(), true); + dialog.showDialog(); + } + }); + //choose RestoreLabel to show + boolean isNeedRestore = ArrayUtils.isNotEmpty(DirectoryOperationFactory.listFilteredFiles(StableUtils.getInstallHome(), getBackupDirectory())); + jarRestoreLabel = isNeedRestore ? jarRestorePreviousRevision : noJarPreviousRevision; + } + + private void initComponents() { + JPanel contentPane = (JPanel) getContentPane(); + contentPane.setLayout(new BorderLayout()); + + + initButtonAndLabel(); + + initJarVersionInfoPane(); + initJarUpdateInfoPane(); + initUpdateActionPane(); + + add(jarVersionInfoPane, BorderLayout.NORTH); + add(jarUpdateInfoPane, BorderLayout.CENTER); + add(updateActionPane, BorderLayout.SOUTH); + + addActionListenerForUpdateBtn(); + + new SwingWorker() { + @Override + protected JSONObject doInBackground() throws Exception { + HttpClient hc = new HttpClient(SiteCenter.getInstance().acquireUrlByKind("jar10.update")); + hc.setTimeout(UpdateConstants.CONNECTION_TIMEOUT); + return new JSONObject(hc.getResponseText()); + } + + @Override + protected void done() { + try { + downloadFileConfig = get(); + showDownLoadInfo(); + } catch (InterruptedException e) { + stopLoading(); + } catch (ExecutionException e) { + stopLoading(); + } finally { + getUpdateInfo(StringUtils.EMPTY).execute(); + } + } + }.execute(); + } + + private SwingWorker getUpdateInfo(final String keyword) { + updateInfoList = new ArrayList(); + lastUpdateCacheTime = UpdateConstants.CHANGELOG_X_START; + String cacheConfigPath = getUpdateCacheConfig(); + cacheProperty = new UpdateInfoCachePropertyManager(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), "resources", "offlineres", cacheConfigPath)); + String recordUpdateTime = cacheProperty.readProperty("updateTime"); + if (StringUtils.isNotEmpty(recordUpdateTime)) { + lastUpdateCacheTime = recordUpdateTime; + } + String recordUpdateState = cacheProperty.readProperty("updateState"); + if (StringUtils.isNotEmpty(recordUpdateState)) { + lastUpdateCacheState = recordUpdateState; + } + return new SwingWorker() { + @Override + protected JSONArray doInBackground() { + try { + getUpdateInfoSuccess = false; + //step1:read from cache file + getCachedUpdateInfo(keyword); + //step2:read from website,start from cacheRecordTime + if (downloadFileConfig == null) { + throw new Exception("network error."); + } + HttpClient hc = new HttpClient(SiteCenter.getInstance().acquireUrlByKind("changelog10") + "&start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); + hc.asGet(); + hc.setTimeout(UpdateConstants.CONNECTION_TIMEOUT * 2); + String responseText = hc.getResponseText(); + JSONArray array = JSONArray.create(); + //假如返回"-1",说明socket出错了 + if (!ComparatorUtils.equals(responseText, "-1")) { + array = new JSONArray(responseText); + } + hc.release(); + return array; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + return JSONArray.create(); + } + + @Override + protected void done() { + try { + JSONArray jsonArray = get(); + //step3:generateInfoTableList + updateInfoTable.getDataModel().populateBean(generateUpdateInfoList(jsonArray, keyword)); + + getUpdateInfoSuccess = true; + //step4:update cache file,start from cacheRecordTime,end latest server jartime + updateCachedInfoFile(jsonArray); + } catch (Exception e) { + getUpdateInfoSuccess = true; + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + }; + } + + //从文件中读取缓存的更新信息 + private void getCachedUpdateInfo(String keyword) throws Exception { + String cacheInfoPath = getUpdateCacheInfo(); + File cacheFile = new File(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), "resources", "offlineres", cacheInfoPath)); + if (!ComparatorUtils.equals(lastUpdateCacheState, "success")) { + cacheFile.delete(); + return; + } + if (cacheFile.exists()) { + FileReader reader = new FileReader(cacheFile); + BufferedReader br = new BufferedReader(reader); + String readStr, updateTimeStr; + + while ((readStr = br.readLine()) != null) { + String[] updateInfo = readStr.split("\\t"); + if (updateInfo.length == 2) { + updateTimeStr = updateInfo[0]; + Date updateTime = CHANGELOG_FORMAT.parse(updateTimeStr); + //形如 Build#release-2018.07.31.03.03.52.80 + String currentNO = GeneralUtils.readBuildNO(); + Date curJarDate = UPDATE_INFO_TABLE_FORMAT.parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); + if (!ComparatorUtils.equals(keyword, StringUtils.EMPTY)) { + if (!containsKeyword(UPDATE_INFO_TABLE_FORMAT.format(updateTime), keyword) && !containsKeyword(updateInfo[1], keyword)) { + continue; + } + } + if (isValidLogInfo(updateInfo[1])) { + updateInfoList.add(new Object[]{UPDATE_INFO_TABLE_FORMAT.format(updateTime), updateInfo[1], updateTime.after(curJarDate)}); + } + } + } + br.close(); + reader.close(); + } + } + + private void updateCachedInfoFile(JSONArray jsonArray) throws Exception { + String cacheDirPath = StableUtils.pathJoin(WorkContext.getCurrent().getPath(), "resources", "offlineres"); + File cacheFileDir = new File(cacheDirPath); + if (!StableUtils.mkdirs(cacheFileDir)) { + FineLoggerFactory.getLogger().error("make dir error."); + return; + } + final File cacheFile = new File(StableUtils.pathJoin(cacheDirPath, getUpdateCacheInfo())); + if (!cacheFile.exists()) { + cacheFile.createNewFile(); + lastUpdateCacheTime = UpdateConstants.CHANGELOG_X_START; + lastUpdateCacheState = UPDATE_CACHE_STATE_FAIL; + } + if (downloadFileConfig == null) { + return; + } + String endTime = getLatestJARTimeStr(); + if (endTime.equals(lastUpdateCacheTime) || jsonArray.length() == 0 || ComparatorUtils.compare(endTime, lastUpdateCacheTime) <= 0) { + return; + } + FileWriter fileWriter = new FileWriter(cacheFile, true); + BufferedWriter bufferWriter = new BufferedWriter(fileWriter); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jo = (JSONObject) jsonArray.get(i); + bufferWriter.write((String) jo.get("update") + '\t' + jo.get("title")); + bufferWriter.newLine(); + bufferWriter.flush(); + } + bufferWriter.close(); + fileWriter.close(); + lastUpdateCacheState = UPDATE_CACHE_STATE_SUCCESS; + lastUpdateCacheTime = endTime; + cacheProperty.updateProperty("updateTime", lastUpdateCacheTime); + cacheProperty.updateProperty("updateState", lastUpdateCacheState); + } + + private ArrayList generateUpdateInfoList(JSONArray jsonArray, String keyword) throws Exception { + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jo = (JSONObject) jsonArray.get(i); + String updateTitle = (String) jo.get("title"); + String updateTimeStr = (String) jo.get("update"); + Date updateTime = CHANGELOG_FORMAT.parse(updateTimeStr); + //形如 Build#release-2018.07.31.03.03.52.80 + String currentNO = GeneralUtils.readBuildNO(); + Date curJarDate = UPDATE_INFO_TABLE_FORMAT.parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); + if (!ComparatorUtils.equals(keyword, StringUtils.EMPTY)) { + if (!containsKeyword(UPDATE_INFO_TABLE_FORMAT.format(updateTime), keyword) && !containsKeyword(updateTitle, keyword)) { + continue; + } + } + if (isValidLogInfo(updateTitle)) { + updateInfoList.add(new Object[]{UPDATE_INFO_TABLE_FORMAT.format(updateTime), updateTitle, updateTime.after(curJarDate)}); + } + } + return new ArrayList(updateInfoList); + } + + private boolean containsKeyword(String str, String keyword) { + return str.toUpperCase().contains(keyword.toUpperCase()); + } + + private void stopLoading() { + loadingLabel.stopLoading(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Connect_VersionUpdateServer_Failed")); + } + + + private void showDownLoadInfo() { + //形如 Build#release-2018.07.31.03.03.52.80 + String buildNO = downloadFileConfig.optString("buildNO"); + Date jarDate = (new SimpleDateFormat("yyyy.MM.dd")).parse(buildNO, new ParsePosition(buildNO.indexOf("-") + 1)); + String serverVersionNO = downloadFileConfig.optString("versionNO"); + String currentVersionNO = ProductConstants.RELEASE_VERSION; + String[] serverVersionSplitStr = serverVersionNO.split("\\."); + String[] currentVersionSplitStr = currentVersionNO.split("\\."); + int index = 0; + int compareResult; + int versionLength = Math.min(serverVersionSplitStr.length, currentVersionSplitStr.length); + + //形如 Build#release-2018.07.31.03.03.52.80 + String currentNO = GeneralUtils.readBuildNO(); + if (!".".equals(StableUtils.getInstallHome())) { + Date currentDate = (new SimpleDateFormat("yyyy.MM.dd")).parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); + if (DateUtils.subtractDate(jarDate, currentDate, DateUtils.DAY) > 0) { + updateButton.setEnabled(true); + updateLabel.setVisible(true); + loadingLabel.stopLoading(buildNO.contains("-") ? buildNO.substring(buildNO.lastIndexOf("-") + 1) : buildNO); + } else { + loadingLabel.stopLoading(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Already_Latest_Version")); + } + } else { + updateButton.setEnabled(true); + updateLabel.setVisible(true); + loadingLabel.stopLoading(buildNO.contains("-") ? buildNO.substring(buildNO.lastIndexOf("-") + 1) : buildNO); + } + + while (index < versionLength) { + compareResult = serverVersionSplitStr[index].length() - currentVersionSplitStr[index].length(); + if (0 == compareResult) { + compareResult = serverVersionSplitStr[index].compareTo(currentVersionSplitStr[index]); + if (0 == compareResult) { + ++index; + continue; + } + break; + } + break; + } + + initMapWithInfo(downloadFileConfig); + } + + public void initMapWithInfo(JSONObject result) { + addJarNameToMap(result, "designer"); + addJarNameToMap(result, "server"); + } + + private void addJarNameToMap(JSONObject result, String category) { + JSONArray jsonArray = result.optJSONArray(category); + if (jsonArray != null) { + for (int i = 0, len = jsonArray.length(); i < len; i++) { + JSONObject jo = jsonArray.optJSONObject(i); + String downloadName = jo.optString("name"); + String downloadUrl = jo.optString("url"); + long downloadSize = jo.optLong("size"); + if (ComparatorUtils.equals(category, "server")) { + File currentJAR = new File(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), ProjectConstants.LIB_NAME, downloadName)); + if (currentJAR.exists() && ComparatorUtils.equals(currentJAR.length(), downloadSize)) { + //假如大小一样的jar包就不要下载了 + continue; + } + } + downloadItems.add(new DownloadItem(downloadName, downloadUrl, downloadSize)); + } + } + } + + /** + * jar包更新按钮监听器 + */ + private void addActionListenerForUpdateBtn() { + updateButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (updateSuccessful) { + RestartHelper.restart(); + } else { + deletePreviousPropertyFile(); + updateButton.setEnabled(false); + progressBar.setVisible(true); + updateLabel.setVisible(false); + + new FileDownloader( + downloadItems.toArray(new DownloadItem[downloadItems.size()]), + StableUtils.pathJoin(StableUtils.getInstallHome(), UpdateConstants.DOWNLOAD_DIR)) { + @Override + protected void process(java.util.List chunks) { + DownloadItem fileInfo = chunks.get(chunks.size() - 1); + progressBar.setString(fileInfo.getName() + " " + fileInfo.getProgressString()); + progressBar.setValue(fileInfo.getProgressValue()); + } + + @Override + public void onDownloadSuccess() { + updateButton.setEnabled(true); + progressBar.setVisible(false); + backup(); + putNewFiles(); + updateSuccessful = true; + updateButton.setText(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_Restart_Designer")); + } + + @Override + public void onDownloadFailed() { + progressBar.setVisible(false); + } + }.execute(); + } + } + }); + } + + /** + * 确保升级更新之前删除以前的配置文件 + */ + public static void deletePreviousPropertyFile() { + //在进行更新升级之前确保move和delete.properties删除 + File moveFile = new File(RestartHelper.MOVE_FILE); + File delFile = new File(RestartHelper.RECORD_FILE); + if ((moveFile.exists()) && (!moveFile.delete())) { + FineLoggerFactory.getLogger().error(RestartHelper.MOVE_FILE + "delete failed!"); + } + if ((delFile.exists()) && (!delFile.delete())) { + FineLoggerFactory.getLogger().error(RestartHelper.RECORD_FILE + "delete failed!"); + } + } + + /** + * JAR包更新的时候备份老的jar包,包括设计器相关的和服务器相关的几个 + */ + private void backup() { + String installHome = StableUtils.getInstallHome(); + //jar包备份文件的目录为"backup/"+jar包当前版本号 + String todayBackupDir = StableUtils.pathJoin(installHome, getBackupDirectory(), (GeneralUtils.readBuildNO())); + backupFilesFromInstallEnv(installHome, todayBackupDir, getJARList4Server()); + backupFilesFromInstallLib(installHome, todayBackupDir, getJARList4Designer()); + jarCurrentLabel.setText(downloadFileConfig.optString("buildNO")); + } + + private void backupFilesFromInstallEnv(String installHome, String todayBackupDir, String[] files) { + for (String file : files) { + try { + IOUtils.copy( + new File(StableUtils.pathJoin(installHome, UpdateConstants.APPS_FOLDER_NAME, FRContext.getCommonOperator().getAppName(), ProjectConstants.WEBINF_NAME, ProjectConstants.LIB_NAME, file)), + new File(StableUtils.pathJoin(todayBackupDir))); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + } + + private void backupFilesFromInstallLib(String installHome, String todayBackupDir, String[] files) { + for (String file : files) { + try { + IOUtils.copy( + new File(StableUtils.pathJoin(installHome, ProjectConstants.LIB_NAME, file)), + new File(StableUtils.pathJoin(todayBackupDir))); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + } + + private void putNewFiles() { + Map map = new HashMap(); + java.util.List list = new ArrayList(); + String installHome = StableUtils.getInstallHome(); + putNewFilesToInstallLib(installHome, getDownLoadJAR4Designer(), map, list); + putNewFilesToInstallEnv(installHome, getDownLoadJAR4Server(), map, list); + RestartHelper.saveFilesWhichToMove(map); + RestartHelper.saveFilesWhichToDelete(list.toArray(new String[list.size()])); + } + + private void putNewFilesToInstallLib(String installHome, String[] files, Map map, java.util.List list) { + for (String file : files) { + map.put(StableUtils.pathJoin(installHome, UpdateConstants.DOWNLOAD_DIR, file), + StableUtils.pathJoin(installHome, ProjectConstants.LIB_NAME, file)); + list.add(StableUtils.pathJoin(installHome, ProjectConstants.LIB_NAME, file)); + } + } + + private void putNewFilesToInstallEnv(String installHome, String[] files, Map map, java.util.List list) { + for (String file : files) { + map.put(StableUtils.pathJoin(installHome, UpdateConstants.DOWNLOAD_DIR, file), + StableUtils.pathJoin(installHome, UpdateConstants.APPS_FOLDER_NAME, FRContext.getCommonOperator().getAppName(), ProjectConstants.WEBINF_NAME, ProjectConstants.LIB_NAME, file)); + list.add(StableUtils.pathJoin(installHome, UpdateConstants.APPS_FOLDER_NAME, FRContext.getCommonOperator().getAppName(), ProjectConstants.WEBINF_NAME, ProjectConstants.LIB_NAME, file)); + } + } + + //获取备份目录 + private String getBackupDirectory() { + return UpdateConstants.DESIGNER_BACKUP_DIR; + } + + //获取服务器jar包列表 + private String[] getJARList4Server() { + return UpdateConstants.JARS_FOR_SERVER_X; + } + + //获取设计器jar包列表 + private String[] getJARList4Designer() { + return UpdateConstants.JARS_FOR_DESIGNER_X; + } + + //获取服务器jar包下载列表 + private String[] getDownLoadJAR4Server() { + ArrayList jarList = new ArrayList(); + for (DownloadItem downloadItem : downloadItems) { + String downloadItemName = downloadItem.getName(); + if (ArrayUtils.contains(getJARList4Server(), downloadItemName)) { + jarList.add(downloadItemName); + } + } + return jarList.toArray(new String[jarList.size()]); + } + + //获取设计器jar包下载列表 + private String[] getDownLoadJAR4Designer() { + ArrayList jarList = new ArrayList(); + for (DownloadItem downloadItem : downloadItems) { + String downloadItemName = downloadItem.getName(); + if (ArrayUtils.contains(getJARList4Designer(), downloadItemName)) { + jarList.add(downloadItemName); + } + } + return jarList.toArray(new String[jarList.size()]); + } + + //获取更新日志缓存配置文件名 + private String getUpdateCacheConfig() { + return UpdateConstants.UPDATE_CACHE_CONFIG_X; + } + + //获取更新日志缓存内容文件名 + private String getUpdateCacheInfo() { + return UpdateConstants.UPDATE_CACHE_INFO_X; + } + + //获取最新的jar包时间字符串 + private String getLatestJARTimeStr() { + if (downloadFileConfig == null) { + return StringUtils.EMPTY; + } + String buildNO = downloadFileConfig.optString("buildNO"); + Date jarDate = (new SimpleDateFormat("yyyy.MM.dd")).parse(buildNO, new ParsePosition(buildNO.indexOf("-") + 1)); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + return df.format(jarDate); + } + + //判断是否是有效的日志内容 + private boolean isValidLogInfo(String logContent) { + String log = logContent.toUpperCase(); + for (String s : UpdateConstants.LOG_TYPE) { + if (log.startsWith(s)) { + return true; + } + } + return false; + } + + /** + * 显示窗口 + */ + public void showDialog() { + setSize(DEFAULT); + setTitle(com.fr.design.i18n.Toolkit.i18nText("FR-Desinger-Updater_UpdateAndUpgrade")); + GUICoreUtils.centerWindow(this); + setVisible(true); + } + + /** + * 检查有效性 + * + * @throws Exception + */ + @Override + public void checkValid() throws Exception { + + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/ColorfulCellRender.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/ColorfulCellRender.java new file mode 100644 index 000000000..461489839 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/ColorfulCellRender.java @@ -0,0 +1,65 @@ +package com.fr.design.onlineupdate.ui.widget; + +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.Graphics; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class ColorfulCellRender extends JPanel implements ListCellRenderer { + private static int CELLCOLOR_DARK = 0xf6f6f6; + private static int CELLCOLOR_LIGHT = 0xffffff; + private static int CELLCOLOR_SELECTED = 0xdfecfd; + private static int TEXT_COORDINATE_X = 10; + private static int TEXT_COORDINATE_Y = 20; + private static final int LISTFONTSIZE = 12; + private Color[] colors = new Color[]{new Color(CELLCOLOR_DARK), new Color(CELLCOLOR_LIGHT)}; + + private String text; + + public ColorfulCellRender() { + setOpaque(true); + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + text = ((null != value) ? (value.toString()) : null); + + Color background; + Color foreground = Color.BLACK; + //当前Renderer是否是拖拽目标 + JList.DropLocation dropLocation = list.getDropLocation(); + if (dropLocation != null + && !dropLocation.isInsert() + && dropLocation.getIndex() == index) { + + background = new Color(CELLCOLOR_SELECTED); + //当前Renderer是否被选中 + } else if (isSelected) { + background = new Color(CELLCOLOR_SELECTED); + } else { + background = colors[index % 2]; + } + + setBackground(background); + setForeground(foreground); + + return this; + } + + @Override + public void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(getForeground()); + g.setFont(new Font("Default", Font.PLAIN, LISTFONTSIZE)); + if (text != null) { + g.drawString(text, TEXT_COORDINATE_X, TEXT_COORDINATE_Y); + } + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/LoadingLabel.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/LoadingLabel.java new file mode 100644 index 000000000..a21d67e46 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/LoadingLabel.java @@ -0,0 +1,48 @@ +package com.fr.design.onlineupdate.ui.widget; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.general.IOUtils; + +import javax.swing.Icon; +import javax.swing.SwingConstants; +import javax.swing.Timer; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class LoadingLabel extends UILabel { + private Icon[] busyIcons = new Icon[15]; + private Timer busyIconTimer; + private int busyIconIndex; + + public LoadingLabel() { + for (int i = 0; i < busyIcons.length; i++) { + busyIcons[i] = IOUtils.readIcon("/com/fr/design/images/update/busy-icon" + i + ".png"); + } + int busyAnimationRate = 30; + + busyIconTimer = new Timer(busyAnimationRate, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + busyIconIndex = (busyIconIndex + 1) % busyIcons.length; + setIcon(busyIcons[busyIconIndex]); + setHorizontalAlignment(SwingConstants.CENTER); + } + }); + busyIconTimer.start(); + } + + /** + * 停止加载,并显示 + * + * @param text 要显示的字段 + */ + public void stopLoading(String text) { + busyIconTimer.stop(); + setIcon(null); + setText(text); + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateActionLabel.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateActionLabel.java new file mode 100644 index 000000000..74c2b6ae5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateActionLabel.java @@ -0,0 +1,95 @@ +package com.fr.design.onlineupdate.ui.widget; + +import com.fr.design.gui.ilable.UILabel; + +import javax.swing.event.MouseInputAdapter; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class UpdateActionLabel extends UILabel { + private ActionListener actionListener; + private boolean drawLine = true; + + public UpdateActionLabel(String text, boolean drawUnderLine) { + super(text); + this.drawLine = drawUnderLine; + this.setForeground(Color.BLUE); + this.addMouseListener(mouseInputAdapter); + this.addMouseMotionListener(mouseInputAdapter); + } + + /** + * 增加事件监听 + * + * @param actionListener 监听器 + */ + public void addActionListener(ActionListener actionListener) { + this.actionListener = actionListener; + } + + /** + * Repaints the text. + */ + public void paintComponent(Graphics _gfx) { + super.paintComponent(_gfx); + + _gfx.setColor(Color.BLUE); + if (drawLine) { + _gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1); + } + } + + private MouseInputAdapter mouseInputAdapter = new MouseInputAdapter() { + public void mouseClicked(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseReleased(MouseEvent evt) { + Object source = evt.getSource(); + + if (source instanceof UILabel) { + //Action. + if (actionListener != null) { + ActionEvent actionEvent = new ActionEvent(source, 99, ""); + actionListener.actionPerformed(actionEvent); + } + } + } + + public void mouseEntered(MouseEvent evt) { + Object source = evt.getSource(); + + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + + public void mouseExited(MouseEvent evt) { + Object source = evt.getSource(); + + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } + + public void mouseDragged(MouseEvent e) { + } + + public void mouseMoved(MouseEvent evt) { + Object source = evt.getSource(); + + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + }; +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTable.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTable.java new file mode 100644 index 000000000..f94a514ad --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTable.java @@ -0,0 +1,46 @@ +package com.fr.design.onlineupdate.ui.widget; + +import javax.swing.JTable; +import javax.swing.table.TableModel; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class UpdateInfoTable extends JTable { + private UpdateInfoTableModel dataModel; + + public UpdateInfoTable(TableModel dm) { + super(dm); + dataModel = (UpdateInfoTableModel) dm; + } + + public UpdateInfoTable() { + } + + public UpdateInfoTable(String[] columnNames) { + this(new UpdateInfoTableModel(columnNames, new ArrayList())); + } + + public UpdateInfoTable(List data, String[] columnNames) { + this(new UpdateInfoTableModel(columnNames, data)); + } + + public UpdateInfoTable(Vector rowData, Vector columnNames) { + super(rowData, columnNames); + } + + public UpdateInfoTable(int numRows, int numColumns) { + super(numRows, numColumns); + } + + public UpdateInfoTableModel getDataModel() { + return dataModel; + } + + public void setDataModel(UpdateInfoTableModel dataModel) { + this.dataModel = dataModel; + } +} diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableCellRender.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableCellRender.java new file mode 100644 index 000000000..22c603c86 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableCellRender.java @@ -0,0 +1,48 @@ +package com.fr.design.onlineupdate.ui.widget; + +import com.fr.general.ComparatorUtils; +import com.fr.stable.StringUtils; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import java.awt.Color; +import java.awt.Component; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class UpdateInfoTableCellRender extends DefaultTableCellRenderer { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + cell.setBackground((row & 1) != 0 ? new Color(0xf0f0f0) : Color.WHITE); + if ((Boolean) table.getValueAt(row, 2)) { + cell.setBackground(new Color(0xdfecfd)); + } + if (column == 0) { + //设置首列日期居中显示 + setHorizontalAlignment(JLabel.CENTER); + + for (int i = 1; row - i >= 0; i++) { + if (ComparatorUtils.equals(table.getValueAt(row - i, 0), value)) { + //调用的父类JLabel的setText,table本身的值不变 + setText(StringUtils.EMPTY); + break; + } + } + } + return cell; + } + + @Override + public void setForeground(Color c) { + super.setForeground(c); + } + + @Override + public void setBackground(Color c) { + super.setBackground(c); + } +} diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableModel.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableModel.java new file mode 100644 index 000000000..147f88a29 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTableModel.java @@ -0,0 +1,65 @@ +package com.fr.design.onlineupdate.ui.widget; + +import javax.swing.table.AbstractTableModel; +import java.util.List; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class UpdateInfoTableModel extends AbstractTableModel { + private String[] titles; + private List data; + + public UpdateInfoTableModel(String[] titles, List data) { + this.titles = titles; + this.data = data; + } + + public void populateBean(List data) { + if (data == null) { + return; + } + clear(); + this.data = data; + fireTableDataChanged(); + } + + public void clear() { + data.clear(); + } + + public List updateBean() { + return data; + } + + @Override + public int getRowCount() { + return data.size(); + } + + @Override + public int getColumnCount() { + return titles.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return data.get(rowIndex)[columnIndex]; + } + + @Override + public String getColumnName(int column) { + return titles[column]; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + super.setValueAt(aValue, rowIndex, columnIndex); + } +} + diff --git a/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTextAreaCellRender.java b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTextAreaCellRender.java new file mode 100644 index 000000000..1e3cebdf8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/onlineupdate/ui/widget/UpdateInfoTextAreaCellRender.java @@ -0,0 +1,43 @@ +package com.fr.design.onlineupdate.ui.widget; + +import javax.swing.BorderFactory; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.table.TableCellRenderer; +import java.awt.Color; +import java.awt.Component; +import java.awt.Insets; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class UpdateInfoTextAreaCellRender extends JTextArea implements TableCellRenderer { + public UpdateInfoTextAreaCellRender() { + setMargin(new Insets(2, 2, 2, 2)); + setLineWrap(true); + setWrapStyleWord(true); + setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0)); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + // 计算当前行的最佳高度 + int maxPreferredHeight = 0; + for (int i = 0; i < table.getColumnCount(); i++) { + setText("" + table.getValueAt(row, i)); + setSize(table.getColumnModel().getColumn(column).getWidth(), 0); + maxPreferredHeight = Math.max(maxPreferredHeight, getPreferredSize().height); + } + + if (table.getRowHeight(row) != maxPreferredHeight) { + table.setRowHeight(row, maxPreferredHeight); + } + + setText(value == null ? "" : value.toString()); + setBackground((row & 1) != 0 ? new Color(0xf0f0f0) : Color.WHITE); + if ((Boolean) table.getValueAt(row, 2)) { + setBackground(new Color(0xdfecfd)); + } + return this; + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/env/EnvListPane.java b/designer-base/src/main/java/com/fr/env/EnvListPane.java index 59eaea4e6..30b4b76f1 100644 --- a/designer-base/src/main/java/com/fr/env/EnvListPane.java +++ b/designer-base/src/main/java/com/fr/env/EnvListPane.java @@ -53,7 +53,7 @@ public class EnvListPane extends JListControlPane { */ @Override public NameableCreator[] createNameableCreators() { - NameableCreator local = new NameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("FR-Engine-Local_Workspace"), "com/fr/design/images/data/bind/localconnect.png", + NameableCreator local = new NameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Local_Workspace"), "com/fr/design/images/data/bind/localconnect.png", LocalDesignerWorkspaceInfo.class, LocalEnvPane.class); NameableCreator remote = new NameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Env_Remote_Server"), "com/fr/design/images/data/bind/distanceconnect.png", RemoteDesignerWorkspaceInfo.class, RemoteEnvPane.class); diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon0.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon0.png new file mode 100644 index 0000000000000000000000000000000000000000..242c0c85bc938a08f6eaa046bd24e9509b0b1d9c GIT binary patch literal 3588 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 KMNUMnLSTZ21;I%G literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon1.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon1.png new file mode 100644 index 0000000000000000000000000000000000000000..9f6f63438ec797feb79c00697d783e4c58dcbe88 GIT binary patch literal 3585 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 Hu0mjf*HOc* literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon10.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon10.png new file mode 100644 index 0000000000000000000000000000000000000000..c4ef4a1fc6a59aec6b053ed05c17ad3a2d24ec9b GIT binary patch literal 3568 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 DwfwCf literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon12.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon12.png new file mode 100644 index 0000000000000000000000000000000000000000..e447ee8ac29a421f2cc2c6786ace0e13559d280a GIT binary patch literal 3589 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 LNkvXXu0mjf9hSZ+ literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon13.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon13.png new file mode 100644 index 0000000000000000000000000000000000000000..848a6f1a41bac5459b3768c20e3eb044749c158e GIT binary patch literal 3586 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 IM6N<$g3?{b8UO$Q literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon14.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon14.png new file mode 100644 index 0000000000000000000000000000000000000000..7b3561df212ff3f799e2e5c6f99db7746ffa783c GIT binary patch literal 3586 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 IM6N<$f;*eD;Q#;t literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon2.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon2.png new file mode 100644 index 0000000000000000000000000000000000000000..c866e62a7c6ae133b78981f8cfa7562364682ce0 GIT binary patch literal 3585 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 Hu0mjfrAo$p literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon3.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon3.png new file mode 100644 index 0000000000000000000000000000000000000000..9be22fa58602d70a8ffa3b0a7729ebc938153a54 GIT binary patch literal 3572 zcmVKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}0009INklv6OU!k9*``}7 zUA3WJs;KdjrqB`)TSJASeelu#0YYB{3nKa?f(lY7UJy!6g2Yf#kZ8T7HCEHq)NHbC zZkyehW;QctZs+)5g%p(h;CuVN-`hu&QdrB(?EE9&e)r>v(b3=cEtD2Fi6AgiH8uYI z`TMSPb#}a$&2Al9+b91D;yAYYzq;`DPd{II%JcnN&+{$e3*Ga5&G!Wj!w^vvlM}BT z`|PEj=U=6i3IL!05XG_c`4_!su8mJTr|DX~uIVXF(?0h)kqrSt(?%kqN{>?z1Zk_#8V$qf&G-*EU)SJ`pw zdT&)cTPWOecVshfk-3G^qrH7!e-y__I*KBi+nFtOb#|NsFmfjV&<>!zcysodrN5Rp zCrLsQDd%%-+fVA($8Q{GhEYc;RSoyluXJ^GoC0tjcQXs1FVoueOSQUs$_)Z5j+3UD znYkW%+jaAdGszi~`TXwT{}`|3{Kk#xAA%sHQ5=)y+bjEM93`7LQ=o5opYv3DHQ+(km>aVN}=eBfC7L|sa&aj^YlAgUAL;~ zx-LzVM~-a^$FXH?odYXnkyOe|wq#n}7mswm!I<$e1prFvr#suWeKIvwR4Xg4P6z?{ z2VE*vlO%~5g^>|O5!rq3uEn0C-S0DIoW1LfcYe`5@n_-XzW%}d<;$a+tJPJVn_M_Hu5U#qILz$;0000KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}0009MNkl&AkMw*KI(&j0^gor9E8u%FG%t=fsn-!9C|%qEgssXQSp=J)%| zc>LJ(OD{IwEGs)Qyg!fr5lAV614AS4{yshPf@z9FrfKS#jLC%%IFrd@%d(X1IMCeG zFnaloOXqw(?J)oV1^{rRH2S{#v1|U`Qad3u${5u#Ap~OtN-5+i4@=kOQcCUn{=v5E zZ@o9_NLL2{pa1}4V-s(u(>t}465aDW6%6E9C#ouTs;lDnrR(D1k?~{Ww|^~IU47us z&(Cu@+S}yX+Q#c;rNtkh&19->@aK`6j_u?*jzqE8kyLBT^L+p?wKo6&2>?j+e)iS* z^70rMhAv&#-7G6Dxq`;;On$WbVEwe~x+ok9Wnb-Ry#@e%@b8?Nn_s$-HATSlTx96M zukn*7yU%jQl*To$vf}vI|C9j$`f_s*-EkZTODWOr)67Y%0Oe|$=J|Y@7l{;n0tXNd zhk9+>MwVscOxBE0Mk!Z>czgSmg9J*cRm-yQ-WB+9Fc`2nXNqfFZEx?KJV=mCrs}h% zAi}aR!bsw9$VhU|J&kkkQF{Beg9Nkl3ulE8*b+9@gMk!|MhXWgC5lq2(tqtFx_iF- z;=jtnBe&mQU)!h=!orqq<5=l4KOv=5bYXGjn}wz2{ExeOi;~GLUR)eaH8#}UYHMry zlu_#ZIWv1|?cv68$F@r}O$#x`)X`Y!qn4)n4y2R<*L5$xdA0MyUnZt<2qB76qWnIe zV;Dv@91fY`u%UEar+&W=YntX27e#l^oN9lEQrbg0J39eme7Cu|!Aqwf$CvM~=#)~$ zIS0lW;f!(0C}Wf&LNHWS#B08TG1tz7K?Vd%v4A9oL%LXcp< y?-mvoh??rkRNZrlxkzFD=K%0607w9UzXt#(r(ct}Sgx-C0000KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}0009QNkl2+9erDzzCg?b&*lB^zbczW{ zWxSNML#5OhqXtZj3!`X)i3`{ebwd;?iP13Sc z)7182_a__LGC!}pNB;(bAV`dio_%9_dbU?exmHSP*|sBW+aa#&f#bSbDHZkhJUI5! zi+i3Eg5UZt;0K{O{KM%FuU8feN~)AnKJui*jm9!vwryhDHgO#nJFZ83-;c7{jdO3m z`C2h%7=I$IHH@E`cxRzhenR=arKG}~bHBMceRFd@R|>)qkDoc0J9qvULnmr~*& z2%&#Ras2gz2l{CJ#$WeWs@0v0vAEV+XWKVciaie;2Y|_c2JM^L3VWV?y72x7AH6Vi z{JTtRrp3$WvsPo--hw73e|_(dYn3O%C_Xn zU*cuQ>EeP%g7YZf(LVM+G62BPLw!BNK@g%K2$Ai$_hB7DiZiB#5K%gv`V>~dvdqte zz(>CCW6zV#lrzR6AQ5N)gwO)4PDx6I0RRv}F&v8ikIzMr7|F$YQ0|MF_@(5S?kc`y|p@uRna`=;X;$BkM56no<(AW?Cx6;fL(L*<>!AqJ$lc~%KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}0009RNklvBBH`KgH(K*bDKvC*r0w>|y+}S^@G;H}$8mH| z_gkrh2llN;Gj=I4bYtYSR4O7Ji55j0ipj3dD*$l&uK)lf03h+jnRC6DuU=~sLKv>= z>d#Mnw1pH3Pq$G@!Wd&W6bw|8U7h^^a0y=JHvqW&{+=CoN5|3w_aBV;L!qF0n9gh` zRmN7Brs*oBP(1c}>R-llxwQAaotv{0xwqr-ma1W(8lp9-qm*hwhz^Hq2VfrB+uKel z*IlWULQ+Blp#+<*He7@N5JFGp6KJjTjw2BO00QJSJeDOWr8<`{Sm{UO@6IQ%?b0eC zgdv15kO7j6jXi{~&wtZeoUv&~$CAD?r;mO0e}dfP)MgW7@su&04&QockGkCk2k!t ze#$gWmr{ZV#uh?Q=ejEDDmNsh@<=IBV`H?qwkJ7&F~0E18v%d-z^2^fRPW&6(BkYw zE~u2kKCf3Ts15Pfc#FNPV@W1l8@dPp-vWRH0Qh47fueq0fo$Jh00000NkvXXu0mjf D&7!)r literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon7.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon7.png new file mode 100644 index 0000000000000000000000000000000000000000..49fbc6ec54f7a5a44a83ff2a7fab1d2c286e5b18 GIT binary patch literal 3598 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 literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon8.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon8.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a5a409387b1eccc58b63fa0d1afa9b80108ba8 GIT binary patch literal 3594 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 Qv;Y7A07*qoM6N<$f^|K;T>t<8 literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/busy-icon9.png b/designer-base/src/main/resources/com/fr/design/images/update/busy-icon9.png new file mode 100644 index 0000000000000000000000000000000000000000..827801235b043066db61a9b1216d8f2e11002a7b GIT binary patch literal 3581 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 DEnc`0 literal 0 HcmV?d00001 diff --git a/designer-base/src/main/resources/com/fr/design/images/update/update_new.png b/designer-base/src/main/resources/com/fr/design/images/update/update_new.png new file mode 100644 index 0000000000000000000000000000000000000000..c4b2b231c04b0e2d8af0ed7f6396e97bc68a4f74 GIT binary patch literal 1110 zcmeAS@N?(olHy`uVBq!ia0vp^LLe-_1|-?yf<%B6OS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%9|WRD45bDP46hOx7_4S6Fo+k-*%fF5lweEp zc6R~NK=9LfcRi5eEbxdd2GSm2>~=ESj)8&clc$Sgh{y4_q1GPSjv{jn19e22cXY~k zxOUZ~nRT*pb|fS(6wqzySaK;$Fh?Y0!v;|n-7Cj}S``*a1VnBTxcEc&2yb1$1($I1 zMTv>3ijnWMzhypD_7~Q*{c8Dq-p=x8d`|m+*qhv+oSgId_8+tT7f)13>OWq)!XQq1 zeed;6Ivh<394Awj^;yQNu4?u6UfDToMP|($z6*?20=K{r~6rhnl0u=95b3$ULMH1%F*=vc}-2#r7D|ee*b89FWqcD z-&`OJ4Lv&hk?+T4pNd|z#=VG*cMlYCz1YjU$^F}jdB-PzHHf*oE-Sn=Q1EJy?$x;1 zl?SDyjlTw#n$4Ed5IVUf`Td3yVmFnhPo2oXIl&=2`?a+UhpTD15_5lO? zi;`CzeSI2Brvx!52~F(K*Vj3{N#}J@>UH^^tJWsAf8SO6^qn+39_pkT;#Buf`t#qZ zn%bwjHa#j>plQ;&%!1D>QP?cm(4;p#rie0<8 zXF4sLkeRvjp!pBB(v^>|ifSxqxO91O2YF@hte4DK7phyr^i>+W-2O9`YxdC)V6PwRbi!8>p7JMwFx^ zmZVxG7o`Fz1|tJQb6rD2T|?6lLlY}gBP$aVZ37D{1B0{mma!-ra`RI%(<*Um*rU|= z5U9ZyWJ7UTx>ZtQajI@ex7bxeqM=wNp1m{ s7oV49V3d+so|I&fZj@?dsb5+Ea;6^8q$n#lP%dWhboFyt=akR{02q46VgLXD literal 0 HcmV?d00001 diff --git a/designer-realize/src/main/java/com/fr/onlineupdate/actions/FileDownloader.java b/designer-realize/src/main/java/com/fr/onlineupdate/actions/FileDownloader.java new file mode 100644 index 000000000..152dbd9d4 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/onlineupdate/actions/FileDownloader.java @@ -0,0 +1,7 @@ +package com.fr.onlineupdate.actions; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class FileDownloader { +} diff --git a/designer-realize/src/main/java/com/fr/onlineupdate/domain/DownloadItem.java b/designer-realize/src/main/java/com/fr/onlineupdate/domain/DownloadItem.java new file mode 100644 index 000000000..25cfff1f7 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/onlineupdate/domain/DownloadItem.java @@ -0,0 +1,7 @@ +package com.fr.onlineupdate.domain; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class DownloadItem { +} diff --git a/designer-realize/src/main/java/com/fr/onlineupdate/factory/DirectoryOperationFactory.java b/designer-realize/src/main/java/com/fr/onlineupdate/factory/DirectoryOperationFactory.java new file mode 100644 index 000000000..97e979c35 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/onlineupdate/factory/DirectoryOperationFactory.java @@ -0,0 +1,7 @@ +package com.fr.onlineupdate.factory; + +/** + * Created by XINZAI on 2018/8/21. + */ +public class DirectoryOperationFactory { +}