diff --git a/designer-base/src/main/java/com/fr/base/function/UITerminator.java b/designer-base/src/main/java/com/fr/base/function/UITerminator.java new file mode 100644 index 0000000000..1f1424936b --- /dev/null +++ b/designer-base/src/main/java/com/fr/base/function/UITerminator.java @@ -0,0 +1,24 @@ +package com.fr.base.function; + +import com.fr.design.utils.DesignUtils; +import com.fr.runtime.FineRuntime; + +/** + * UI 终止动作 + * + * created by Harrison on 2022/07/14 + **/ +public abstract class UITerminator { + + public void run() { + + // 先执行必须的逻辑 + FineRuntime.start(); + DesignUtils.initLookAndFeel(); + + // 在执行核心逻辑 + doRun(); + } + + protected abstract void doRun(); +} diff --git a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java index 8301a0ca32..823a551ffe 100644 --- a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java +++ b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java @@ -55,6 +55,7 @@ import com.fr.stable.xml.XMLReadable; import com.fr.stable.xml.XMLTools; import com.fr.stable.xml.XMLWriter; import com.fr.stable.xml.XMLableReader; +import com.fr.start.common.DesignerStartupConfig; import com.fr.third.apache.logging.log4j.core.appender.FileAppender; import com.fr.third.apache.logging.log4j.core.layout.PatternLayout; import com.fr.third.org.apache.commons.io.FilenameUtils; @@ -188,7 +189,9 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private DesignerPushUpdateConfigManager designerPushUpdateConfigManager = DesignerPushUpdateConfigManager.getInstance(); private VcsConfigManager vcsConfigManager = VcsConfigManager.getInstance(); - + + private DesignerStartupConfig designerStartupConfig = DesignerStartupConfig.getInstance(); + public static final String CAS_CERTIFICATE_PATH = "certificatePath"; public static final String CAS_CERTIFICATE_PASSWORD = "certificatePass"; @@ -1000,6 +1003,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { public void setLanguage(Locale locale) { this.language = locale; } + + public boolean isStartupPageEnabled() { + return this.designerStartupConfig.isEnabled(); + } + + public void setStartupPageEnabled(boolean enabled) { + this.designerStartupConfig.setEnabled(enabled); + } /** * 返回环境名称迭代器 @@ -1119,23 +1130,26 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { public void setCurrentDirectoryPrefix(String prefix) { this.CurrentDirectoryPrefix = prefix; } - - - /** - * 返回最近打开的文件路径列表 - */ - public List getRecentOpenedFilePathList() { - - if (StringUtils.isEmpty(getCurEnvName())) { + + public List getRecentOpenedFilePathList4Env(String envName) { + + if (StringUtils.isEmpty(envName)) { return tempRecentOpenedFilePathList; } else { - if (!recentOpenedFileListMap.containsKey(getCurEnvName())) { - recentOpenedFileListMap.put(getCurEnvName(), tempRecentOpenedFilePathList); + if (!recentOpenedFileListMap.containsKey(envName)) { + recentOpenedFileListMap.put(envName, tempRecentOpenedFilePathList); } } + + return recentOpenedFileListMap.get(envName); + } - - return recentOpenedFileListMap.get(getCurEnvName()); + /** + * 返回最近打开的文件路径列表 + */ + public List getRecentOpenedFilePathList() { + + return this.getRecentOpenedFilePathList4Env(getCurEnvName()); } /** @@ -1829,6 +1843,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { readHttpsParas(reader); } else if (name.equals(EnvDetectorConfig.XML_TAG)) { readEnvDetectorConfig(reader); + } else if (name.equals(DesignerStartupConfig.XML_TAG)) { + readStartupConfig(reader); } else if (name.equals("AlphaFineConfigManager")) { readAlphaFineAttr(reader); } else if (name.equals("RecentColors")) { @@ -1869,6 +1885,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private void readEnvDetectorConfig(XMLableReader reader) { reader.readXMLObject(this.envDetectorConfig); } + + private void readStartupConfig(XMLableReader reader) { + reader.readXMLObject(this.designerStartupConfig); + } private void readHttpsParas(XMLableReader reader) { String tempVal; @@ -2084,6 +2104,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { writeHttpsParas(writer); writeAlphaFineAttr(writer); writeEnvDetectorConfig(writer); + writeStartupConfig(writer); writeRecentColor(writer); writeOpenDebug(writer); writeDesignerPushUpdateAttr(writer); @@ -2133,6 +2154,12 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { this.envDetectorConfig.writeXML(writer); } } + + private void writeStartupConfig(XMLPrintWriter writer) { + if (this.designerStartupConfig != null) { + this.designerStartupConfig.writeXML(writer); + } + } //写入uuid private void writeUUID(XMLPrintWriter writer) { diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java index 6cb50776c5..661d5f05ed 100644 --- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java +++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java @@ -1,7 +1,7 @@ package com.fr.design; import com.fr.common.report.ReportState; -import com.fr.decision.webservice.v10.plugin.helper.PluginErrorRemindHandler; +import com.fr.design.plugin.remind.PluginErrorDesignReminder; import com.fr.design.data.DesignTableDataManager; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.DialogActionAdapter; @@ -35,7 +35,6 @@ import com.fr.process.engine.core.FineProcessContext; import com.fr.rpc.Result; import com.fr.stable.AssistUtils; import com.fr.stable.StringUtils; -import com.fr.env.PluginErrorRemindDialog; import com.fr.start.server.ServerTray; import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContextCallback; @@ -139,7 +138,7 @@ public class EnvChangeEntrance { if (template != null) { template.refreshToolArea(); } - pluginErrorRemind(); + PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); } catch (Exception exception) { // 失败的处理 WorkspaceExceptionHandler.getInstance().handleInSwitch(exception, selectedEnv); @@ -245,28 +244,6 @@ public class EnvChangeEntrance { } } - /** - * 插件启动错误信息提示 - */ - public void pluginErrorRemind() { - if (!WorkContext.getCurrent().isLocal()) { - return; - } - - String content = PluginErrorRemindHandler.pluginErrorContent(); - if (StringUtils.isNotEmpty(content)) { - // 该操作需要在当前awt操作之后执行,使用SwingUtilities.invokeLater将其置于awt操作对列末尾 - // 若使用UIUtil.invokeLaterIfNeeded,会立即执行,影响其他UI操作 - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - PluginErrorRemindDialog dialog = new PluginErrorRemindDialog(DesignerContext.getDesignerFrame(), content); - dialog.setVisible(true); - } - }); - } - } - /** * 判断是否需要做版本验证,判断依据为 * 1、选择的环境为远程环境 diff --git a/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java index 08273202d1..a41f6cb56d 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java @@ -40,7 +40,9 @@ public class PreferenceAction extends UpdateAction { DesignerEnvManager.loadLogSetting(); DesignerEnvManager.getEnvManager().saveXMLFile(); JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - jt.refreshToolArea(); + if (jt != null) { + jt.refreshToolArea(); + } preferencePane.showRestartDialog(); DesignerFrameFileDealerPane.getInstance().refreshDockingView(); } diff --git a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java index 9f15abee71..51b0ed2a7a 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java @@ -14,9 +14,11 @@ import com.fr.design.gui.frpane.UITabbedPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UIColorButton; import com.fr.design.gui.ibutton.UINoThemeColorButton; +import com.fr.design.gui.ibutton.UIRadioButton; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.icombobox.UIDictionaryComboBox; +import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ifilechooser.FileChooserArgs; import com.fr.design.gui.ifilechooser.FileChooserFactory; import com.fr.design.gui.ifilechooser.FileChooserProvider; @@ -26,6 +28,7 @@ import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.iprogressbar.UIProgressBarUI; import com.fr.design.gui.ispinner.UISpinner; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; import com.fr.design.jdk.JdkVersion; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; @@ -42,8 +45,10 @@ import com.fr.general.FRFont; import com.fr.general.IOUtils; import com.fr.general.Inter; import com.fr.general.log.Log4jConfig; +import com.fr.io.attr.ImageExportAttr; import com.fr.locale.InterProviderFactory; import com.fr.log.FineLoggerFactory; +import com.fr.report.ReportConfigManager; import com.fr.stable.Constants; import com.fr.stable.os.OperatingSystem; import com.fr.third.apache.logging.log4j.Level; @@ -52,19 +57,24 @@ import com.fr.transaction.Worker; import com.fr.workspace.WorkContext; import com.fr.workspace.server.vcs.VcsOperator; import com.fr.workspace.server.vcs.git.config.GcConfig; +import org.jetbrains.annotations.NotNull; import javax.swing.BorderFactory; import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.KeyStroke; +import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.Timer; import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.BorderLayout; @@ -177,6 +187,7 @@ public class PreferencePane extends BasicPane { private UICheckBox vcsEnableCheckBox; private UICheckBox saveCommitCheckBox; private UICheckBox useIntervalCheckBox; + private UICheckBox startupPageEnabledCheckBox; private IntegerEditor saveIntervalEditor; private UICheckBox gcEnableCheckBox; private UIButton gcButton; @@ -189,6 +200,14 @@ public class PreferencePane extends BasicPane { private JProgressBar gcProgressBar; private Timer gcProgressTimer; private UIButton gcOkButton = new UIButton(i18nText("Fine-Design_Report_OK")); + + private UIRadioButton previewResolutionBtnS; + private UIRadioButton previewResolutionBtnM; + + private UIRadioButton previewRenderSpeed; + private UIRadioButton previewRenderQuality; + private static final int DPI_SCALE_S = 1; + private static final int DPI_SCALE_M = 2; public PreferencePane() { this.initComponents(); @@ -201,9 +220,13 @@ public class PreferencePane extends BasicPane { UITabbedPane jtabPane = new UITabbedPane(); JPanel generalPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); - jtabPane.addTab(i18nText("Fine-Design_Basic_General"), generalPane); + UIScrollPane generalScrollPane = patchScroll(generalPane); + jtabPane.addTab(i18nText("Fine-Design_Basic_General"), generalScrollPane); + JPanel advancePane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); - jtabPane.addTab(i18nText("Fine-Design_Basic_Advanced"), advancePane); + UIScrollPane adviceScrollPane = patchScroll(advancePane); + jtabPane.addTab(i18nText("Fine-Design_Basic_Advanced"), adviceScrollPane); + contentPane.add(jtabPane, BorderLayout.NORTH); createFunctionPane(generalPane); @@ -219,6 +242,8 @@ public class PreferencePane extends BasicPane { createLanPane(generalPane); + // 先屏蔽下 + // createStartupPagePane(generalPane); createLengthPane(advancePane); createServerPane(advancePane); @@ -274,6 +299,7 @@ public class PreferencePane extends BasicPane { JPanel imageCompressPanel = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Template_Preview_Performance")); imageCompressPanelCheckBox = new UICheckBox(i18nText("Fine-Design_Image_Compress")); imageCompressPanel.add(imageCompressPanelCheckBox); + imageCompressPanel.add(createImageExportSettingPane()); advancePane.add(imageCompressPanel); JPanel designerStartupOption = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Startup_Option")); @@ -281,7 +307,43 @@ public class PreferencePane extends BasicPane { designerStartupOption.add(cloudAnalyticsDelayCheckBox); advancePane.add(designerStartupOption); } + + private JPanel createImageExportSettingPane() { + previewResolutionBtnS = new UIRadioButton(i18nText("Fine-Design_Image_Export_SD"), true); + previewResolutionBtnM = new UIRadioButton(i18nText("Fine-Design_Image_Export_HD")); + ButtonGroup previewResolutionBtnGroup = new ButtonGroup(); + previewResolutionBtnGroup.add(previewResolutionBtnS); + previewResolutionBtnGroup.add(previewResolutionBtnM); + + previewRenderSpeed = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Speed_Priority")); + previewRenderQuality = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Quality_First")); + ButtonGroup previewRenderGroup = new ButtonGroup(); + previewRenderGroup.add(previewRenderQuality); + previewRenderGroup.add(previewRenderSpeed); + JPanel imageExportSettingPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + JComponent[][] templateComps = { + {new UILabel(Toolkit.i18nText("Fine-Design_Report_Engine_Enlarge_Or_Reduce") + ":"), this.previewResolutionBtnS, this.previewResolutionBtnM}, + {new UILabel(Toolkit.i18nText("Fine-Design_Image_Export_Rendering_Quality") + ":"), this.previewRenderQuality, this.previewRenderSpeed}, + }; + imageExportSettingPane.add( + TableLayoutHelper.createGapTableLayoutPane( + templateComps, + new double[]{TableLayout.FILL, TableLayout.FILL}, + new double[]{TableLayout.FILL, TableLayout.FILL, TableLayout.FILL}, + 20, 0), + BorderLayout.CENTER); + imageExportSettingPane.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 0)); + return imageExportSettingPane; + } + @NotNull + private UIScrollPane patchScroll(JPanel generalPane) { + UIScrollPane generalPanelWithScroll = new UIScrollPane(generalPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + generalPanelWithScroll.setBorder(new EmptyBorder(0, 0, 0, 0)); + generalPanelWithScroll.setPreferredSize(new Dimension(generalPane.getWidth(), 600)); + return generalPanelWithScroll; + } + private void createVcsSettingPane(JPanel generalPane) { JPanel vcsPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Title")); generalPane.add(vcsPane); @@ -588,6 +650,21 @@ public class PreferencePane extends BasicPane { languageComboBox.setFont(FRFont.getInstance("Dialog", Font.PLAIN, 12));//为了在中文系统中显示韩文 return languageComboBox; } + + private void createStartupPagePane(JPanel generalPane) { + + // ben:选择版本语言; + JPanel startupPagePaneWrapper = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); + JPanel startupPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane("启动页配置"); + generalPane.add(startupPagePaneWrapper); + startupPagePaneWrapper.add(startupPane); + + startupPageEnabledCheckBox = new UICheckBox("启动设计器时,自动打开启动页"); + startupPane.add(startupPageEnabledCheckBox); + UILabel descLabel = new UILabel("注意:若在远程环境下直接关闭,再次启动时,启动速度会变慢"); + descLabel.setForeground(new Color(51, 51, 52, (int)Math.round(0.5 * 255))); + startupPane.add(descLabel); + } private String getDisplayShortCut(String shotrCut) { return shotrCut.replace(TYPE, DISPLAY_TYPE).replace(BACK_SLASH, DISPLAY_BACK_SLASH).replace(SLASH, DISPLAY_SLASH) @@ -757,7 +834,27 @@ public class PreferencePane extends BasicPane { this.startWithEmptyFile.setSelected(designerEnvManager.isStartWithEmptyFile()); this.imageCompressPanelCheckBox.setSelected(designerEnvManager.isImageCompress()); + + ImageExportAttr attr = ReportConfigManager.getProviderInstance().getImageExportAttr(); + if (attr.getPreviewRenderQuality() == ImageExportAttr.RENDER_SPEED) { + previewRenderSpeed.setSelected(true); + } else { + previewRenderQuality.setSelected(true); + } + + if (attr.getPreviewResolutionScale() == DPI_SCALE_S) { + previewResolutionBtnS.setSelected(true); + } else { + previewResolutionBtnM.setSelected(true); + } + boolean enabled = WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot(); + previewRenderSpeed.setEnabled(enabled); + previewRenderQuality.setEnabled(enabled); + previewResolutionBtnS.setEnabled(enabled); + previewResolutionBtnM.setEnabled(enabled); + this.cloudAnalyticsDelayCheckBox.setSelected(designerEnvManager.isCloudAnalyticsDelay()); +// this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled()); } private int chooseCase(int sign) { @@ -824,6 +921,7 @@ public class PreferencePane extends BasicPane { vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected()); vcsConfigManager.setSaveCommit(this.saveCommitCheckBox.isSelected()); vcsConfigManager.setUseInterval(this.useIntervalCheckBox.isSelected()); +// designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected()); Configurations.update(new Worker() { @Override public void run() { @@ -883,6 +981,18 @@ public class PreferencePane extends BasicPane { } }); + ImageExportAttr attr = ReportConfigManager.getProviderInstance().getImageExportAttr(); + if (previewRenderSpeed.isSelected()) { + attr.setPreviewRenderQuality(ImageExportAttr.RENDER_SPEED); + } else { + attr.setPreviewRenderQuality(ImageExportAttr.RENDER_QUALITY); + } + if (previewResolutionBtnS.isSelected()) { + attr.setPreviewResolutionScale(DPI_SCALE_S); + } else { + attr.setPreviewResolutionScale(DPI_SCALE_M); + } + } // 如果语言设置改变了,则显示重启对话框 diff --git a/designer-base/src/main/java/com/fr/design/components/loading/LoadingPane.java b/designer-base/src/main/java/com/fr/design/components/loading/LoadingPane.java new file mode 100644 index 0000000000..25b0fe1816 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/loading/LoadingPane.java @@ -0,0 +1,148 @@ +package com.fr.design.components.loading; + +import javax.swing.JComponent; +import javax.swing.Timer; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Composite; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.LayoutManager; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/4/12 + */ +public class LoadingPane extends JComponent implements ActionListener { + + private AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); + private volatile boolean mIsRunning; + private volatile boolean mIsFadingOut; + private Timer mTimer; + private int mAngle; + private int mFadeCount; + private int mFadeLimit = 15; + private int lines = 12; + private int maxAngle = 360; + private int angleAdd = 30; + + public LoadingPane() { + + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // do nothing + } + }); + + setLayout(getCoverLayout()); + setBackground(null); + setOpaque(false); + } + + protected LayoutManager getCoverLayout() { + return new LayoutManager() { + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return parent.getPreferredSize(); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return null; + } + + @Override + public void layoutContainer(Container parent) { + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + }; + } + + + @Override + public void paint(Graphics g) { + int w = this.getWidth(); + int h = this.getHeight(); + super.paint(g); + if (!mIsRunning) { + return; + } + Graphics2D g2 = (Graphics2D) g.create(); + float fade = (float) mFadeCount / (float) mFadeLimit; + Composite urComposite = g2.getComposite(); + g2.setComposite(composite); + g2.fillRect(0, 0, w, h); + g2.setComposite(urComposite); + int s = Math.min(w, h) / 50; + int cx = w / 2; + int cy = h / 2; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(Color.BLACK); + g2.rotate(Math.PI * mAngle / 180, cx, cy); + for (int i = 0; i < lines; i++) { + float scale = (11.0f - (float) i) / 11.0f; + g2.drawLine(cx + s, cy, cx + s * 2, cy); + g2.rotate(-Math.PI / 6, cx, cy); + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, scale * fade)); + } + g2.dispose(); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (mIsRunning) { + repaint(); + mAngle += angleAdd; + if (mAngle >= maxAngle) { + mAngle = 0; + } + if (mIsFadingOut) { + if (--mFadeCount == 0) { + mIsRunning = false; + mTimer.stop(); + } + } else if (mFadeCount < mFadeLimit) { + mFadeCount++; + } + } + } + + public void start() { + if (mIsRunning) { + return; + } + mIsRunning = true; + mIsFadingOut = false; + mFadeCount = 0; + int fps = 24; + int tick = 1000 / fps; + mTimer = new Timer(tick, this); + mTimer.start(); + } + + public void stop() { + mIsRunning = false; + mIsFadingOut = true; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java b/designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java new file mode 100644 index 0000000000..0a01f8bbf2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java @@ -0,0 +1,107 @@ +package com.fr.design.components.tooltip; + +import com.fr.base.GraphHelper; +import com.fr.design.gui.itooltip.UIToolTip; +import com.fr.log.FineLoggerFactory; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JToolTip; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ToolTipUI; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.GeneralPath; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.Enumeration; +import java.util.Vector; + +/** + * 现代化的 UIToolTip + * 见 设计文档 + * + * created by Harrison on 2022/07/09 + **/ +public class ModernToolTip extends UIToolTip { + + public ModernToolTip() { + super(); + setUI(new ModernToolTipUI()); + } + + private class ModernToolTipUI extends ToolTipUI { + + private String[] strs; + private Icon icon; + private boolean needPaint; + public void paint(Graphics g, JComponent c) { + if (!needPaint) { + return; + } + FontMetrics metrics = GraphHelper.getFontMetrics(c.getFont()); + Dimension size = c.getSize(); + int width = size.width; + int height = size.height; + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setColor(new Color(51, 51, 52, (int) Math.round(0.7 * 255))); + g2.fillRoundRect(0, 0, width, height, 0, 0); + + g2.setColor(Color.WHITE); + if (strs != null) { + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); + for (int i = 0; i < strs.length; i++) { + g2.drawString(strs[i], icon.getIconWidth() + 6, (metrics.getHeight()) * (i + 1)); + } + } + } + + @Override + public Dimension getPreferredSize(JComponent c) { + FontMetrics metrics = GraphHelper.getFontMetrics(c.getFont()); + String tipText = ((JToolTip) c).getTipText(); + icon = ((UIToolTip)c).getIcon(); + needPaint = true; + if (tipText == null) { + if(icon.getIconWidth() == -1) { + needPaint = false; + } + tipText = " "; + } + BufferedReader br = new BufferedReader(new StringReader(tipText)); + String line; + int maxWidth = 0; + Vector v = new Vector(); + try { + while ((line = br.readLine()) != null) { + int width = SwingUtilities.computeStringWidth(metrics, line); + maxWidth = (maxWidth < width) ? width : maxWidth; + v.addElement(line); + } + } catch (IOException ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + int lines = v.size(); + if (lines < 1) { + strs = null; + lines = 1; + } else { + strs = new String[lines]; + int i = 0; + for (Enumeration e = v.elements(); e.hasMoreElements(); i++) { + strs[i] = e.nextElement(); + } + } + int height = metrics.getHeight() * lines; + return new Dimension(maxWidth + icon.getIconWidth() + 10, Math.max(height, icon.getIconHeight()) + 6); + } + + } +} diff --git a/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java b/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java index 4b532b92d8..4720c8e103 100644 --- a/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java +++ b/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java @@ -15,7 +15,12 @@ public enum DesignerLaunchStatus implements Event { * 初始化环境完成 */ WORKSPACE_INIT_COMPLETE, - + + /** + * 设计器模块初始化开始 + */ + DESIGNER_INIT_STARTED, + /** * 设计器模块启动完成 */ diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java index 112adff560..573b35f791 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java @@ -13,6 +13,7 @@ import com.fr.design.data.BasicTableDataTreePane; import com.fr.design.data.BasicTableDataUtils; import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.StrategyConfigAttrUtils; +import com.fr.design.data.datapane.auth.TableDataAuthHelper; import com.fr.design.data.datapane.management.clip.TableDataTreeClipboard; import com.fr.design.data.datapane.management.search.pane.TableDataSearchRemindPane; import com.fr.design.data.datapane.management.search.pane.TreeSearchToolbarPane; @@ -22,6 +23,7 @@ import com.fr.design.data.tabledata.StoreProcedureWorkerListener; import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils; import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; import com.fr.design.data.tabledata.tabledatapane.DBTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.loading.TableDataLoadingPane; import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; @@ -39,7 +41,6 @@ import com.fr.design.gui.itextfield.UITextField; import com.fr.design.gui.itoolbar.UIToolbar; import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; import com.fr.design.i18n.Toolkit; -import com.fr.design.icon.IconPathConstants; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.menu.LineSeparator; @@ -87,6 +88,7 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -1017,8 +1019,46 @@ public class TableDataTreePane extends BasicTableDataTreePane { AbstractTableDataPane tableDataPane = wrapper.creatTableDataPane(); - //下面创建creatTableDataPane后会直接populate,所以populate时不能用后设置的一些参数,比如name - dgEdit(tableDataPane, dsName, false); + if (TableDataAuthHelper.needCheckAuthWhenEdit(wrapper.getTableData())) { + // 先打开一个Loading面板 + TableDataLoadingPane loadingPane = new TableDataLoadingPane(); + BasicDialog loadingDialog = loadingPane.showLargeWindow(SwingUtilities.getWindowAncestor(TableDataTreePane.this), null); + // 查询权限 + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + // 获取无权限连接名称集合 + Collection noAuthConnections = TableDataAuthHelper.getNoAuthConnections(); + // 获取当前数据集对应的数据连接名称 + String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData()); + return !noAuthConnections.contains(connectionName); + } + + @Override + protected void done() { + try { + Boolean hasAuth = get(); + if (hasAuth) { + // 有权限时,关闭Loading面板,打开编辑面板 + loadingDialog.setVisible(false); + dgEdit(tableDataPane, dsName, false); + } else { + // 无权限时,给出无权限提示 + loadingPane.switchTo(TableDataLoadingPane.NO_AUTH_PANE_NAME); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("loading connection error in remote design", e.getMessage()); + // 查询权限失败时,给出报错提示 + loadingPane.switchTo(TableDataLoadingPane.ERROR_NAME); + } + } + }.execute(); + loadingDialog.setVisible(true); + } else { + // 无需检查权限时,直接打开数据库查询编辑面板 + //下面创建creatTableDataPane后会直接populate,所以populate时不能用后设置的一些参数,比如name + dgEdit(tableDataPane, dsName, false); + } } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java b/designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java new file mode 100644 index 0000000000..382e04dd94 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java @@ -0,0 +1,57 @@ +package com.fr.design.data.datapane.auth; + +import com.fr.base.TableData; +import com.fr.data.impl.Connection; +import com.fr.data.impl.DBTableData; +import com.fr.data.impl.NameDatabaseConnection; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.connection.DBConnectAuth; + +import java.util.Collection; +import java.util.Collections; + +/** + * 数据连接权限相关的工具类 + * @author Yvan + */ +public class TableDataAuthHelper { + + /** + * 编辑数据集时是否需要检查权限 + * @param tableData + * @return + */ + public static boolean needCheckAuthWhenEdit(TableData tableData) { + // 远程设计下,编辑DBTableData时需要判断权限 + return !WorkContext.getCurrent().isLocal() && tableData instanceof DBTableData; + } + + /** + * 获取无权限数据连接集合 + * 远程下需要调用RPC,为耗时操作,谨慎使用 + * @return + */ + public static Collection getNoAuthConnections() { + // 获取无权限连接集合 + Collection noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections(); + return noAuthConnections == null ? Collections.emptyList() : noAuthConnections; + } + + /** + * 通过数据集获取其数据连接的名称 + * + * 注意: + * 1. Connection接口本身是不提供名称的,只有我们内部为了使用方便,将其包装成了NameDataBaseConnection + * 如果不是NameDataBaseConnection类型,则无名称,因此这里只能用判断类型的方式获取名称 + * 2. 仅支持DBTableData获取连接名 + * @return + */ + public static String getConnectionNameByDBTableData(DBTableData tableData) { + Connection database = tableData.getDatabase(); + if (database instanceof NameDatabaseConnection) { + return ((NameDatabaseConnection) database).getName(); + } + return StringUtils.EMPTY; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java index 640fb2762a..76f32d6f0c 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java @@ -138,18 +138,34 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { if (connection instanceof NameDatabaseConnection) { this.setSelectedItem(((NameDatabaseConnection) connection).getName()); } else { - String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); - if (StringUtils.isNotBlank(s)) { - // 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白 - // 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置 - if (nameList.contains(s)) { - this.setSelectedItem(s); - } - } - // alex:如果这个ComboBox还是没有选中,那么选中第一个 - if (StringUtils.isBlank(this.getSelectedItem()) && this.getConnectionSize() > 0) { - this.setSelectedItem(this.getConnection(0)); + setRecentConnection(); + } + } + + /** + * 下拉框选项设置成最近选择的connection,如果最近选择不存在,则选择列表中的第一个 + */ + protected void setRecentConnection() { + String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); + if (StringUtils.isNotBlank(s)) { + // 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白 + // 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置 + if (nameList.contains(s)) { + this.setSelectedItem(s); } } + // alex:如果这个ComboBox还是没有选中,那么选中第一个 + if (StringUtils.isBlank(this.getSelectedItem()) && this.getConnectionSize() > 0) { + this.setSelectedItem(this.getConnection(0)); + } + } + + /** + * 是否无选中状态(空白item也视为无选中) + * @return + */ + protected boolean isSelectedItemEmpty() { + String selectedItem = this.getSelectedItem(); + return selectedItem == null || StringUtils.equals(selectedItem, EMPTY.toString()); } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java index 93f2938556..f6ddfc5b98 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java @@ -7,6 +7,7 @@ import com.fr.data.impl.Connection; import com.fr.data.impl.ConnectionBean; import com.fr.data.impl.JDBCDatabaseConnection; import com.fr.data.impl.JNDIDatabaseConnection; +import com.fr.data.metric.utils.DatabaseConnectionMetricHandler; import com.fr.design.ExtraDesignClassManager; import com.fr.design.data.MapCompareUtils; import com.fr.design.dialog.BasicDialog; @@ -186,6 +187,9 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh case ADDED: case UPDATED: addedOrUpdatedConnections.add(new ConnectionBean(s, StringUtils.EMPTY, connection)); + if (connection instanceof JDBCDatabaseConnection){ + DatabaseConnectionMetricHandler.handleSaveConnection((JDBCDatabaseConnection) connection, null); + } default: break; } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java index a979a20cd6..613eed9a48 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java @@ -1,26 +1,32 @@ package com.fr.design.data.datapane.connect; import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; import com.fr.data.core.db.TableProcedure; import com.fr.data.impl.AbstractDatabaseConnection; import com.fr.data.impl.Connection; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.UIConstants; +import com.fr.design.data.tabledata.tabledatapane.DBTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ilist.TableViewList; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.general.GeneralContext; import com.fr.stable.ArrayUtils; +import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.ToolTipManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -45,7 +51,39 @@ public class ConnectionTableProcedurePane extends BasicPane { private java.util.List listeners = new java.util.ArrayList(); public ConnectionTableProcedurePane() { + init(null); + } + + /** + * 传入父容器 + * @param parent + */ + public ConnectionTableProcedurePane(SwitchableTableDataPane parent) { + init(parent); + } + + private void init(SwitchableTableDataPane parent) { this.setLayout(new BorderLayout(4, 4)); + // 初始化数据连接下拉框 + initConnectionComboBox(parent); + // 初始化中间的面板 + JPanel centerPane = initCenterPane(); + this.add(connectionComboBox, BorderLayout.NORTH); + this.add(centerPane, BorderLayout.CENTER); + this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); + addKeyMonitor(); + } + + private JPanel initCenterPane() { + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // 搜索面板 + centerPane.add(createSearchPane(), BorderLayout.NORTH); + // 数据库表视图面板 + centerPane.add(createTableViewBorderPane(), BorderLayout.CENTER); + return centerPane; + } + + private void initConnectionComboBox(SwitchableTableDataPane parent) { connectionComboBox = new ConnectionComboBoxPanel(com.fr.data.impl.Connection.class) { @Override @@ -60,10 +98,34 @@ public class ConnectionTableProcedurePane extends BasicPane { search(true); } } + + @Override + protected void afterRefreshItems() { + // 刷新完成后,如果未选中(在nameList初始化完成之前可能会出现),则尝试再次设置 + if (isSelectedItemEmpty()) { + setRecentConnection(); + } + // 获取数据连接之后,让父容器切换面板 + if (parent != null) { + parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); + } + } + + @Override + protected void refreshItemsError() { + // 获取数据连接出现错误时,也让父容器从Loading面板切换至内容面板 + if (parent != null) { + parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); + } + } }; + connectionComboBox.addComboBoxActionListener(filter); + } + + private JPanel createTableViewBorderPane() { tableViewList = new TableViewList(); ToolTipManager.sharedInstance().registerComponent(tableViewList); - connectionComboBox.addComboBoxActionListener(filter); + tableViewList.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { if (evt.getClickCount() >= 2) { @@ -80,23 +142,50 @@ public class ConnectionTableProcedurePane extends BasicPane { } } }); - JPanel filterPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); + tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + JPanel tableViewBorderPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tableViewBorderPane.add(tableViewListPane, BorderLayout.CENTER); JPanel checkBoxgroupPane = createCheckBoxgroupPane(); if (checkBoxgroupPane != null) { - filterPane.add(createCheckBoxgroupPane(), BorderLayout.NORTH); + tableViewBorderPane.add(createCheckBoxgroupPane(), BorderLayout.SOUTH); } + return tableViewBorderPane; + } + + /** + * 创建搜索Panel,用于搜索表或视图 + * @return + */ + private JPanel createSearchPane() { + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); JPanel searchPane = new JPanel(new BorderLayout(10, 0)); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.setBackground(Color.WHITE); searchField = new UITextField(); - searchPane.add(searchField, BorderLayout.CENTER); + searchField.setBorderPainted(false); + searchField.setPlaceholder(Toolkit.i18nText("Fine-Design_Basic_Table_Search")); searchField.getDocument().addDocumentListener(searchListener); - filterPane.add(searchPane, BorderLayout.CENTER); - UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); - tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); - this.add(connectionComboBox, BorderLayout.NORTH); - this.add(tableViewListPane, BorderLayout.CENTER); - this.add(filterPane, BorderLayout.SOUTH); - this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); - addKeyMonitor(); + searchField.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.CHECKBOX_HOVER_SELECTED)); + } + + @Override + public void mouseExited(MouseEvent e) { + super.mouseExited(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + } + }); + // 搜索图标 + UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); + searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + searchPane.add(searchField, BorderLayout.CENTER); + searchPane.add(searchLabel, BorderLayout.EAST); + panel.add(searchPane, BorderLayout.CENTER); + return panel; } protected void filter(Connection connection, String conName, List nameList) { @@ -224,4 +313,4 @@ public class ConnectionTableProcedurePane extends BasicPane { */ public void actionPerformed(TableProcedure target); } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java index d0738e57b8..a430a13bd1 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java @@ -127,10 +127,12 @@ public abstract class ItemEditableComboBoxPanel extends JPanel { itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() + 1); itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() - 1); } + afterRefreshItems(); } catch (Exception e) { if (!(e instanceof CancellationException)) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } + refreshItemsError(); } } @@ -160,6 +162,20 @@ public abstract class ItemEditableComboBoxPanel extends JPanel { */ protected abstract java.util.Iterator items(); + /** + * 刷新ComboBox.items之后 + */ + protected void afterRefreshItems() { + // 空实现,供子类重写 + } + + /** + * 刷新ComboBox.items时出现异常 + */ + protected void refreshItemsError() { + // 空实现,供子类重写 + } + /* * 弹出对话框编辑Items */ diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java index e73f64eb36..d0ffd7f22c 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java @@ -20,6 +20,8 @@ import com.fr.design.data.datapane.preview.sql.PreviewPerformedSqlPane; import com.fr.design.data.datapane.sqlpane.SQLEditPane; import com.fr.design.data.tabledata.strategy.StrategyConfigHandler; import com.fr.design.data.tabledata.tabledatapane.db.StrategyConfigFrom; +import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; @@ -36,6 +38,7 @@ import com.fr.design.gui.itoolbar.UIToolbar; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; import com.fr.design.gui.syntax.ui.rtextarea.RTextScrollPane; import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.menu.SeparatorDef; import com.fr.design.menu.ToolBarDef; @@ -70,6 +73,7 @@ import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import java.awt.BorderLayout; +import java.awt.CardLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; @@ -86,7 +90,7 @@ import java.util.List; * @version 10.0 * Created by rinoux on 2020/7/22 */ -public class DBTableDataPane extends AbstractTableDataPane { +public class DBTableDataPane extends AbstractTableDataPane implements SwitchableTableDataPane { private static final int BOTTOM = 6; private static final String PREVIEW_BUTTON = Toolkit.i18nText("Fine-Design_Basic_Preview"); @@ -109,14 +113,42 @@ public class DBTableDataPane extends AbstractTableDataPane { private StrategyConfigHandler configHandler; + private CardLayout card; + /** 数据库查询面板真正的内容面板 */ + private JPanel contentPane; + /** 加载中面板 */ + private JPanel loadingPane; public DBTableDataPane() { + initCards(); + initContentPane(); + } + + /** + * 初始化内容面板 + */ + protected void initContentPane() { init(); initMainSplitPane(); } + /** + * 初始化cardLayout以及LoadingPane等,并且布局切到LoadingPane + */ + protected void initCards() { + card = new CardLayout(); + setLayout(card); + + loadingPane = new TipsPane(true); + contentPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + + add(LOADING_PANE_NAME, loadingPane); + add(CONTENT_PANE_NAME, contentPane); + switchTo(LOADING_PANE_NAME); + } + private void init() { - setLayout(new BorderLayout(4, 4)); + contentPane.setLayout(new BorderLayout(4, 4)); this.sqlTextPane = new SQLEditPane(); this.sqlTextPane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL); @@ -130,7 +162,7 @@ public class DBTableDataPane extends AbstractTableDataPane { editorPane = new UITableEditorPane<>(model); - this.connectionTableProcedurePane = new ConnectionTableProcedurePane() { + this.connectionTableProcedurePane = new ConnectionTableProcedurePane(this) { @Override protected void filter(Connection connection, String conName, List nameList) { connection.addConnection(nameList, conName, new Class[]{ @@ -231,7 +263,21 @@ public class DBTableDataPane extends AbstractTableDataPane { JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, this.connectionTableProcedurePane, sqlSplitPane); mainSplitPane.setBorder(BorderFactory.createLineBorder(GUICoreUtils.getTitleLineBorderColor())); mainSplitPane.setOneTouchExpandable(true); - add(mainSplitPane, BorderLayout.CENTER); + contentPane.add(mainSplitPane, BorderLayout.CENTER); + } + + @Override + public void switchTo(String panelName) { + try { + if (panelName != null) { + card.show(this, panelName); + } + } catch (IllegalArgumentException ingore) { + // 有些直接继承此面板或者替换掉此面板的插件,在未适配此功能时会出现报错,因为不是CardLayout,无法切换,这里处理下 + FineLoggerFactory.getLogger().info("cannot switch pane by {}", this.getClass().getName()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } } private boolean isPreviewOrRefreshButton(FocusEvent e) { diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java new file mode 100644 index 0000000000..221ee1cbba --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java @@ -0,0 +1,23 @@ +package com.fr.design.data.tabledata.tabledatapane.loading; + + + +/** + * 可切换的DBTableData对应的数据集面板,需要使用CardLayout布局 + * 主要是给插件适配用的 + * @author Yvan + */ +public interface SwitchableTableDataPane { + + /** Loading面板 */ + String LOADING_PANE_NAME = "Loading"; + /** 内容面板 */ + String CONTENT_PANE_NAME = "Content"; + + /** + * 根据面板名称切换面板 + * @param paneName 面板名称 + */ + void switchTo(String paneName); + +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java new file mode 100644 index 0000000000..c3f12c3e7f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java @@ -0,0 +1,54 @@ +package com.fr.design.data.tabledata.tabledatapane.loading; + +import com.fr.design.dialog.BasicPane; +import com.fr.design.i18n.Toolkit; + +import javax.swing.JPanel; +import java.awt.CardLayout; + +/** + * @author Yvan + */ +public class TableDataLoadingPane extends BasicPane { + + /** Loading面板 */ + public static final String LOADING_PANE_NAME = "Loading"; + /** 无权限提示面板 */ + public static final String NO_AUTH_PANE_NAME = "NoAuthority"; + /** 错误提示面板 */ + public static final String ERROR_NAME = "Error"; + + private CardLayout card; + + /** 加载中面板 */ + private JPanel loadingPane; + /** 错误提示面板 */ + private JPanel errorPane; + /** 数据连接无权限面板 */ + private JPanel noAuthorityPane; + + public TableDataLoadingPane() { + initPanes(); + } + + private void initPanes() { + card = new CardLayout(); + this.setLayout(card); + loadingPane = new TipsPane(true); + errorPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Error")); + noAuthorityPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_No_Auth")); + add(LOADING_PANE_NAME, loadingPane); + add(NO_AUTH_PANE_NAME, noAuthorityPane); + add(ERROR_NAME, errorPane); + switchTo(LOADING_PANE_NAME); + } + + public void switchTo(String panelName) { + card.show(this, panelName); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Basic_DS-Database_Query"); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java new file mode 100644 index 0000000000..40fcb6ef28 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java @@ -0,0 +1,45 @@ +package com.fr.design.data.tabledata.tabledatapane.loading; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; + +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; + +/** + * 提示面板,支持自定义提示,支持进度条配置可选 + * @author Yvan + */ +public class TipsPane extends JPanel { + + /** + * 默认提示 + */ + private static final String LOADING = Toolkit.i18nText("Fine-Design_Basic_Loading_And_Waiting"); + + public TipsPane () { + this(LOADING, false); + } + + public TipsPane (String tip) { + this(tip, false); + } + + public TipsPane (boolean needProgressBar) { + this(LOADING, needProgressBar); + } + + public TipsPane (String tips, boolean needProgressBar) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + UILabel tipsLabel = new UILabel(tips, SwingConstants.CENTER); + this.add(tipsLabel, BorderLayout.CENTER); + if (needProgressBar) { + JProgressBar progressBar = new JProgressBar(); + progressBar.setIndeterminate(true); + this.add(progressBar, BorderLayout.SOUTH); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java index a9b97d2698..bd2e8b2afb 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java @@ -296,7 +296,7 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver, UIOb return selectedIndex; } - protected void setSelectedIndex(int newSelectedIndex, boolean fireChanged) { + public void setSelectedIndex(int newSelectedIndex, boolean fireChanged) { if (selectedIndex != newSelectedIndex) { selectedIndex = newSelectedIndex; for (int i = 0; i < labelButtonList.size(); i++) { diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java index d772591047..12ca005249 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java @@ -63,7 +63,7 @@ public class UITabGroup extends UIButtonGroup { } @Override - protected void setSelectedIndex(int newSelectedIndex, boolean fireChanged) { + public void setSelectedIndex(int newSelectedIndex, boolean fireChanged) { super.setSelectedIndex(newSelectedIndex, false); tabChanged(newSelectedIndex); } diff --git a/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java b/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java index 85d73515e5..c98455a58f 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java +++ b/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java @@ -14,11 +14,18 @@ import java.awt.event.MouseEvent; public class ActionLabel extends UILabel { private ActionListener actionListener; private Color color; + // 文字是否有下划线 + private boolean drawUnderLine = true; public ActionLabel(String text) { this(text, Color.blue); } + public ActionLabel(String text, boolean drawUnderLine) { + this(text, Color.blue); + this.drawUnderLine = drawUnderLine; + } + public ActionLabel(String text, Color color) { super(text); this.color = color; @@ -39,7 +46,9 @@ public class ActionLabel extends UILabel { super.paintComponent(_gfx); _gfx.setColor(this.color); - _gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1); + if (drawUnderLine) { + _gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1); + } } private MouseInputAdapter mouseInputAdapter = new MouseInputAdapter() { @@ -95,4 +104,12 @@ public class ActionLabel extends UILabel { } } }; -} \ No newline at end of file + + public boolean isDrawUnderLine() { + return drawUnderLine; + } + + public void setDrawUnderLine(boolean drawUnderLine) { + this.drawUnderLine = drawUnderLine; + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java b/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java index 8db73f8e66..ab6fb70b41 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java +++ b/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java @@ -67,6 +67,9 @@ public class UIToolTip extends JToolTip{ this.addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { Container container = getComponent(); + if (container == null) { + return; + } while (!ComparatorUtils.equals(container.getClass(), UIScrollPane.class)) { if (container.getParent() == null) { break; diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeAttrChangeListener.java b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeAttrChangeListener.java new file mode 100644 index 0000000000..c31cfe5295 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeAttrChangeListener.java @@ -0,0 +1,7 @@ +package com.fr.design.gui.itree.refreshabletree; + +import com.fr.data.impl.TreeAttr; + +public interface TreeAttrChangeListener { + void doChange(TreeAttr treeAttr); +} diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java index a848b06d69..691749fac6 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java @@ -10,21 +10,24 @@ import javax.swing.BoxLayout; import javax.swing.JPanel; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.List; public class TreeRootPane extends BasicPane { + private final List listeners = new ArrayList<>(); + // 是否支持多选(checkBoxTree) //private JCheckBox multipleSelection; - private UICheckBox checkTypeCheckBox; + private final UICheckBox checkTypeCheckBox; // richer:加载的方式,支持异步加载和完全加载 - private UICheckBox loadTypeCheckBox; + private final UICheckBox loadTypeCheckBox; - private UICheckBox layerTypeCheckBox; + private final UICheckBox layerTypeCheckBox; - private UICheckBox returnFullPathCheckBox; + private final UICheckBox returnFullPathCheckBox; public TreeRootPane() { this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); @@ -41,13 +44,6 @@ public class TreeRootPane extends BasicPane { checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); loadTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Load_By_Async")); loadTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - loadTypeCheckBox.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - UICheckBox checkBox = (UICheckBox) e.getSource(); - doLoadTypeChange(checkBox.isSelected()); - } - }); loadTypePane.add(loadTypeCheckBox); this.add(loadTypePane); @@ -63,11 +59,27 @@ public class TreeRootPane extends BasicPane { checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); returnFullPathPane.add(returnFullPathCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Return_Full_Path"))); returnFullPathCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + addCheckBoxListener(); this.add(returnFullPathPane); } + private void addCheckBoxListener() { + loadTypeCheckBox.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + UICheckBox checkBox = (UICheckBox) e.getSource(); + doLoadTypeChange(checkBox.isSelected()); + } + }); + + checkTypeCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + loadTypeCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + layerTypeCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + returnFullPathCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + } + private void doLoadTypeChange(Boolean selected) { //给埋点插件提供一个方法,埋埋点用 } @@ -82,6 +94,7 @@ public class TreeRootPane extends BasicPane { loadTypeCheckBox.setSelected(treeAttr.isAjax()); layerTypeCheckBox.setSelected(treeAttr.isSelectLeafOnly()); returnFullPathCheckBox.setSelected(treeAttr.isReturnFullPath()); + fireTreeAttrChangeListener(); } public TreeAttr update() { @@ -93,4 +106,17 @@ public class TreeRootPane extends BasicPane { return treeAttr; } + + public void addTreeAttrChangeListener(TreeAttrChangeListener listener) { + listeners.add(listener); + } + + public void fireTreeAttrChangeListener() { + TreeAttr treeAttr = new TreeAttr(); + treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected()); + treeAttr.setAjax(loadTypeCheckBox.isSelected()); + treeAttr.setSelectLeafOnly(layerTypeCheckBox.isSelected()); + treeAttr.setReturnFullPath(returnFullPathCheckBox.isSelected()); + listeners.forEach(listener -> listener.doChange(treeAttr)); + } } diff --git a/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java b/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java index 071feee6ac..401fae8497 100644 --- a/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java +++ b/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java @@ -13,6 +13,9 @@ import javax.swing.JRadioButton; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.LayoutManager; @@ -148,6 +151,50 @@ public class FRGUIPaneFactory { public static LayoutManager createNColumnGridLayout(int nColumn) { return new FRGridLayout(nColumn); } + + /** + * 将 centerBody 为中心,创建一个布局 + * 注:只有当且仅当有一个组件,且希望组件 上下左右 居中时使用 + * @param centerBody 中心组件 + * @return 布局方式 + */ + public static LayoutManager createCenterLayout(JComponent centerBody) { + + final double yFactor = 0.30; + return new LayoutManager() { + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return centerBody.getPreferredSize(); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return null; + } + + @Override + public void layoutContainer(Container parent) { + int width = parent.getParent().getWidth(); + int height = parent.getParent().getHeight(); + + // 这个时候大小是不确定的 + int bodyWidth = centerBody.getPreferredSize().width; + int bodyHeight = centerBody.getPreferredSize().height; + int labelX = (width - bodyWidth) / 2; + int labelY = (int) ((height - bodyHeight) * yFactor); + centerBody.setBounds(labelX, labelY, bodyWidth, bodyHeight); + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + }; + } /** * 创建一个带标题边框面板 diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java index 4751649b83..da8f28f60d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java @@ -29,17 +29,16 @@ import com.fr.design.fun.impl.AbstractTemplateTreeShortCutProvider; import com.fr.design.gui.iprogressbar.ProgressDialog; import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.design.i18n.Toolkit; +import com.fr.design.lock.LockInfoDialog; import com.fr.design.mainframe.share.mini.MiniShopDisposingChecker; -import com.fr.design.mainframe.share.mini.MiniShopNativeTaskManager; import com.fr.design.mainframe.toolbar.ToolBarMenuDock; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; import com.fr.design.mainframe.vcs.common.VcsHelper; import com.fr.design.menu.ShortCut; import com.fr.design.os.impl.MacOsAddListenerAction; import com.fr.design.os.impl.SupportOSImpl; -import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.TemplateUtils; -import com.fr.design.lock.LockInfoDialog; +import com.fr.design.utils.gui.GUICoreUtils; import com.fr.event.EventDispatcher; import com.fr.exception.DecryptTemplateException; import com.fr.exception.TplLockedException; @@ -60,11 +59,11 @@ import com.fr.stable.os.OperatingSystem; import com.fr.stable.os.support.OSSupportCenter; import com.fr.stable.project.ProjectConstants; import com.fr.start.OemHandler; +import com.fr.start.common.DesignerOpenEmptyPanel; import com.fr.workspace.WorkContext; import com.fr.workspace.Workspace; import com.fr.workspace.connect.WorkspaceConnectionInfo; -import java.util.UUID; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JFrame; @@ -103,6 +102,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; public class DesignerFrame extends JFrame implements JTemplateActionListener, TargetModifiedListener { @@ -171,7 +171,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta return; } //关闭前当前模板 停止编辑 - HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().stopEditing(); + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentEditingTemplate != null) { + currentEditingTemplate.stopEditing(); + } SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true); // 全部保存成功才退出 if (saveSomeTemplatePane.showSavePane()) { @@ -302,10 +305,15 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta } public void resizeFrame() { - - HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().setComposite(); + + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentEditingTemplate != null) { + currentEditingTemplate.setComposite(); + } reCalculateFrameSize(); - HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().doResize(); + if (currentEditingTemplate != null) { + currentEditingTemplate.doResize(); + } } @Deprecated @@ -798,6 +806,17 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta } } } + + public void showEmptyJTemplate() { + + DesignerOpenEmptyPanel designerOpenEmptyPanel = new DesignerOpenEmptyPanel(); + BorderLayout layout = (BorderLayout) basePane.getLayout(); + basePane.remove(layout.getLayoutComponent(BorderLayout.CENTER)); + basePane.remove(layout.getLayoutComponent(BorderLayout.EAST)); + basePane.add(designerOpenEmptyPanel, BorderLayout.CENTER); + + layeredPane.repaint(); + } /** * 添加新建模板, 并激活. diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIModeConfig.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIModeConfig.java index 1e072d956a..400f698185 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIModeConfig.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIModeConfig.java @@ -1,8 +1,11 @@ package com.fr.design.mainframe; +import com.fr.base.AutoChangeLineProvider; +import com.fr.base.DefaultAutoChangeLine; import com.fr.base.ScreenResolution; import com.fr.design.fun.ReportLengthUNITProvider; import com.fr.design.unit.UnitConvertUtil; +import com.fr.form.fit.NewUIModeAutoChangeLine; import com.fr.general.ComparatorUtils; import com.fr.stable.Constants; @@ -58,6 +61,14 @@ public class DesignerUIModeConfig { return mode.parseLengthUNIT(unitType); } + /** + * 获取不同模式下的换行逻辑 + * @return AutoChangeLineProvider + */ + public AutoChangeLineProvider getAutoChangeLineStrategy() { + return mode.getAutoChangeLineStrategy(); + } + /** * 获取不同模式下的屏幕分辨率 * @@ -75,6 +86,11 @@ public class DesignerUIModeConfig { return UnitConvertUtil.parseLengthUNIT(unitType); } + @Override + public AutoChangeLineProvider getAutoChangeLineStrategy() { + return new DefaultAutoChangeLine(); + } + @Override protected int getScreenResolution() { return ScreenResolution.getScreenResolution(); @@ -87,6 +103,11 @@ public class DesignerUIModeConfig { return new PXReportLengthUNIT(); } + @Override + public AutoChangeLineProvider getAutoChangeLineStrategy() { + return new NewUIModeAutoChangeLine(); + } + @Override protected int getScreenResolution() { return Constants.DEFAULT_WEBWRITE_AND_SCREEN_RESOLUTION; @@ -96,6 +117,8 @@ public class DesignerUIModeConfig { protected abstract ReportLengthUNITProvider parseLengthUNIT(int unitType); + public abstract AutoChangeLineProvider getAutoChangeLineStrategy(); + protected abstract int getScreenResolution(); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java b/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java index 8861a75919..26f2406985 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java @@ -1,58 +1,30 @@ package com.fr.design.mainframe; +import com.fr.design.components.loading.LoadingPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; + +import javax.swing.Timer; import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Component; -import java.awt.Composite; import java.awt.Container; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.LayoutManager; -import java.awt.RenderingHints; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import javax.swing.ImageIcon; -import javax.swing.JComponent; -import javax.swing.Timer; /** * @author hades * @version 10.0 * Created by hades on 2021/4/12 */ -public class TransparentPane extends JComponent implements ActionListener { +public class TransparentPane extends LoadingPane { private UILabel label; - private AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); - private volatile boolean mIsRunning; - private volatile boolean mIsFadingOut; - private Timer mTimer; - private int mAngle; - private int mFadeCount; - private int mFadeLimit = 15; - private int lines = 12; - private int maxAngle = 360; - private int angleAdd = 30; + private double prec = 0.56; public TransparentPane() { - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - // do nothing - } - }); - - setLayout(getCoverLayout()); - setBackground(null); - setOpaque(false); + super(); label = new UILabel(Toolkit.i18nText("Fine-Design_Saving_Template_Tip")); add(label); } @@ -91,72 +63,4 @@ public class TransparentPane extends JComponent implements ActionListener { }; } - - @Override - public void paint(Graphics g) { - int w = this.getWidth(); - int h = this.getHeight(); - super.paint(g); - if (!mIsRunning) { - return; - } - Graphics2D g2 = (Graphics2D) g.create(); - float fade = (float) mFadeCount / (float) mFadeLimit; - Composite urComposite = g2.getComposite(); - g2.setComposite(composite); - g2.fillRect(0, 0, w, h); - g2.setComposite(urComposite); - int s = Math.min(w, h) / 50; - int cx = w / 2; - int cy = h / 2; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(Color.BLACK); - g2.rotate(Math.PI * mAngle / 180, cx, cy); - for (int i = 0; i < lines; i++) { - float scale = (11.0f - (float) i) / 11.0f; - g2.drawLine(cx + s, cy, cx + s * 2, cy); - g2.rotate(-Math.PI / 6, cx, cy); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, scale * fade)); - } - g2.dispose(); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (mIsRunning) { - repaint(); - mAngle += angleAdd; - if (mAngle >= maxAngle) { - mAngle = 0; - } - if (mIsFadingOut) { - if (--mFadeCount == 0) { - mIsRunning = false; - mTimer.stop(); - } - } else if (mFadeCount < mFadeLimit) { - mFadeCount++; - } - } - } - - public void start() { - if (mIsRunning) { - return; - } - mIsRunning = true; - mIsFadingOut = false; - mFadeCount = 0; - int fps = 24; - int tick = 1000 / fps; - mTimer = new Timer(tick, this); - mTimer.start(); - } - - public void stop() { - mIsRunning = false; - mIsFadingOut = true; - } - } diff --git a/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java b/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java index 3faadf795a..12e3503a06 100644 --- a/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java +++ b/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java @@ -2,6 +2,8 @@ package com.fr.design.notification; import com.fr.design.notification.ui.NotificationCenterPane; +import com.fr.stable.StringUtils; + import java.util.ArrayList; import java.util.List; @@ -30,6 +32,15 @@ public class NotificationCenter { NotificationCenterPane.getNotificationCenterPane().refreshButton(); } + /** + * 通过messageId删除消息 + * @param messageID + */ + public void removeNotificationByMessageID(String messageID) { + notifications.removeIf(notification -> StringUtils.equals(notification.getMessageId(), messageID)); + NotificationCenterPane.getNotificationCenterPane().refreshButton(); + } + public Notification getNotification(int index){ return notifications.get(index); } diff --git a/designer-base/src/main/java/com/fr/design/plugin/remind/PluginErrorDesignReminder.java b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginErrorDesignReminder.java new file mode 100644 index 0000000000..6ba1c115ba --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginErrorDesignReminder.java @@ -0,0 +1,143 @@ +package com.fr.design.plugin.remind; + +import com.fr.design.dialog.NotificationDialogAction; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.notification.Notification; +import com.fr.design.notification.NotificationCenter; +import com.fr.plugin.error.PluginErrorRemindHandler; +import com.fr.plugin.error.PluginErrorReminder; +import com.fr.stable.StringUtils; +import com.fr.stable.collections.CollectionUtils; +import com.fr.workspace.WorkContext; + +import javax.swing.SwingUtilities; +import java.util.List; + +/** + * 插件错误信息提醒-设计器模块 + * + * @author Yvan + */ +public class PluginErrorDesignReminder implements PluginErrorReminder { + + private static final String MESSAGE_ID = "plugin-invalidate-remind"; + public static final String COMMA = "、"; + public static final String COLON = ":"; + public static final String NEW_LINE_TAG = "
"; + private static final int MAX_PLUGIN_NAME_PER_LINE = 3; + + private static class Holder { + private static final PluginErrorDesignReminder INSTANCE = new PluginErrorDesignReminder(); + } + + private PluginErrorDesignReminder() {} + + public static PluginErrorDesignReminder getInstance() { + return Holder.INSTANCE; + } + + @Override + public void remindStartFailedPlugins() { + + if (!WorkContext.getCurrent().isLocal()) { + return; + } + String content = PluginErrorRemindHandler.pluginErrorContent(); + if (StringUtils.isNotEmpty(content)) { + // 该操作需要在当前awt操作之后执行,使用SwingUtilities.invokeLater将其置于awt操作对列末尾 + // 若使用UIUtil.invokeLaterIfNeeded,会立即执行,影响其他UI操作 + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + PluginStartFailedRemindDialog dialog = new PluginStartFailedRemindDialog(DesignerContext.getDesignerFrame(), content); + dialog.setVisible(true); + } + }); + } + } + + @Override + public void remindInvalidatePlugins() { + + if (!WorkContext.getCurrent().isLocal()) { + return; + } + // 获取失效插件名称列表 + List embedPluginNames = PluginErrorRemindHandler.getInvalidateEmbedPluginNames(); + if (!CollectionUtils.isEmpty(embedPluginNames)) { + // 构建消息 + String message = generateMessageContent(embedPluginNames); + Notification notification = generateNotification(message, embedPluginNames); + // 添加消息 + NotificationCenter.getInstance().addNotification(notification); + } + } + + /** + * 构建消息内容 + * @param invalidatePluginNames + * @return + */ + private String generateMessageContent(List invalidatePluginNames) { + return new StringBuilder() + .append(Toolkit.i18nText("Fine-Design_Plugin_Embed_Notice")) + .append(COLON) + .append(NEW_LINE_TAG) + .append(NEW_LINE_TAG) + .append(dealWithPluginNames(invalidatePluginNames)) + .append(NEW_LINE_TAG) + .append(NEW_LINE_TAG) + .append(Toolkit.i18nText("Fine-Design_Plugin_Embed_Description")) + .append(NEW_LINE_TAG) + .toString(); + } + + /** + * 处理消息中的插件名称展示 + * 由于Notification那边展示的弹窗是随消息宽度变化的,所以插件名称很多时会变得很长。这里做个分行 + * @return + * @param invalidatePluginNames + */ + public String dealWithPluginNames(List invalidatePluginNames) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < invalidatePluginNames.size(); i++) { + String pluginName = invalidatePluginNames.get(i); + builder.append(pluginName); + if (i != invalidatePluginNames.size() - 1) { + builder.append(i % MAX_PLUGIN_NAME_PER_LINE == (MAX_PLUGIN_NAME_PER_LINE - 1) ? NEW_LINE_TAG : COMMA); + } + } + return builder.toString(); + } + + /** + * 构建通知对象 + * @param message + * @param invalidatePluginNames + * @return + */ + private Notification generateNotification(String message, List invalidatePluginNames) { + return new Notification( + MESSAGE_ID, + Notification.WARNING_MESSAGE, + message, + new NotificationDialogAction() { + @Override + public String name() { + return "plugin-invalidate-remind-show"; + } + + @Override + public void doClick() { + PluginInvalidateRemindDialog remindDialog = new PluginInvalidateRemindDialog( + DesignerContext.getDesignerFrame(), + invalidatePluginNames, + PluginErrorRemindHandler.getInvalidateEmbedPluginMarkers(), + MESSAGE_ID); + remindDialog.setVisible(true); + } + } + ); + } +} diff --git a/designer-base/src/main/java/com/fr/design/plugin/remind/PluginInvalidateRemindDialog.java b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginInvalidateRemindDialog.java new file mode 100644 index 0000000000..0c9986951f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginInvalidateRemindDialog.java @@ -0,0 +1,211 @@ +package com.fr.design.plugin.remind; + +import com.fr.common.util.Collections; +import com.fr.design.actions.UpdateAction; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.DesignSizeI18nManager; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.notification.NotificationCenter; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.FRFont; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginMarker; +import com.fr.plugin.manage.PluginManager; +import com.fr.plugin.manage.control.PluginTaskCallback; +import com.fr.plugin.manage.control.PluginTaskResult; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +/** + * @author Yvan + */ +public class PluginInvalidateRemindDialog extends JDialog implements ActionListener{ + + /** + * 因内置而失效的插件Marker列表 + */ + private List pluginMarkers; + + /** + * 因内置而失效的插件名称列表 + */ + private List pluginNames; + + /** + * 本弹窗对应的消息的id + * 方便弹窗逻辑执行完之后,删除通知中心的消息 + */ + private String messageID; + + + public PluginInvalidateRemindDialog(Frame parent, List pluginNames, List pluginMarkers, String messageId) { + super(parent, true); + this.pluginMarkers = pluginMarkers; + this.pluginNames = pluginNames; + this.messageID = messageId; + // 标题 + this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Tool_Tips")); + this.setResizable(false); + + this.add(initTopPane(), BorderLayout.NORTH); + this.add(initCenterPanel(), BorderLayout.CENTER); + this.add(initBottomPanel(), BorderLayout.SOUTH); + this.setSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog")); + + GUICoreUtils.centerWindow(this); + + } + + /** + * 上层的面板,用于解释插件内置 + * @return + */ + private JPanel initTopPane() { + JPanel topPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + + // 图标面板 + JPanel imagePanel = new JPanel(); + Icon icon = IOUtils.readIcon("com/fr/design/images/warnings/icon_WarningIcon_normal.png"); + UILabel imageLabel = new UILabel(); + imageLabel.setIcon(icon); + imagePanel.add(imageLabel); + imagePanel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); + + JPanel verticalPanel = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); + UILabel noticeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Notice")); + noticeLabel.setFont(FRFont.getInstance().applySize(16)); + UILabel adviceLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Advice")); + UILabel descriptionLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Description")); + verticalPanel.add(noticeLabel); + verticalPanel.add(adviceLabel); + verticalPanel.add(descriptionLabel); + + topPane.add(imagePanel, BorderLayout.WEST); + topPane.add(verticalPanel, BorderLayout.CENTER); + topPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 20)); + return topPane; + } + + /** + * 中层面板,用于展示内置插件列表 + * @return + */ + private JPanel initCenterPanel() { + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + + // "插件列表"标签面板 + UILabel textLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_List")); + textLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); + + JTextPane textPane = new JTextPane(); + textPane.setEditable(false); + textPane.setBackground(Color.WHITE); + SimpleAttributeSet attributeSet = new SimpleAttributeSet(); + StyleConstants.setLineSpacing(attributeSet, 0.5f); + textPane.setParagraphAttributes(attributeSet, true); + textPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + textPane.setText(generatePluginListText(pluginNames)); + JScrollPane scrollPane = new JScrollPane(textPane); + + centerPane.add(textLabel, BorderLayout.NORTH); + centerPane.add(scrollPane, BorderLayout.CENTER); + centerPane.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); + centerPane.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane")); + return centerPane; + } + + /** + * 生成中间面板展示的插件列表 + * @param pluginNames + * @return + */ + private String generatePluginListText(List pluginNames) { + String space = " "; + StringBuilder sb = new StringBuilder(); + for (String pluginName : pluginNames) { + sb.append(space).append(pluginName).append("\n"); + } + return sb.toString(); + } + + /** + * 底层面板,用于处理用户操作 + * @return + */ + private JPanel initBottomPanel() { + JPanel bottomPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + + UIButton ignore = new UIButton(Toolkit.i18nText("Fine-Design_Plugin_Embed_Ignore")); + UIButton delete = new UIButton(Toolkit.i18nText("Fine-Design_Plugin_Embed_Delete_Plugins")); + UILabel emptyLabel = new UILabel(); + ignore.addActionListener(this); + delete.addActionListener(new DeleteEmbedPluginsAction(this)); + bottomPane.add(ignore, BorderLayout.WEST); + bottomPane.add(emptyLabel, BorderLayout.CENTER); + bottomPane.add(delete, BorderLayout.EAST); + return bottomPane; + } + + @Override + public void actionPerformed(ActionEvent e) { + this.dispose(); + } + + private class DeleteEmbedPluginsAction extends UpdateAction { + + private JDialog dialog; + + + DeleteEmbedPluginsAction(JDialog dialog) { + this.dialog = dialog; + } + + @Override + public void actionPerformed(ActionEvent e) { + this.dialog.dispose(); + // 删除插件 + deleteEmbedPlugins(pluginMarkers); + // 删除消息 + NotificationCenter.getInstance().removeNotificationByMessageID(messageID); + } + + /** + * 删除插件 + * @param toDelete + */ + private void deleteEmbedPlugins(List toDelete) { + if (Collections.isEmpty(toDelete)) { + return; + } + for (PluginMarker pluginMarker : toDelete) { + // 删除插件 + PluginManager.getController().uninstall(pluginMarker, false, new PluginTaskCallback() { + @Override + public void done(PluginTaskResult result) { + // 输出结果日志 + FineLoggerFactory.getLogger().info( + "Detele Embed Plugin(id = {}, version = {}) {}", + pluginMarker.getPluginID(), + pluginMarker.getVersion(), result.isSuccess() ? "Succeeded" : "Failed"); + } + }); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/env/PluginErrorRemindDialog.java b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginStartFailedRemindDialog.java similarity index 96% rename from designer-base/src/main/java/com/fr/env/PluginErrorRemindDialog.java rename to designer-base/src/main/java/com/fr/design/plugin/remind/PluginStartFailedRemindDialog.java index 1558d72e95..639c7a2925 100644 --- a/designer-base/src/main/java/com/fr/env/PluginErrorRemindDialog.java +++ b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginStartFailedRemindDialog.java @@ -1,4 +1,4 @@ -package com.fr.env; +package com.fr.design.plugin.remind; import com.fr.design.ExtraDesignClassManager; import com.fr.design.actions.UpdateAction; @@ -32,11 +32,11 @@ import java.util.Set; /** * 插件启动失败提示窗 */ -public class PluginErrorRemindDialog extends JDialog implements ActionListener { +public class PluginStartFailedRemindDialog extends JDialog implements ActionListener { private static final String SIM_HEI = "SimHei"; - public PluginErrorRemindDialog(Frame parent, String text) { + public PluginStartFailedRemindDialog(Frame parent, String text) { super(parent, true); //上面的标签面板 JPanel topPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); diff --git a/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java b/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java new file mode 100644 index 0000000000..56db4cee9e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java @@ -0,0 +1,34 @@ +package com.fr.design.update.actions; + + +import com.fr.common.util.Strings; +import com.fr.design.utils.BrowseUtils; +import com.fr.general.CloudCenter; +import com.fr.log.FineLoggerFactory; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + + +/** + * 帮助-更新升级 + * 点击查看新特性 + * */ +public class NewFeatureAction implements ActionListener { + + + public static String DEFAULT_UPDATE_DETAIL_URL = "https://help.fanruan.com/finereport/doc-view-4699.html"; + + @Override + public void actionPerformed(ActionEvent e) { + try { + String url = CloudCenter.getInstance().acquireConf("fr.latest.update.detil"); + if (Strings.isEmpty(url)) { + url = DEFAULT_UPDATE_DETAIL_URL; + } + BrowseUtils.browser(url); + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage()); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java b/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java index deda005c36..bcdb25f954 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java @@ -9,6 +9,7 @@ import com.fr.design.dialog.FineJOptionPane; 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.ActionLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.i18n.Toolkit; @@ -16,6 +17,7 @@ import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.DesignerContext; import com.fr.design.update.actions.FileProcess; +import com.fr.design.update.actions.NewFeatureAction; import com.fr.design.update.domain.UpdateInfoCachePropertyManager; import com.fr.design.update.utils.UpdateFileUtils; import com.fr.design.update.ui.widget.LoadingLabel; @@ -86,6 +88,7 @@ public class UpdateMainDialog extends UIDialog { private static final String HYPHEN = "-"; private final SimpleDateFormat CHANGELOG_FORMAT = new SimpleDateFormat("M/d/y, h:m:s a", Locale.ENGLISH); + private final SimpleDateFormat UPDATELOG_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); private final SimpleDateFormat UPDATE_INFO_TABLE_FORMAT = new SimpleDateFormat("yyyy.MM.dd"); private JSONObject downloadFileConfig; @@ -93,8 +96,6 @@ public class UpdateMainDialog extends UIDialog { private LoadingLabel loadingLabel; //更新按钮 private UIButton updateButton; - //有新版本提示标签 - private UILabel updateLabel; //jar包版本信息面板,包括当前版本和最新版本 private JPanel jarVersionInfoPane; @@ -157,13 +158,8 @@ public class UpdateMainDialog extends UIDialog { progressBar.setStringPainted(true); progressBar.setPreferredSize(PROGRESSBAR); - updateLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_New_Version_Available")); - updateLabel.setHorizontalAlignment(SwingConstants.RIGHT); - updateLabel.setVisible(false); - progressBarPane.add(GUICoreUtils.createBorderLayoutPane( - progressBar, BorderLayout.CENTER, - updateLabel, BorderLayout.EAST + progressBar, BorderLayout.CENTER ), BorderLayout.CENTER); updateActionPane = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ @@ -183,9 +179,9 @@ public class UpdateMainDialog extends UIDialog { 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[] columnUpdateContentPaneSize = {TableLayout.PREFERRED, TableLayout.FILL}; 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[] columnUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_COLUMN_SIZE, TableLayout.PREFERRED, TableLayout.PREFERRED}; double[] columnUpdateSubContentPaneLabelSize = {UPDATE_CONTENT_PANE_LABEL_COLUMN_SIZE, TableLayout.PREFERRED}; JPanel jarUpdateContentPane = new JPanel(); @@ -195,15 +191,15 @@ public class UpdateMainDialog extends UIDialog { 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("Fine-Design_Updater_JAR_Version")), jarCurrentLabel), new UILabel()}, - new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Latest_JAR")), loadingLabel), new UILabel()}, + new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_JAR_Version")), jarCurrentLabel), jarRestoreLabel}, + new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Latest_JAR")), loadingLabel), + getNewFeatureActionLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Latest_Feature_Detail"))}, 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("Fine-Design_Updater_JarUpdate")), new UILabel(), jarRestoreLabel), new UILabel()}, new Component[]{new UILabel(), jarUpdateContentPane, new UILabel()} }, rowUpdatePaneSize, columnUpdatePaneSize, LayoutConstants.VGAP_LARGE); } @@ -221,7 +217,7 @@ public class UpdateMainDialog extends UIDialog { new Component[]{new UILabel(), new UILabel(), new UILabel()} }, searchRow, searchColumn, LayoutConstants.VGAP_LARGE); - String[] columnNames = {com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Date"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Content"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_SignHeader")}; + String[] columnNames = {com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Date"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Version"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Content"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_SignHeader")}; initUpdateInfoTable(columnNames); UIScrollPane uiScrollPane = new UIScrollPane(updateInfoTable); @@ -232,31 +228,32 @@ public class UpdateMainDialog extends UIDialog { } 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); + sorter.setSortable(UpdateInfoTable.UPDATE_DATE_INDEX, true); + sorter.setSortable(UpdateInfoTable.UPDATE_VERSION_INDEX, true); + sorter.setSortable(UpdateInfoTable.UPDATE_TITLE_INDEX, false); + sorter.setSortable(UpdateInfoTable.SIGN_INDEX, false); updateInfoTable.setRowSorter(sorter); List sortKeys = new ArrayList<>(); - sortKeys.add(new RowSorter.SortKey(updateTimeColIndex, SortOrder.DESCENDING)); + sortKeys.add(new RowSorter.SortKey(UpdateInfoTable.UPDATE_DATE_INDEX, SortOrder.DESCENDING)); + sortKeys.add(new RowSorter.SortKey(UpdateInfoTable.UPDATE_VERSION_INDEX, 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.getColumnModel().getColumn(UpdateInfoTable.UPDATE_DATE_INDEX).setMaxWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.UPDATE_DATE_INDEX).setMinWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.UPDATE_VERSION_INDEX).setMaxWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.UPDATE_VERSION_INDEX).setMinWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMaxWidth(0); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMinWidth(0); + updateInfoTable.getTableHeader().getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMaxWidth(0); + updateInfoTable.getTableHeader().getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMinWidth(0); updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Date")).setCellRenderer(new UpdateInfoTableCellRender()); + updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Version")).setCellRenderer(new UpdateInfoTableCellRender()); updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Content")).setCellRenderer(new UpdateInfoTextAreaCellRender()); } @@ -300,18 +297,18 @@ public class UpdateMainDialog extends UIDialog { updateButton.setEnabled(false); double[] rowSize = {TableLayout.PREFERRED}; + double[] colSize = {TableLayout.PREFERRED}; + UILabel versionLabel = new UILabel(UpdateConstants.DEFAULT_APP_NAME + StringUtils.BLANK + ProductConstants.VERSION); + versionLabel.setFont(new Font("Default", Font.BOLD, 16)); + - double[] colSize = {UPDATE_CONTENT_PANE_LABEL_COLUMN_SIZE, TableLayout.PREFERRED}; updateVersionReminderPane = initPaneContent( - Color.WHITE, rowSize, colSize, - new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Designer_Version")), - new UILabel(UpdateConstants.DEFAULT_APP_NAME + StringUtils.BLANK + ProductConstants.VERSION) + Color.WHITE, rowSize, colSize, versionLabel ); String notInstallVersion = InterProviderFactory.getProvider().getLocText("Fine-Core_Basic_About_No_Build"); String versionBuildNo = GeneralUtils.getVersion() + HYPHEN + GeneralUtils.readBuildNO(); jarCurrentLabel = new UILabel(ComparatorUtils.equals(notInstallVersion, GeneralUtils.readBuildNO()) ? notInstallVersion : versionBuildNo, SwingConstants.CENTER); - UILabel noJarPreviousRevision = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_No_Previous_Version")); UpdateActionLabel jarRestorePreviousRevision = new UpdateActionLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Restore"), false); jarRestorePreviousRevision.setForeground(new Color(RESTORE_LABEL_COLOR)); jarRestorePreviousRevision.addActionListener(new ActionListener() { @@ -323,7 +320,7 @@ public class UpdateMainDialog extends UIDialog { }); //choose RestoreLabel to show boolean isNeedRestore = ArrayUtils.isNotEmpty(UpdateFileUtils.listBackupVersions()); - jarRestoreLabel = isNeedRestore ? jarRestorePreviousRevision : noJarPreviousRevision; + jarRestoreLabel = isNeedRestore ? jarRestorePreviousRevision : null; } private void initComponents() { @@ -417,14 +414,21 @@ public class UpdateMainDialog extends UIDialog { if (downloadFileConfig == null) { throw new Exception("network error."); } - HttpGet get = new HttpGet(CloudCenter.getInstance().acquireUrlByKind("changelog10") + "&start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); - httpClient = HttpToolbox.getHttpClient(CloudCenter.getInstance().acquireUrlByKind("changelog10") + "&start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); + + HttpGet get = new HttpGet(CloudCenter.getInstance().acquireUrlByKind("updatelog") + "?start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); + httpClient = HttpToolbox.getHttpClient(CloudCenter.getInstance().acquireUrlByKind("updatelog") + "?start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); + + response = httpClient.execute(get); String responseText = CommonIOUtils.inputStream2String(response.getEntity().getContent(),EncodeConstants.ENCODING_UTF_8).trim(); + JSONArray array = JSONArray.create(); //假如返回"-1",说明socket出错了 if (!ComparatorUtils.equals(responseText, "-1")) { - array = new JSONArray(responseText); + JSONObject respObject = new JSONObject(responseText); + if (respObject != null && "success".equals(respObject.get("status"))) { + array = respObject.getJSONArray("data"); + } } return array; } catch (Exception e) { @@ -483,7 +487,7 @@ public class UpdateMainDialog extends UIDialog { continue; } } - if (isValidLogInfo(updateInfo[1])) { + if (isValidLogInfo(updateInfo[1]) && curJarDate != null) { updateInfoList.add(new Object[]{UPDATE_INFO_TABLE_FORMAT.format(updateTime), updateInfo[1], updateTime.after(curJarDate)}); } } @@ -531,9 +535,10 @@ public class UpdateMainDialog extends UIDialog { 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); + String updateTitle = (String) jo.get("jiraId") + " " + jo.get("info"); + String updateVersionStr = (String) jo.get("version"); + String updateTimeStr = (String) jo.get("updateTime"); + Date updateTime = UPDATELOG_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)); @@ -546,7 +551,7 @@ public class UpdateMainDialog extends UIDialog { } } if (isValidLogInfo(updateTitle)) { - updateInfoList.add(new Object[]{UPDATE_INFO_TABLE_FORMAT.format(updateTime), updateTitle, updateTime.after(curJarDate)}); + updateInfoList.add(new Object[]{UPDATE_INFO_TABLE_FORMAT.format(updateTime), updateVersionStr, updateTitle, updateTime.after(curJarDate)}); } } return new ArrayList<>(updateInfoList); @@ -579,14 +584,12 @@ public class UpdateMainDialog extends UIDialog { Date currentDate = (new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss")).parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); if (DateUtils.subtractDate(jarDate, currentDate, DateUtils.SECOND) > 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("Fine-Design_Updater_Already_Latest_Version")); } } else { updateButton.setEnabled(true); - updateLabel.setVisible(true); loadingLabel.stopLoading(buildNO.contains("-") ? buildNO.substring(buildNO.lastIndexOf("-") + 1) : buildNO); } @@ -608,41 +611,7 @@ public class UpdateMainDialog extends UIDialog { * jar包更新按钮监听器 */ private void addActionListenerForUpdateBtn() { - updateButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String[] option = {Toolkit.i18nText("Fine-Design_Report_Yes"), Toolkit.i18nText("Fine-Design_Report_No")}; - int a = JOptionPane.showOptionDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Information"), - Toolkit.i18nText("Fine-Design_Update_Info_Title"),JOptionPane.YES_NO_OPTION, QUESTION_MESSAGE, UIManager.getIcon("OptionPane.warningIcon"), option, 1); - if (a == 0) { - progressBar.setVisible(true); - progressBar.setString(Toolkit.i18nText("Fine-Design_Update_Info_Wait_Message")); - UpdateCallBack callBack = new UpdateProgressCallBack(progressBar); - updateButton.setEnabled(false); - updateLabel.setVisible(false); - RestoreResultDialog.deletePreviousPropertyFile(); - final String installLib = StableUtils.pathJoin(StableUtils.getInstallHome(), ProjectConstants.LOGS_NAME, UpdateConstants.INSTALL_LIB); - final JFrame frame = DesignerContext.getDesignerFrame(); - final RestartHelper helper = new RestartHelper(); - FineProcessContext.getParentPipe().fire(FineProcessEngineEvent.DESTROY); - new FileProcess(callBack) { - @Override - public void onDownloadSuccess() { - progressBar.setVisible(false); - deleteForDesignerUpdate(installLib); - helper.restartForUpdate(frame); - } - @Override - public void onDownloadFailed() { - progressBar.setVisible(false); - deleteForDesignerUpdate(installLib); - FineJOptionPane.showMessageDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Failed_Message")); - helper.restartForUpdate(frame); - } - }.execute(); - } - } - }); + updateButton.addActionListener(new UpdateAction()); } private void deleteForDesignerUpdate(String installLib) { @@ -688,6 +657,13 @@ public class UpdateMainDialog extends UIDialog { return false; } + private ActionLabel getNewFeatureActionLabel(final String text){ + ActionLabel actionLabel = new ActionLabel(text, new Color(RESTORE_LABEL_COLOR)); + actionLabel.setDrawUnderLine(false); + actionLabel.addActionListener(new NewFeatureAction()); + return actionLabel; + } + /** * 显示窗口 */ @@ -705,4 +681,41 @@ public class UpdateMainDialog extends UIDialog { @Override public void checkValid() throws Exception { } -} \ No newline at end of file + + + private class UpdateAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String[] option = {Toolkit.i18nText("Fine-Design_Report_Yes"), Toolkit.i18nText("Fine-Design_Report_No")}; + int a = JOptionPane.showOptionDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Information"), + Toolkit.i18nText("Fine-Design_Update_Info_Title"),JOptionPane.YES_NO_OPTION, QUESTION_MESSAGE, UIManager.getIcon("OptionPane.warningIcon"), option, 1); + if (a == 0) { + progressBar.setVisible(true); + progressBar.setString(Toolkit.i18nText("Fine-Design_Update_Info_Wait_Message")); + UpdateCallBack callBack = new UpdateProgressCallBack(progressBar); + updateButton.setEnabled(false); + RestoreResultDialog.deletePreviousPropertyFile(); + final String installLib = StableUtils.pathJoin(StableUtils.getInstallHome(), ProjectConstants.LOGS_NAME, UpdateConstants.INSTALL_LIB); + final JFrame frame = DesignerContext.getDesignerFrame(); + final RestartHelper helper = new RestartHelper(); + FineProcessContext.getParentPipe().fire(FineProcessEngineEvent.DESTROY); + new FileProcess(callBack) { + @Override + public void onDownloadSuccess() { + progressBar.setVisible(false); + deleteForDesignerUpdate(installLib); + helper.restartForUpdate(frame); + } + @Override + public void onDownloadFailed() { + progressBar.setVisible(false); + deleteForDesignerUpdate(installLib); + FineJOptionPane.showMessageDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Failed_Message")); + helper.restartForUpdate(frame); + } + }.execute(); + } + + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java index c7690f3d55..1b704826f7 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java @@ -10,6 +10,12 @@ import java.util.Vector; * Created by XINZAI on 2018/8/21. */ public class UpdateInfoTable extends JTable { + + public static int UPDATE_DATE_INDEX = 0; + public static int UPDATE_VERSION_INDEX = 1; + public static int UPDATE_TITLE_INDEX = 2; + public static int SIGN_INDEX = 3; + private UpdateInfoTableModel dataModel; public UpdateInfoTable(TableModel dm) { diff --git a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java index 9a853762e8..21998babad 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java @@ -18,11 +18,11 @@ public class UpdateInfoTableCellRender extends DefaultTableCellRenderer { 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)) { + if ((Boolean) table.getValueAt(row, UpdateInfoTable.SIGN_INDEX)) { cell.setBackground(new Color(0xdfecfd)); } - if (column == 0) { - //设置首列日期居中显示 + if (column == UpdateInfoTable.UPDATE_DATE_INDEX || column == UpdateInfoTable.UPDATE_VERSION_INDEX) { + //设置日期,版本居中显示 setHorizontalAlignment(JLabel.CENTER); for (int i = 1; row - i >= 0; i++) { diff --git a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java index 4f9836d4c4..93edd98392 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java @@ -35,9 +35,9 @@ public class UpdateInfoTextAreaCellRender extends JTextArea implements TableCell setText(value == null ? "" : value.toString()); setBackground((row & 1) != 0 ? new Color(0xf0f0f0) : Color.WHITE); - if ((Boolean) table.getValueAt(row, 2)) { + if ((Boolean) table.getValueAt(row, UpdateInfoTable.SIGN_INDEX)) { setBackground(new Color(0xdfecfd)); } return this; } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java b/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java index f9fb484a6a..67fb918666 100644 --- a/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java @@ -24,18 +24,16 @@ import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.os.OperatingSystem; import com.fr.start.ServerStarter; +import com.fr.start.common.DesignerStartupContext; +import com.fr.startup.ui.StartupPageModel; import com.fr.value.NotNullLazyValue; import com.fr.workspace.WorkContext; import org.jetbrains.annotations.NotNull; import javax.swing.SwingUtilities; import javax.swing.UIManager; -import java.awt.Color; import java.awt.Desktop; import java.awt.Font; -import java.awt.Frame; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -50,6 +48,7 @@ import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.Locale; +import java.util.Optional; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -216,6 +215,28 @@ public class DesignUtils { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { + DesignerStartupContext context = DesignerStartupContext.getInstance(); + // 如果在启动页展示中 + if (context.isOnWaiting()) { + FileFILE fileFILE = new FileFILE(f); + // 设置上一次启动模板为 + DesignerEnvManager.getEnvManager().setLastOpenFile(fileFILE.getPath()); + StartupPageModel model = context.getStartupPageModel(); + Optional.ofNullable(model) + .ifPresent((e) -> { + // 执行上一次模板的启动 + Runnable openLastTemplateRunnable = e.getOpenLastTemplateRunnable(); + openLastTemplateRunnable.run(); + }); + return; + } + // 如果是在启动中 + if (context.isOnStartup()) { + // 之前就有这样的问题 + return; + } + + // 打开模板 DesignerContext.getDesignerFrame().openTemplate(new FileFILE(f)); } }); diff --git a/designer-base/src/main/java/com/fr/design/widget/component/CheckBoxDictPane.java b/designer-base/src/main/java/com/fr/design/widget/component/ReturnTypePane.java similarity index 50% rename from designer-base/src/main/java/com/fr/design/widget/component/CheckBoxDictPane.java rename to designer-base/src/main/java/com/fr/design/widget/component/ReturnTypePane.java index 9a76352f94..4f3b93a539 100644 --- a/designer-base/src/main/java/com/fr/design/widget/component/CheckBoxDictPane.java +++ b/designer-base/src/main/java/com/fr/design/widget/component/ReturnTypePane.java @@ -1,32 +1,29 @@ package com.fr.design.widget.component; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - import com.fr.design.designer.IntervalConstants; import com.fr.design.gui.ibutton.UIButtonGroup; -import com.fr.design.gui.ilable.UILabel; - -import javax.swing.*; - import com.fr.design.gui.icombobox.DictionaryComboBox; import com.fr.design.gui.icombobox.DictionaryConstants; +import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; -import com.fr.form.ui.CheckBoxGroup; -import com.fr.form.ui.ComboCheckBox; +import com.fr.form.ui.ReturnTypeProvider; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; + +public class ReturnTypePane extends JPanel { -public class CheckBoxDictPane extends JPanel { - - private DictionaryComboBox delimiterComboBox; - private UIButtonGroup returnTypeComboBox; - private DictionaryComboBox startComboBox; - private DictionaryComboBox endComboBox; - private JPanel returnStringPane; - - public CheckBoxDictPane() { + private final DictionaryComboBox delimiterComboBox; + private final UIButtonGroup returnTypeComboBox; + private final DictionaryComboBox startComboBox; + private final DictionaryComboBox endComboBox; + private final JPanel returnStringPane; + + public ReturnTypePane() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); delimiterComboBox = new DictionaryComboBox(DictionaryConstants.delimiters, DictionaryConstants.delimiterDisplays); delimiterComboBox.setEditable(true); @@ -36,18 +33,13 @@ public class CheckBoxDictPane extends JPanel { endComboBox.setEditable(true); Component[][] components = new Component[][]{ new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Delimiter")), delimiterComboBox}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_Start_Symbol")),startComboBox}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_End_Symbol")),endComboBox} + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_Start_Symbol")), startComboBox}, + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_End_Symbol")), endComboBox} }; returnStringPane = TableLayoutHelper.createGapTableLayoutPane(components, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W2, IntervalConstants.INTERVAL_L1); returnTypeComboBox = new UIButtonGroup(new String[]{com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Array"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_String")}); - returnTypeComboBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - checkVisible(returnTypeComboBox.getSelectedIndex()); - } - }); + returnTypeComboBox.addActionListener(e -> checkVisible(returnTypeComboBox.getSelectedIndex())); JPanel headPane = TableLayoutHelper.createGapTableLayoutPane( new Component[][]{new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Date_Selector_Return_Type")), returnTypeComboBox}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L2, IntervalConstants.INTERVAL_L1); JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); @@ -57,34 +49,33 @@ public class CheckBoxDictPane extends JPanel { this.add(jPanel); } - public void checkVisible(int selectIndex){ - returnStringPane.setVisible(selectIndex == 1); + public void setReturnType(ReturnType returnType) { + int selectIndex = returnType == ReturnType.ARRAY ? 0 : 1; + returnTypeComboBox.setSelectedIndex(selectIndex,true); + checkVisible(selectIndex); } - public void populate(ComboCheckBox comboCheckBox) { - this.delimiterComboBox.setSelectedItem(comboCheckBox.getDelimiter()); - this.returnTypeComboBox.setSelectedIndex(comboCheckBox.isReturnString() ? 1 : 0); - this.startComboBox.setSelectedItem(comboCheckBox.getStartSymbol()); - this.endComboBox.setSelectedItem(comboCheckBox.getEndSymbol()); - checkVisible(this.returnTypeComboBox.getSelectedIndex()); + public void checkVisible(int selectIndex) { + returnStringPane.setVisible(selectIndex == 1); } - public void update(ComboCheckBox comboCheckBox) { - comboCheckBox.setDelimiter((String)this.delimiterComboBox.getSelectedItem()); - comboCheckBox.setReturnString(this.returnTypeComboBox.getSelectedIndex() != 0); - comboCheckBox.setStartSymbol((String)this.startComboBox.getSelectedItem()); - comboCheckBox.setEndSymbol((String)this.endComboBox.getSelectedItem()); + + public void update(ReturnTypeProvider returnTypeProvider) { + returnTypeProvider.setDelimiter((String) this.delimiterComboBox.getSelectedItem()); + returnTypeProvider.setReturnString(this.returnTypeComboBox.getSelectedIndex() != 0); + returnTypeProvider.setStartSymbol((String) this.startComboBox.getSelectedItem()); + returnTypeProvider.setEndSymbol((String) this.endComboBox.getSelectedItem()); } - public void populate(CheckBoxGroup checkBoxGroup) { - this.delimiterComboBox.setSelectedItem(checkBoxGroup.getDelimiter()); - this.returnTypeComboBox.setSelectedIndex(checkBoxGroup.isReturnString() ? 1 : 0); - this.startComboBox.setSelectedItem(checkBoxGroup.getStartSymbol()); - this.endComboBox.setSelectedItem(checkBoxGroup.getEndSymbol()); + + public void populate(ReturnTypeProvider returnTypeProvider) { + this.delimiterComboBox.setSelectedItem(returnTypeProvider.getDelimiter()); + this.returnTypeComboBox.setSelectedIndex(returnTypeProvider.isReturnString() ? 1 : 0); + this.startComboBox.setSelectedItem(returnTypeProvider.getStartSymbol()); + this.endComboBox.setSelectedItem(returnTypeProvider.getEndSymbol()); checkVisible(this.returnTypeComboBox.getSelectedIndex()); } - public void update(CheckBoxGroup checkBoxGroup) { - checkBoxGroup.setDelimiter((String)this.delimiterComboBox.getSelectedItem()); - checkBoxGroup.setReturnString(this.returnTypeComboBox.getSelectedIndex() != 0); - checkBoxGroup.setStartSymbol((String)this.startComboBox.getSelectedItem()); - checkBoxGroup.setEndSymbol((String)this.endComboBox.getSelectedItem()); + + public enum ReturnType { + STRING, + ARRAY } } diff --git a/designer-base/src/main/java/com/fr/start/BaseDesigner.java b/designer-base/src/main/java/com/fr/start/BaseDesigner.java index 97355c8fea..89c928e2c4 100644 --- a/designer-base/src/main/java/com/fr/start/BaseDesigner.java +++ b/designer-base/src/main/java/com/fr/start/BaseDesigner.java @@ -3,7 +3,6 @@ */ package com.fr.start; -import com.fr.base.extension.FileExtension; import com.fr.common.report.ReportState; import com.fr.design.DesignerEnvManager; import com.fr.design.ExtraDesignClassManager; @@ -15,6 +14,7 @@ import com.fr.design.fun.DesignerStartOpenFileProcessor; import com.fr.design.fun.impl.DesignerStartWithEmptyFile; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.toolbar.ToolBarMenuDock; import com.fr.design.monitor.DesignerLifecycleMonitorContext; import com.fr.design.ui.util.UIUtil; @@ -26,18 +26,17 @@ import com.fr.event.Null; import com.fr.exit.DesignerExiter; import com.fr.file.FILE; import com.fr.file.FILEFactory; -import com.fr.file.FileFILE; -import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.process.ProcessEventPipe; import com.fr.process.engine.core.CarryMessageEvent; import com.fr.process.engine.core.FineProcessContext; import com.fr.stable.OperatingSystem; +import com.fr.start.common.DesignerStartupContext; +import com.fr.start.common.DesignerStartupUtil; import com.fr.start.event.LazyStartupEvent; import com.fr.workspace.base.WorkspaceStatus; import java.awt.Window; -import java.io.File; import java.lang.reflect.Method; /** @@ -124,24 +123,14 @@ public abstract class BaseDesigner extends ToolBarMenuDock { try { FILE file = null; if (args != null && args.length > 0) { - // p:需要打开这个报表文件,这个代码不能删除. - for (String arg : args) { - if (ComparatorUtils.equals("demo", arg)) { - file = FILEFactory.createFILE(FILEFactory.ENV_PREFIX + DesignerEnvManager.getEnvManager().getLastOpenFile()); - break; - } - File f = new File(arg); - String path = f.getAbsolutePath(); - if (isAcceptFilePathEnd(path)) { - file = new FileFILE(f); - } - } + file = DesignerStartupUtil.convertArgs2FILE(args); } else { file = FILEFactory.createFILE(FILEFactory.ENV_PREFIX + DesignerEnvManager.getEnvManager().getLastOpenFile()); } DesignerFrame df = DesignerContext.getDesignerFrame(); isException = openFile(df, isException, file); df.fireDesignerOpened(); + FineLoggerFactory.getLogger().debug("show designer cost {} ms", DesignerStartupContext.getRecorder().getTime()); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); if (!isException) { @@ -152,21 +141,6 @@ public abstract class BaseDesigner extends ToolBarMenuDock { } } - private boolean isAcceptFilePathEnd(String path) { - FileExtension[] acceptFileExtensions = new FileExtension[]{ - FileExtension.CPT, FileExtension.XLS, FileExtension.XLSX, FileExtension.FRM, FileExtension.CHT, FileExtension.VIS - }; - for (FileExtension acceptFileExtension : acceptFileExtensions) { - String[] extensions = acceptFileExtension.getExtensions(); - for (String extension : extensions) { - if (path.endsWith("." + extension)) { - return true; - } - } - } - return false; - } - private boolean openFile(final DesignerFrame df, boolean isException, FILE file) { //启动时打开指定文件的接口 @@ -183,19 +157,52 @@ public abstract class BaseDesigner extends ToolBarMenuDock { isException = true;//此时有文件nullpointer异常,执行打开空文件 } } + + openTemplate(df, isException, file); + + if (OperatingSystem.isMacOS()) { + enableFullScreenMode(df); + } + + JTemplate selectedJTemplate = df.getSelectedJTemplate(); + if (selectedJTemplate != null) { + selectedJTemplate.requestGridFocus(); + } + return isException; + } + + private void openTemplate(DesignerFrame df, boolean isException, FILE file) { + + boolean onStartup = DesignerStartupContext.getInstance().isSupport(); + if (onStartup) { + DesignerStartupContext context = DesignerStartupContext.getInstance(); + if (context.isCreateNew()) { + df.addAndActivateJTemplate(); + // 如果没有模板,则需要确认一下 + MutilTempalteTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); + return; + } + if (context.isOpenLastFile()) { + if (file != null && file.exists() && !isException) { + df.openTemplate(file); + return; + } + } + if (context.isOpenEmpty()) { + df.showEmptyJTemplate(); + return; + } + } + if (file != null && file.exists() && !isException) { df.openTemplate(file); } else { df.addAndActivateJTemplate(); + // 如果没有模板,则需要确认一下 MutilTempalteTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); } - if (OperatingSystem.isMacOS()) { - enableFullScreenMode(df); - } - df.getSelectedJTemplate().requestGridFocus(); - return isException; } - + private void enableFullScreenMode(Window window) { String className = "com.apple.eawt.FullScreenUtilities"; String methodName = "setWindowCanFullScreen"; diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java b/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java new file mode 100644 index 0000000000..e89598ae27 --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java @@ -0,0 +1,77 @@ +package com.fr.start.common; + +import com.fr.base.svg.IconUtils; +import com.fr.design.file.HistoryTemplateListPane; +import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.DesignSizeI18nManager; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.utils.ColorUtils; + +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * created by Harrison on 2022/07/09 + **/ +public class DesignerOpenEmptyPanel extends JPanel { + + private static final Color BUTTON_COLOR = new Color(63, 155, 249); + private static final int ARC = 4; + + private final JPanel body; + + public DesignerOpenEmptyPanel() { + + this.body = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + UILabel createIcon = new UILabel(IconUtils.readIcon("/com/fr/design/startup/create_new_template.svg")); + JButton createButton = new JButton(Toolkit.i18nText("Fine-Design_New_Template")) { + @Override + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setColor(BUTTON_COLOR); + g2d.fillRoundRect(0, 0, getWidth(), getHeight(), ARC, ARC); + super.paintComponent(g2d); + } + }; + createButton.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.start.common.DesignerOpenEmptyPanel.createButton")); + createButton.setForeground(Color.WHITE); + createButton.setBorderPainted(false); + createButton.setContentAreaFilled(false); + createButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DesignerFrame df = DesignerContext.getDesignerFrame(); + df.addAndActivateJTemplate(); + // 如果没有模板,则需要确认一下 + MutilTempalteTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); + } + }); + createButton.setBorder(new EmptyBorder(0, 10, 0, 10)); + JPanel createButtonPanel = new JPanel(FRGUIPaneFactory.createCenterFlowLayout()); + createButtonPanel.add(createButton); + createButtonPanel.setBorder(new EmptyBorder(0, 0, 0, 0)); + createButtonPanel.setBackground(Color.WHITE); + this.body.add(createIcon, BorderLayout.NORTH); + this.body.add(createButtonPanel, BorderLayout.SOUTH); + + setLayout(FRGUIPaneFactory.createCenterLayout(this.body)); + + ColorUtils.syncBackground(this, Color.WHITE); + + add(this.body); + } +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java new file mode 100644 index 0000000000..5aae98f03e --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java @@ -0,0 +1,55 @@ +package com.fr.start.common; + +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLable; +import com.fr.stable.xml.XMLableReader; + +public class DesignerStartupConfig implements XMLable { + + public static final String XML_TAG = "DesignerStartupConfig"; + + private static final long serialVersionUID = -8170289826729582122L; + + private static final DesignerStartupConfig INSTANCE = new DesignerStartupConfig(); + + public static DesignerStartupConfig getInstance() { + + return INSTANCE; + } + + /** + * 默认值是 false + */ + private boolean enabled = false; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + + @Override + public Object clone() throws CloneNotSupportedException { + DesignerStartupConfig config = new DesignerStartupConfig(); + config.setEnabled(true); + return config; + } + + @Override + public void readXML(XMLableReader reader) { + if (reader.isAttr()) { + this.setEnabled(reader.getAttrAsBoolean("isEnabled", false)); + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(XML_TAG); + writer.attr("isEnabled", this.isEnabled()); + writer.end(); + } + +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java new file mode 100644 index 0000000000..b996fbe4b7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java @@ -0,0 +1,176 @@ +package com.fr.start.common; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.env.DesignerWorkspaceType; +import com.fr.start.module.StartupArgs; +import com.fr.startup.ui.StartupPageModel; +import com.fr.third.guava.collect.Lists; +import com.fr.third.org.apache.commons.lang3.time.StopWatch; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * 启动页上下文 + * + * created by Harrison on 2022/06/22 + **/ +public class DesignerStartupContext { + + /** + * 启动参数 + */ + private StartupArgs startupArgs; + + /** + * 启动数据 + */ + private StartupPageModel startupPageModel; + + /** + * 是否在起始页打开的等待过程中 + */ + private boolean onWaiting = false; + + /** + * 是否在启动中 + */ + private boolean onStartup = true; + + /** + * 是否在预热中 + */ + private boolean onWarmup = false; + + /** + * 打开上一次的文件 + */ + private boolean openLastFile; + + /** + * 打开空设计器 + */ + private boolean openEmpty; + + /** + * 直接创建一个新模板 + */ + private boolean createNew; + + /** + * 时间记录 + */ + private static StopWatch STOP_WATCH = new StopWatch(); + + public static DesignerStartupContext getInstance() { + return StartupContextHolder.INSTANCE; + } + + private static class StartupContextHolder { + private static final DesignerStartupContext INSTANCE = new DesignerStartupContext(); + } + + public static StopWatch getRecorder() { + return STOP_WATCH; + } + + /* 启动模式 */ + + /** + * 展示启动页 + * 1. 判断当前的工作目录数量 + * 2. 判断是否是 demo、还是打开目标文件 + * 3. 功能是否开启 + * + * @return 是/否 + */ + public boolean isShowStartupPage() { + + DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); + Iterator envNameIterator = envManager.getEnvNameIterator(); + ArrayList envs = Lists.newArrayList(envNameIterator); + return !startupArgs.isDemo() && DesignerStartupUtil.convertArgs2FILE(startupArgs.get()) == null && !envs.isEmpty() && envManager.isStartupPageEnabled(); + } + + /* 预热相关 */ + + public boolean onWarmup() { + + return this.onWarmup; + } + + public boolean canWarmup() { + + String curEnvName = DesignerEnvManager.getEnvManager().getCurEnvName(); + DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(curEnvName); + return workspaceInfo.getType() == DesignerWorkspaceType.Local; + } + + public void setStartupPageModel(StartupPageModel startupPageModel) { + this.startupPageModel = startupPageModel; + } + + public StartupPageModel getStartupPageModel() { + + return startupPageModel; + } + + public boolean isOnWaiting() { + return onWaiting; + } + + public void setOnWaiting(boolean onWaiting) { + this.onWaiting = onWaiting; + } + + public boolean isSupport() { + return onStartup && isShowStartupPage(); + } + + public boolean isOnStartup() { + return onStartup; + } + + public void setOnStartup(boolean onStartup) { + this.onStartup = onStartup; + } + + /* 文件相关*/ + + public boolean isOpenLastFile() { + + return this.openLastFile; + } + + public boolean isOpenEmpty() { + + return this.openEmpty; + } + + /* set */ + + public void setOnWarmup(boolean onWarmup) { + this.onWarmup = onWarmup; + } + + public void setOpenLastFile(boolean openLastFile) { + this.openLastFile = openLastFile; + } + + public void setOpenEmpty(boolean openEmpty) { + this.openEmpty = openEmpty; + } + + public boolean isCreateNew() { + return createNew; + } + + public void setCreateNew(boolean createNew) { + this.createNew = createNew; + } + + public void setStartupArgs(StartupArgs startupArgs) { + this.startupArgs = startupArgs; + } +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupExecutor.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupExecutor.java new file mode 100644 index 0000000000..1a033e8cd2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupExecutor.java @@ -0,0 +1,32 @@ +package com.fr.start.common; + +import java.util.ArrayList; +import java.util.List; + +/** + * created by Harrison on 2022/07/03 + **/ +public class DesignerStartupExecutor { + + private List warmupTasks = new ArrayList<>(); + + public void execute(Runnable runnable) { + + if (!DesignerStartupContext.getInstance().onWarmup()) { + runnable.run(); + } + } + + public void reset() { + + warmupTasks.clear(); + } + + public static DesignerStartupExecutor getInstance() { + return DesignerStartupExecutorHolder.INSTANCE; + } + + private static class DesignerStartupExecutorHolder { + private static final DesignerStartupExecutor INSTANCE = new DesignerStartupExecutor(); + } +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupPool.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupPool.java new file mode 100644 index 0000000000..524c474df1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupPool.java @@ -0,0 +1,20 @@ +package com.fr.start.common; + +import com.fr.concurrent.FineExecutors; +import com.fr.concurrent.NamedThreadFactory; + +import java.util.concurrent.Executor; + +/** + * created by Harrison on 2022/07/03 + **/ +public class DesignerStartupPool { + + private static final Executor COMMON_EXECUTOR = FineExecutors.newCachedThreadPool(new NamedThreadFactory("startup-common")); + + public static Executor common() { + + return COMMON_EXECUTOR; + } + +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupUtil.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupUtil.java new file mode 100644 index 0000000000..5bc55e80c5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupUtil.java @@ -0,0 +1,51 @@ +package com.fr.start.common; + +import com.fr.base.extension.FileExtension; +import com.fr.design.DesignerEnvManager; +import com.fr.file.FILE; +import com.fr.file.FILEFactory; +import com.fr.file.FileFILE; +import com.fr.general.ComparatorUtils; +import org.jetbrains.annotations.Nullable; + +import java.io.File; + +/** + * created by Harrison on 2022/07/09 + **/ +public class DesignerStartupUtil { + + @Nullable + public static FILE convertArgs2FILE(String[] args) { + + // p:需要打开这个报表文件,这个代码不能删除. + FILE file = null; + for (String arg : args) { + if (ComparatorUtils.equals("demo", arg)) { + file = FILEFactory.createFILE(FILEFactory.ENV_PREFIX + DesignerEnvManager.getEnvManager().getLastOpenFile()); + break; + } + File f = new File(arg); + String path = f.getAbsolutePath(); + if (isAcceptFilePathEnd(path)) { + file = new FileFILE(f); + } + } + return file; + } + + private static boolean isAcceptFilePathEnd(String path) { + FileExtension[] acceptFileExtensions = new FileExtension[]{ + FileExtension.CPT, FileExtension.XLS, FileExtension.XLSX, FileExtension.FRM, FileExtension.CHT, FileExtension.VIS + }; + for (FileExtension acceptFileExtension : acceptFileExtensions) { + String[] extensions = acceptFileExtension.getExtensions(); + for (String extension : extensions) { + if (path.endsWith("." + extension)) { + return true; + } + } + } + return false; + } +} diff --git a/designer-realize/src/main/java/com/fr/start/module/StartupArgs.java b/designer-base/src/main/java/com/fr/start/module/StartupArgs.java similarity index 100% rename from designer-realize/src/main/java/com/fr/start/module/StartupArgs.java rename to designer-base/src/main/java/com/fr/start/module/StartupArgs.java diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageConstants.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageConstants.java new file mode 100644 index 0000000000..ae27e1a9ef --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageConstants.java @@ -0,0 +1,17 @@ +package com.fr.startup.ui; + +/** + * created by Harrison on 2022/07/07 + **/ +public class StartupPageConstants { + + /** + * 圆弧长度 + */ + public static final int ARC_DIAMETER = 20; + + /** + * 内容宽度 + */ + public static final int CONTENT_WIDTH = 850; +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageModel.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageModel.java new file mode 100644 index 0000000000..4b82545a01 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageModel.java @@ -0,0 +1,111 @@ +package com.fr.startup.ui; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.env.DesignerWorkspaceType; +import com.fr.third.guava.collect.Lists; +import com.fr.workspace.connect.WorkspaceConnectionInfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * created by Harrison on 2022/07/06 + **/ +public class StartupPageModel { + + private StartupWorkspaceBean selectWorkspaceInfo; + + private List workspaceInfos = new ArrayList<>(); + + private Map> recentFilesMap = new HashMap<>(); + + private Runnable openLastTemplateRunnable; + + private Runnable createNewTemplateRunnable; + + private Runnable openEmptyTemplateRunnable; + + public static StartupPageModel create() { + + DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); + Iterator envNameIterator = envManager.getEnvNameIterator(); + List infos = Lists.newArrayList(envNameIterator) + .stream() + .map((e) -> { + DesignerWorkspaceInfo workspaceInfo = envManager.getWorkspaceInfo(e); + if (workspaceInfo.getType() == DesignerWorkspaceType.Remote) { + WorkspaceConnectionInfo connection = workspaceInfo.getConnection(); + return new StartupWorkspaceBean(e, connection.getUrl(), workspaceInfo.getType()); + } else { + return new StartupWorkspaceBean(e, workspaceInfo.getPath(), workspaceInfo.getType()); + } + }) + .collect(Collectors.toList()); + Map> recentFileMap = new HashMap<>(); + for (StartupWorkspaceBean info : infos) { + String name = info.getName(); + List recentFiles = envManager.getRecentOpenedFilePathList4Env(name); + recentFileMap.put(name, recentFiles); + } + return new StartupPageModel(infos, recentFileMap); + } + + public StartupPageModel(List workspaceInfos, Map> recentFilesMap) { + this.selectWorkspaceInfo = workspaceInfos.get(0); + this.workspaceInfos = workspaceInfos; + this.recentFilesMap = recentFilesMap; + } + + public StartupWorkspaceBean getSelectWorkspaceInfo() { + return selectWorkspaceInfo; + } + + public void setSelectWorkspaceInfo(StartupWorkspaceBean selectWorkspaceInfo) { + this.selectWorkspaceInfo = selectWorkspaceInfo; + } + + public List getWorkspaceInfos() { + return workspaceInfos; + } + + public void setWorkspaceInfos(List workspaceInfos) { + this.workspaceInfos = workspaceInfos; + } + + public Map> getRecentFilesMap() { + return recentFilesMap; + } + + public void setRecentFilesMap(Map> recentFilesMap) { + this.recentFilesMap = recentFilesMap; + } + + public Runnable getOpenLastTemplateRunnable() { + return openLastTemplateRunnable; + } + + public void setOpenLastTemplateRunnable(Runnable openLastTemplateRunnable) { + this.openLastTemplateRunnable = openLastTemplateRunnable; + } + + public Runnable getCreateNewTemplateRunnable() { + return createNewTemplateRunnable; + } + + public void setCreateNewTemplateRunnable(Runnable createNewTemplateRunnable) { + this.createNewTemplateRunnable = createNewTemplateRunnable; + } + + public Runnable getOpenEmptyTemplateRunnable() { + return openEmptyTemplateRunnable; + } + + public void setOpenEmptyTemplateRunnable(Runnable openEmptyTemplateRunnable) { + this.openEmptyTemplateRunnable = openEmptyTemplateRunnable; + } +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageUtil.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageUtil.java new file mode 100644 index 0000000000..896b425957 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageUtil.java @@ -0,0 +1,40 @@ +package com.fr.startup.ui; + +import com.fr.base.svg.SVGIcon; +import com.fr.design.env.DesignerWorkspaceType; + +import javax.swing.Icon; + +/** + * created by Harrison on 2022/07/11 + **/ +public class StartupPageUtil { + + /** + * 获取最近区域的 ICON + * + * @param workspaceBean 工作目录 + * @return 图标 + */ + public static Icon getIcon4RecentAreaByWorkspace(StartupWorkspaceBean workspaceBean) { + + if (workspaceBean.getType() == DesignerWorkspaceType.Local) { + return SVGIcon.readSVGIcon("/com/fr/design/startup/local_server_background_36.svg", 36, 36); + } + return SVGIcon.readSVGIcon("/com/fr/design/startup/remote_server_background_36.svg", 36, 36); + } + + /** + * 获取工作目录描述区域的 ICON + * + * @param workspaceBean 工作目录 + * @return 图标 + */ + public static Icon getIcon4DescAreaByWorkspace(StartupWorkspaceBean workspaceBean) { + + if (workspaceBean.getType() == DesignerWorkspaceType.Local) { + return SVGIcon.readSVGIcon("/com/fr/design/startup/local_server_background_28.svg", 28, 28); + } + return SVGIcon.readSVGIcon("/com/fr/design/startup/remote_server_background_28.svg", 28, 28); + } +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java new file mode 100644 index 0000000000..fefe6e8eca --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java @@ -0,0 +1,339 @@ +package com.fr.startup.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.DesignerEnvManager; +import com.fr.design.components.loading.LoadingPane; +import com.fr.design.dialog.UIExpandDialog; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.ui.util.UIUtil; +import com.fr.design.utils.ColorUtils; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.collections.CollectionUtils; +import org.jetbrains.annotations.NotNull; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; +import javax.swing.SwingWorker; +import javax.swing.border.EmptyBorder; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.LayoutManager; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; +import java.util.Map; + +/** + * 启动页 + * 见设计文档 + *

+ * created by Harrison on 2022/07/06 + **/ +public class StartupPageWindow extends JFrame { + + private static final int CONTENT_LAYER = 0; + private static final int TRANSPARENT_LAYER = 1; + + private static final Color HOVER_COLOR = new Color(65, 155, 249); + private static final Color SEP_COLOR = new Color(224, 224, 225); + + private static final int GROUP_WIDTH = 600; + private static final int RECENT_FILE_LIMIT = 6; + private static final int RECENT_FILE_SCROLL = RECENT_FILE_LIMIT + 1; + private static final int WORKSPACE_PANEL_WIDTH = 180; + private static final int TITLE_FONT_SIZE = 24; + private static final int ITEM_VERTICAL_GAP = 5; + + private static final Dimension SCREEN_SIZE = new Dimension(1600, 820); + + private StartupPageWorkspacePanel workspacePanel; + + private JPanel recentOpenPanel; + + private JPanel contentPane; + + private JPanel body; + + private LoadingPane loadingPane = new LoadingPane(); + + private JLayeredPane layeredPane = new JLayeredPane() { + @Override + public void doLayout() { + for (Component comp : getComponents()) { + comp.setBounds(0, 0, getWidth(), getHeight()); + } + } + }; + + public StartupPageWindow(StartupPageModel pageModel) { + + patchUIAction(pageModel); + + setLayout(new BorderLayout()); + + this.body = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // Header + UILabel label = new UILabel(Toolkit.i18nText("Fine-Design_Startup_Page_Select_Workspace")); + Font font = label.getFont(); + Font titleFont = font.deriveFont(font.getStyle(), TITLE_FONT_SIZE); + label.setFont(titleFont); + JPanel headerPanel = new JPanel(); + LayoutManager centerFlowLayout = FRGUIPaneFactory.createCenterFlowLayout(); + headerPanel.setLayout(centerFlowLayout); + headerPanel.add(label); + this.body.add(headerPanel, BorderLayout.NORTH); + + // Workspace-description + this.workspacePanel = generateWorkspacePanel(pageModel); + this.body.add(workspacePanel, BorderLayout.CENTER); + + workspacePanel.setSelectWorkspaceRunnable(new Runnable() { + @Override + public void run() { + JPanel newPanel = generateRecentOpenPanel(pageModel); + + body.remove(recentOpenPanel); + recentOpenPanel = newPanel; + body.add(recentOpenPanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + }); + + this.recentOpenPanel = generateRecentOpenPanel(pageModel); + this.body.add(recentOpenPanel, BorderLayout.SOUTH); + this.contentPane = new JPanel(); + this.contentPane.setLayout(getCenterLayout(body)); + this.contentPane.add(this.body, BorderLayout.CENTER); + this.contentPane.setPreferredSize(this.body.getPreferredSize()); + + this.layeredPane.setName("layered-pane"); + this.layeredPane.add(this.contentPane, CONTENT_LAYER); + this.layeredPane.add(this.loadingPane, TRANSPARENT_LAYER); + this.layeredPane.moveToFront(this.contentPane); + + add(this.layeredPane, BorderLayout.CENTER); + + // Workspace-detail + setSize(SCREEN_SIZE); + + repaint(); + validate(); + revalidate(); + + GUICoreUtils.centerWindow(this); + } + + private void patchUIAction(StartupPageModel pageModel) { + + Runnable selectAndOpenLastTemplateRunnable = pageModel.getOpenLastTemplateRunnable(); + pageModel.setOpenLastTemplateRunnable(() -> { + enterWorkspace(selectAndOpenLastTemplateRunnable); + }); + + Runnable createNewTemplateRunnable = pageModel.getCreateNewTemplateRunnable(); + pageModel.setCreateNewTemplateRunnable(() -> { + enterWorkspace(createNewTemplateRunnable); + }); + + Runnable openEmptyTemplateRunnable = pageModel.getOpenEmptyTemplateRunnable(); + pageModel.setOpenEmptyTemplateRunnable(() -> { + enterWorkspace(openEmptyTemplateRunnable); + }); + } + + private void enterWorkspace(Runnable action) { + + loadingPane.start(); + layeredPane.moveToFront(loadingPane); + SwingWorker task = new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + action.run(); + return null; + } + + @Override + protected void done() { + + try { + Void result = get(); + setVisible(false); + } catch (Exception e) { + // 处理错误 + UIUtil.invokeLaterIfNeeded(() -> { + UIExpandDialog.Builder() + .owner(StartupPageWindow.this) + .title(Toolkit.i18nText("Fine-Design_Basic_Remote_Env_Try")) + .message(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed")) + .messageType(UIExpandDialog.WARNING_MESSAGE) + .detail(e.getMessage()) + .expand(true) + .modal(false) + .build() + .setVisible(true); + }); + FineLoggerFactory.getLogger().error(e.getMessage(), e); + layeredPane.moveToFront(contentPane); + } finally { + loadingPane.stop(); + } + } + }; + task.execute(); + } + + private JPanel generateRecentOpenPanel(StartupPageModel pageModel) { + + JPanel recentOpenPanel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setColor(Color.WHITE); + g2d.fillRoundRect(0, 0, getWidth(), getHeight(), StartupPageConstants.ARC_DIAMETER, StartupPageConstants.ARC_DIAMETER); + } + }; + recentOpenPanel.setLayout(new BorderLayout()); + recentOpenPanel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 6)); + + StartupWorkspaceBean workspaceInfo = pageModel.getSelectWorkspaceInfo(); + JPanel workspaceWrapperYPanel = new JPanel(); + workspaceWrapperYPanel.setName("workspace-wrapper"); + { + workspaceWrapperYPanel.setLayout(new VerticalFlowLayout()); + + JPanel workspaceWrapperXPanel = new JPanel(); + workspaceWrapperXPanel.setLayout(new FlowLayout()); + workspaceWrapperXPanel.setBorder(BorderFactory.createEmptyBorder()); + + JPanel workspacePanel = new JPanel(); + workspacePanel.setLayout(new BorderLayout(0, 15)); + + UILabel workspaceIcon = new UILabel(StartupPageUtil.getIcon4RecentAreaByWorkspace(workspaceInfo)); + workspacePanel.add(workspaceIcon, BorderLayout.NORTH); + + UILabel nameLabel = new UILabel(workspaceInfo.getName()); + nameLabel.setHorizontalAlignment(SwingConstants.CENTER); + workspacePanel.add(nameLabel, BorderLayout.SOUTH); + workspaceWrapperXPanel.add(workspacePanel); + Dimension preferredSize = workspaceWrapperXPanel.getPreferredSize(); + workspaceWrapperXPanel.setPreferredSize(new Dimension(WORKSPACE_PANEL_WIDTH, (int) preferredSize.getHeight())); + + workspaceWrapperYPanel.add(workspaceWrapperXPanel); + } + recentOpenPanel.add(workspaceWrapperYPanel, BorderLayout.WEST); + + JPanel separatorPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + { + JSeparator sep = new JSeparator(); + sep.setOrientation(JSeparator.VERTICAL); + sep.setForeground(SEP_COLOR); + separatorPanel.add(sep, BorderLayout.CENTER); + } + recentOpenPanel.add(separatorPanel, BorderLayout.CENTER); + + JComponent recentOpenGroupPanel = generateRecentOpenGroupPanel(pageModel, workspaceInfo); + recentOpenPanel.add(recentOpenGroupPanel, BorderLayout.EAST); + + ColorUtils.syncBackground(recentOpenPanel, Color.WHITE); + + Dimension preferredSize = recentOpenPanel.getPreferredSize(); + recentOpenPanel.setPreferredSize(new Dimension(StartupPageConstants.CONTENT_WIDTH, (int) preferredSize.getHeight())); + + JPanel recentOpenWrapperPanel = new JPanel(); + recentOpenWrapperPanel.setName("recentOpenWrapper"); + recentOpenWrapperPanel.setLayout(new BorderLayout(0, 0)); + recentOpenWrapperPanel.setBorder(new EmptyBorder(0, 0, 0, 20)); + recentOpenWrapperPanel.add(recentOpenPanel, BorderLayout.CENTER); + + return recentOpenWrapperPanel; + } + + @NotNull + private JComponent generateRecentOpenGroupPanel(StartupPageModel pageModel, StartupWorkspaceBean workspaceInfo) { + + JPanel recentOpenGroupPanel = new JPanel(); + Map> recentFilesMap = pageModel.getRecentFilesMap(); + + boolean needScroll = false; + double itemHeight = 0.0d; + if (!CollectionUtils.isEmpty(recentFilesMap)) { + String name = workspaceInfo.getName(); + List recentFiles = recentFilesMap.get(name); + if (!CollectionUtils.isEmpty(recentFiles)) { + recentOpenGroupPanel.setLayout(new GridLayout(recentFiles.size(), 1, 50, 5)); + needScroll = recentFiles.size() > RECENT_FILE_LIMIT; + for (String recentFile : recentFiles) { + JPanel recentItemPanel = new JPanel(); + recentItemPanel.setLayout(new FlowLayout(FlowLayout.LEFT, ITEM_VERTICAL_GAP, 0)); + recentItemPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/cpt.svg"))); + UILabel recentFileLabel = new UILabel(recentFile); + Color recentFileLabelForeground = recentFileLabel.getForeground(); + recentItemPanel.add(recentFileLabel); + recentItemPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + recentFileLabel.setForeground(HOVER_COLOR); + } + + @Override + public void mouseExited(MouseEvent e) { + recentFileLabel.setForeground(recentFileLabelForeground); + } + + @Override + public void mouseClicked(MouseEvent e) { + DesignerEnvManager.getEnvManager().setLastOpenFile(recentFile); + pageModel.getOpenLastTemplateRunnable().run(); + } + }); + Dimension preferredSize = recentItemPanel.getPreferredSize(); + itemHeight = preferredSize.getHeight(); + recentOpenGroupPanel.add(recentItemPanel); + } + } + } + Dimension preferredSize = recentOpenGroupPanel.getPreferredSize(); + recentOpenGroupPanel.setPreferredSize(new Dimension(GROUP_WIDTH, (int) preferredSize.getHeight())); + + if (needScroll) { + int scrollHeight = (int) Math.round(itemHeight * RECENT_FILE_LIMIT + ITEM_VERTICAL_GAP * (RECENT_FILE_SCROLL)); + UIScrollPane scrollPane = new UIScrollPane(recentOpenGroupPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0)); + scrollPane.setPreferredSize(new Dimension(GROUP_WIDTH, scrollHeight)); + return scrollPane; + } + return recentOpenGroupPanel; + } + + private StartupPageWorkspacePanel generateWorkspacePanel(StartupPageModel pageModel) { + + return new StartupPageWorkspacePanel(pageModel); + } + + protected LayoutManager getCenterLayout(JComponent centerBody) { + + return FRGUIPaneFactory.createCenterLayout(centerBody); + } + +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageWorkspacePanel.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWorkspacePanel.java new file mode 100644 index 0000000000..a22c32b03b --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWorkspacePanel.java @@ -0,0 +1,501 @@ +package com.fr.startup.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.components.tooltip.ModernToolTip; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.utils.ColorUtils; +import com.fr.third.guava.collect.Lists; +import org.jetbrains.annotations.NotNull; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JToolTip; +import javax.swing.ScrollPaneConstants; +import javax.swing.border.EmptyBorder; +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static com.fr.startup.ui.StartupPageConstants.ARC_DIAMETER; + +/** + * created by Harrison on 2022/07/06 + **/ +public class StartupPageWorkspacePanel extends JPanel { + + /* color */ + + private static final Color SHALLOW_WHITE_COLOR = new Color(248, 250, 254); + private static final Color HOVER_COLOR = new Color(65, 155, 249); + private static final Color PATH_COLOR = new Color(51, 51, 52, (int) Math.round(255 * 0.5)); + + /* 长度 */ + + private static final int SCROLL_BAR_WIDTH = 20; + + private static final int CONTENT_WIDTH = StartupPageConstants.CONTENT_WIDTH + SCROLL_BAR_WIDTH; + private static final int BORDER_THIN = 2; + + private static final int ITEM_VERTICAL_GAP = 20; + private static final int SINGLE_ITEM_HEIGHT = 72; + private static final int SCROLL_HEIGHT = SINGLE_ITEM_HEIGHT * 4 + ITEM_VERTICAL_GAP * 4; + + private static final int NAME_LABEL_SIZE = 15; + private static final int PATH_LABEL_SIZE = 10; + + private static final Dimension LABEL_DIMENSION = new Dimension(28, 28); + private static final Dimension PATH_DIMENSION = new Dimension(100, 20); + private static final Dimension SELECT_WORKSPACE_DIMENSION = new Dimension(210, 72); + private static final Dimension SELECT_CREATE_DIMENSION = new Dimension(60, 72); + public static final int COLUMN_LIMIT = 3; + + /* model */ + + private final StartupPageModel pageModel; + + private final List> partitions; + + private Runnable selectWorkspaceRunnable; + + private final Runnable createNewTemplateRunnable; + + private final Runnable openEmptyTemplateRunnable; + + private JComponent contentPanel; + + private JPanel tailPanel; + + private boolean showMore = true; + + public StartupPageWorkspacePanel(StartupPageModel pageModel) { + + this.setLayout(new BorderLayout(0, 0)); + + this.pageModel = pageModel; + + List workspaceInfos = pageModel.getWorkspaceInfos(); + this.partitions = Lists.partition(workspaceInfos, COLUMN_LIMIT); + + this.contentPanel = generateLimitContentPanel(partitions); + this.add(contentPanel, BorderLayout.NORTH); + + this.tailPanel = generateTailPanel(); + + this.createNewTemplateRunnable = pageModel.getCreateNewTemplateRunnable(); + this.openEmptyTemplateRunnable = pageModel.getOpenEmptyTemplateRunnable(); + + this.add(tailPanel, BorderLayout.SOUTH); + this.repaint(); + } + + public void showLessContent() { + + this.remove(this.contentPanel); + + this.contentPanel = generateLimitContentPanel(this.partitions); + this.add(contentPanel, BorderLayout.NORTH); + } + + public void showMoreContent() { + + this.remove(this.contentPanel); + + this.contentPanel = generateUnLimitContentPanel(this.partitions); + this.add(contentPanel, BorderLayout.NORTH); + } + + private JComponent generateUnLimitContentPanel(List> partitions) { + + JPanel workspaceDescPanel = new JPanel(); + workspaceDescPanel.setLayout(new GridLayout(partitions.size(), 1, 0, ITEM_VERTICAL_GAP)); + for (List partition : partitions) { + JPanel partitionPanel = generatePartitionPanel(partition); + workspaceDescPanel.add(partitionPanel); + } + boolean needScroll = partitions.size() > 4; + if (needScroll) { + // 滚动条 + UIScrollPane scrollPane = new UIScrollPane(workspaceDescPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setBorder(new EmptyBorder(10, 0, 0, 0)); + scrollPane.setPreferredSize(new Dimension(CONTENT_WIDTH, SCROLL_HEIGHT)); + return scrollPane; + } + return workspaceDescPanel; + } + + private JPanel generateLimitContentPanel(List> partitions) { + + JPanel workspaceDescPanel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEFT, 0, ITEM_VERTICAL_GAP); + int limit = 2; + for (int i = 0; i < partitions.size(); i++) { + if (i >= limit) { + break; + } + List partition = partitions.get(i); + + JPanel partitionPanel = generatePartitionPanel(partition); + workspaceDescPanel.add(partitionPanel); + } + return workspaceDescPanel; + } + + @NotNull + private JPanel generateTailPanel() { + + JPanel tailPanel = new JPanel(); + { + tailPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); + tailPanel.setBorder(new EmptyBorder(0, 0, 0, 20)); + JPanel showAllPanel = new JPanel(); + showAllPanel.setLayout(new BorderLayout(5, 0)); + showAllPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + + UILabel fontLabel = new UILabel(Toolkit.i18nText("Fine-Design_Startup_Page_Expand_All")); + fontLabel.setForeground(HOVER_COLOR); + showAllPanel.add(fontLabel, BorderLayout.WEST); + + UILabel iconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/startup/show_more.svg")); + showAllPanel.add(iconLabel, BorderLayout.EAST); + + Color showAllBackground = showAllPanel.getBackground(); + + showAllPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + Color hoverColor = new Color(217, 235, 254); + showAllPanel.setBackground(hoverColor); + } + + @Override + public void mouseExited(MouseEvent e) { + ColorUtils.syncBackground(showAllPanel, showAllBackground); + } + + @Override + public void mousePressed(MouseEvent e) { + if (showMore) { + fontLabel.setText(Toolkit.i18nText("Fine-Design_Startup_Page_Collapse_Workspace")); + iconLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/show_less.svg")); + showMoreContent(); + showMore = !showMore; + } else { + fontLabel.setText(Toolkit.i18nText("Fine-Design_Startup_Page_Expand_All")); + iconLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/show_more.svg")); + showLessContent(); + showMore = !showMore; + } + } + }); + tailPanel.add(showAllPanel); + Dimension preferredSize = tailPanel.getPreferredSize(); + tailPanel.setPreferredSize(new Dimension(CONTENT_WIDTH, (int) preferredSize.getHeight())); + } + return tailPanel; + } + + @NotNull + private JPanel generatePartitionPanel(List partition) { + + JPanel partitionPanel = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(0, 20, 0);; + partitionPanel.setName("partitionPanel"); + + for (StartupWorkspaceBean workspaceInfo : partition) { + + JPanel workspaceItemDesc = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + layoutSelectWorkspacePanel(workspaceInfo, workspaceItemDesc); + + layoutSelectAndCreatePanel(workspaceItemDesc); + + partitionPanel.add(workspaceItemDesc); + + Dimension preferredSize = partitionPanel.getPreferredSize(); + partitionPanel.setPreferredSize(new Dimension(CONTENT_WIDTH, (int) preferredSize.getHeight())); + } + return partitionPanel; + } + + private void layoutSelectWorkspacePanel(StartupWorkspaceBean workspaceInfo, JPanel workspaceItemDesc) { + + // 选择工作目录 + // 图标 / 分隔符 / 说明-进入 + // 选择并新建 + AtomicReference borderColorRef = new AtomicReference<>(null); + + JPanel selectWorkspacePanel = new JPanel() { + @Override + public JToolTip createToolTip() { + return new ModernToolTip(); + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color borderColor = borderColorRef.get(); + + Color backColor = Color.WHITE; + g2d.setColor(backColor); + // 直角和圆角上下叠合在一起 + int rectOffset = 10; + int roundOffset = 15; + // 填充一个直角 + g2d.fillRoundRect(0, 0, getWidth() - rectOffset, getHeight(), ARC_DIAMETER, ARC_DIAMETER); + // 填充一个圆角 + g2d.fillRoundRect(getWidth() - roundOffset, 0, roundOffset, getHeight(), 0, 0); + paintBorderIfHover(g2d, borderColor, backColor); + } + + /** + * 当悬浮的时候,将边框展示出来 + * 会叠合,然后填充中间 + * + * |----【-|--】 + * | A 【C| B】 + * |----【-|--】 + * + * 见上面有两种线,分别是 A-| 和 B-【 + * 这里会将 A 和 B 叠在一起,中间则存在 C,然后将 C 的部分扩大一点,然后填充上背景 + * 则形成下面这种图形 + * + * |----】 + * |----】 + * + * @param g2d 绘画 + * @param borderColor 边框颜色 + * @param backColor 背景颜色 + */ + private void paintBorderIfHover(Graphics2D g2d, Color borderColor, Color backColor) { + + if (borderColor != null) { + g2d.setColor(borderColor); + g2d.setStroke(new BasicStroke(BORDER_THIN)); + // 需要一个修正值 + int strokeOffset = BORDER_THIN / 2; + // 直角和圆角上下叠合在一起 + int rectOffset = 10; + int roundOffset = 15; + // 画一个圆角 + int fixRoundWidth = getWidth() - rectOffset; + int fixRoundHeight = getHeight() - BORDER_THIN; + g2d.drawRoundRect(strokeOffset, strokeOffset, fixRoundWidth, fixRoundHeight, ARC_DIAMETER, ARC_DIAMETER); + // 画一个直角 + g2d.drawRoundRect(getWidth() - roundOffset, strokeOffset, roundOffset - strokeOffset, getHeight() - BORDER_THIN, 0, 0); + + g2d.setColor(backColor); + + // 绘制一个矩形,覆盖住多余的相交线 + // 需要考虑上下的线宽 + int coverHeight = getHeight() - (BORDER_THIN * 2); + // 偏左一点的 fixedX + int fixedX = getWidth() - roundOffset - BORDER_THIN; + // 圆角和直角相交的区域 + int coverWidth = 10; + g2d.fillRect(fixedX, BORDER_THIN, coverWidth, coverHeight); + } + } + }; + selectWorkspacePanel.setLayout(new BorderLayout(0,0)); + selectWorkspacePanel.setToolTipText(Toolkit.i18nText("Fine-Design_Startup_Page_Double_Click_Enter_Workspace")); + selectWorkspacePanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + { + + JPanel iconPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + iconPanel.setBorder(new EmptyBorder(0, 10, 0, 10)); + Icon icon = StartupPageUtil.getIcon4DescAreaByWorkspace(workspaceInfo); + UILabel label = new UILabel(icon); + label.setPreferredSize(LABEL_DIMENSION); + iconPanel.add(label, BorderLayout.CENTER); + selectWorkspacePanel.add(iconPanel, BorderLayout.WEST); + + // desc / >箭头 + JPanel descPanel = new JPanel(); + descPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + descPanel.setBorder(new EmptyBorder(0, 10, 0, 0)); + + JPanel simpleDescPanelWrapper = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.CENTER, 0, 0); + JPanel simpleDescPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + UILabel nameLabel = new UILabel(workspaceInfo.getName()); + Font font = nameLabel.getFont(); + Font newSizeFont = font.deriveFont(font.getStyle(), NAME_LABEL_SIZE); + nameLabel.setFont(newSizeFont); + Color nameForeground = nameLabel.getForeground(); + simpleDescPanel.add(nameLabel,BorderLayout.NORTH); + + UILabel pathLabel = new UILabel(workspaceInfo.getPath()); + pathLabel.setPreferredSize(PATH_DIMENSION); + Font pathFont = pathLabel.getFont(); + pathLabel.setFont(pathFont.deriveFont(pathFont.getStyle(), PATH_LABEL_SIZE)); + Color pathColor = PATH_COLOR; + pathLabel.setForeground(pathColor); + simpleDescPanel.add(pathLabel, BorderLayout.SOUTH); + simpleDescPanelWrapper.add(simpleDescPanel); + + descPanel.add(simpleDescPanelWrapper, BorderLayout.WEST); + + MouseAdapter selectWorkspaceMouseListener = new MouseAdapter() { + + @Override + public void mouseEntered(MouseEvent e) { + Color hoverColor = HOVER_COLOR; + borderColorRef.set(hoverColor); + nameLabel.setForeground(hoverColor); + pathLabel.setForeground(hoverColor ); + selectWorkspacePanel.getParent().repaint(); + } + + @Override + public void mouseExited(MouseEvent e) { + borderColorRef.set(Color.WHITE); + nameLabel.setForeground(nameForeground); + pathLabel.setForeground(pathColor); + selectWorkspacePanel.getParent().repaint(); + } + + @Override + public void mousePressed(MouseEvent e) { + + int clickCount = e.getClickCount(); + if (clickCount == BORDER_THIN) { + pageModel.setSelectWorkspaceInfo(workspaceInfo); + openEmptyTemplateRunnable.run(); + return; + } + // selectWorkspaceRunnable + pageModel.setSelectWorkspaceInfo(workspaceInfo); + selectWorkspaceRunnable.run(); + } + + }; + + UILabel arrowLabel = new UILabel(IconUtils.readIcon("/com/fr/design/startup/more.svg")) { + @Override + public JToolTip createToolTip() { + return new ModernToolTip(); + } + }; + arrowLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Startup_Page_Enter_Workspace")); + arrowLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + arrowLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/more_hover.svg")); + selectWorkspaceMouseListener.mouseEntered(e); + } + + @Override + public void mouseExited(MouseEvent e) { + arrowLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/more.svg")); + selectWorkspaceMouseListener.mouseExited(e); + } + + @Override + public void mousePressed(MouseEvent e) { + openEmptyTemplateRunnable.run(); + } + }); + descPanel.add(arrowLabel, BorderLayout.EAST); + + selectWorkspacePanel.add(descPanel, BorderLayout.CENTER); + selectWorkspacePanel.addMouseListener(selectWorkspaceMouseListener); + } + + ColorUtils.syncBackground(selectWorkspacePanel, Color.WHITE); + selectWorkspacePanel.setPreferredSize(SELECT_WORKSPACE_DIMENSION); + workspaceItemDesc.add(selectWorkspacePanel, BorderLayout.WEST); + } + + private void layoutSelectAndCreatePanel(JPanel workspaceItemDesc) { + + // 选择并新建 + AtomicReference borderColorRef = new AtomicReference<>(null); + JPanel selectAndCreatePanel = new JPanel() { + @Override + public JToolTip createToolTip() { + return new ModernToolTip(); + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color borderColor = borderColorRef.get(); + + Color backColor = SHALLOW_WHITE_COLOR; + g2d.setColor(backColor); + + // 见 layoutSelectWorkspacePanel 部分的分析 + // 直角和圆角上下叠合在一起 + int rectOffset = 10; + int roundOffset = 15; + int strokeOffset = BORDER_THIN / 2; + int fixedRoundOffset = roundOffset + strokeOffset; + g2d.fillRoundRect(0, 0, getWidth() - rectOffset, getHeight(), 0, 0); + g2d.fillRoundRect(getWidth() - fixedRoundOffset, 0, roundOffset, getHeight(), ARC_DIAMETER, ARC_DIAMETER); + if (borderColor != null) { + g2d.setColor(borderColor); + g2d.setStroke(new BasicStroke(BORDER_THIN)); + // 画画的笔触需要调整一下 + g2d.drawRoundRect(strokeOffset, strokeOffset, getWidth() - rectOffset, getHeight() - BORDER_THIN, 0, 0); + g2d.drawRoundRect(getWidth() - fixedRoundOffset, strokeOffset, roundOffset - strokeOffset, getHeight() - BORDER_THIN, ARC_DIAMETER, ARC_DIAMETER); + g2d.setColor(backColor); + int fillWidth = 11; + g2d.fillRect(getWidth() - fixedRoundOffset - BORDER_THIN, BORDER_THIN, fillWidth, getHeight() - BORDER_THIN * 2); + } + } + + }; + selectAndCreatePanel.setToolTipText(Toolkit.i18nText("Fine-Design_Startup_Page_Enter_Workspace_And_Create")); + selectAndCreatePanel.setBorder(new EmptyBorder(0, 0, 0, 0)); + selectAndCreatePanel.setLayout(new BorderLayout()); + { + UILabel label = new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/add.svg")); + label.setPreferredSize(new Dimension(ARC_DIAMETER, ARC_DIAMETER)); + label.setForeground(HOVER_COLOR); + selectAndCreatePanel.add(label, BorderLayout.CENTER); + selectAndCreatePanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + borderColorRef.set(HOVER_COLOR); + selectAndCreatePanel.getParent().repaint(); + label.setIcon(IconUtils.readIcon("/com/fr/design/standard/system/add_hover.svg")); + } + + @Override + public void mouseExited(MouseEvent e) { + borderColorRef.set(null); + selectAndCreatePanel.getParent().repaint(); + label.setIcon(IconUtils.readIcon("/com/fr/design/standard/system/add.svg")); + } + @Override + public void mousePressed(MouseEvent e) { + createNewTemplateRunnable.run(); + } + }); + } + ColorUtils.syncBackground(selectAndCreatePanel, Color.GREEN); + selectAndCreatePanel.setPreferredSize(SELECT_CREATE_DIMENSION); + workspaceItemDesc.add(selectAndCreatePanel, BorderLayout.EAST); + } + + public void setSelectWorkspaceRunnable(Runnable selectWorkspaceRunnable) { + + this.selectWorkspaceRunnable = selectWorkspaceRunnable; + } + +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupWorkspaceBean.java b/designer-base/src/main/java/com/fr/startup/ui/StartupWorkspaceBean.java new file mode 100644 index 0000000000..04d660db95 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupWorkspaceBean.java @@ -0,0 +1,49 @@ +package com.fr.startup.ui; + +import com.fr.design.env.DesignerWorkspaceType; + +/** + * created by Harrison on 2022/07/07 + **/ +public class StartupWorkspaceBean { + + private String name; + + private String path; + + private DesignerWorkspaceType type; + + public StartupWorkspaceBean(String name, String path, DesignerWorkspaceType type) { + this.name = name; + this.path = path; + this.type = type; + } + + public static StartupWorkspaceBean create(String name, String path) { + return new StartupWorkspaceBean(name, path, DesignerWorkspaceType.Local); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public DesignerWorkspaceType getType() { + return type; + } + + public void setType(DesignerWorkspaceType type) { + this.type = type; + } +} diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties index f4840b71a4..03a445fab5 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties @@ -18,4 +18,6 @@ com.fr.design.mainframe.ForbiddenPane.refreshButton=75*24 com.fr.design.cell.expand.sort.pane=257*185 com.fr.design.sort.rule.item=125*20 com.fr.design.ds.column.sort.pane=250*180 -com.fr.design.sort.expand.header.pane=95*10 \ No newline at end of file +com.fr.design.sort.expand.header.pane=95*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties index fb0ecfb3d2..3cb9b007d1 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties @@ -17,4 +17,6 @@ com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 com.fr.design.cell.expand.sort.pane=257*170 com.fr.design.sort.rule.item=125*20 com.fr.design.ds.column.sort.pane=250*165 -com.fr.design.sort.expand.header.pane=95*10 \ No newline at end of file +com.fr.design.sort.expand.header.pane=95*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties index 19bb7e97aa..df59420a41 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties @@ -17,4 +17,6 @@ com.fr.design.mainframe.ForbiddenPane.refreshButton=80*24 com.fr.design.cell.expand.sort.pane=267*165 com.fr.design.sort.rule.item=125*20 com.fr.design.ds.column.sort.pane=250*180 -com.fr.design.sort.expand.header.pane=95*10 \ No newline at end of file +com.fr.design.sort.expand.header.pane=95*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties index 055a81109a..e665593029 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties @@ -15,7 +15,10 @@ com.fr.design.report.fit.firstColumn=80*20 com.fr.design.report.fit.column=100*20 com.fr.design.lock.LockInfoDialog=400*180 com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 +com.fr.start.common.DesignerOpenEmptyPanel.createButton=70*24 com.fr.design.cell.expand.sort.pane=227*155 com.fr.design.sort.rule.item=80*20 com.fr.design.ds.column.sort.pane=220*150 -com.fr.design.sort.expand.header.pane=108*10 \ No newline at end of file +com.fr.design.sort.expand.header.pane=108*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties index 2ee112455f..2c99349ca1 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties @@ -17,4 +17,6 @@ com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 com.fr.design.cell.expand.sort.pane=227*155 com.fr.design.sort.rule.item=80*20 com.fr.design.ds.column.sort.pane=220*150 -com.fr.design.sort.expand.header.pane=108*10 \ No newline at end of file +com.fr.design.sort.expand.header.pane=108*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/add.svg b/designer-base/src/main/resources/com/fr/design/standard/system/add.svg new file mode 100755 index 0000000000..cccd52cb5c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/add.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/add_hover.svg b/designer-base/src/main/resources/com/fr/design/standard/system/add_hover.svg new file mode 100644 index 0000000000..777e87831e --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/add_hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/cpt.svg b/designer-base/src/main/resources/com/fr/design/standard/system/cpt.svg new file mode 100755 index 0000000000..0fcdcf70ae --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/cpt.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/home_folder.svg b/designer-base/src/main/resources/com/fr/design/standard/system/home_folder.svg new file mode 100755 index 0000000000..eaf43b0cf8 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/home_folder.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/remote_connect.svg b/designer-base/src/main/resources/com/fr/design/standard/system/remote_connect.svg new file mode 100755 index 0000000000..514e4c5006 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/remote_connect.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/create_new_template.svg b/designer-base/src/main/resources/com/fr/design/startup/create_new_template.svg new file mode 100755 index 0000000000..fd61e745be --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/create_new_template.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/local_server_background_28.svg b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_28.svg new file mode 100755 index 0000000000..a79e502777 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_28.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/local_server_background_36.svg b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_36.svg new file mode 100644 index 0000000000..8ea966cbc4 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_36.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/more.svg b/designer-base/src/main/resources/com/fr/design/startup/more.svg new file mode 100755 index 0000000000..65f7b7c701 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/more.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/more_hover.svg b/designer-base/src/main/resources/com/fr/design/startup/more_hover.svg new file mode 100644 index 0000000000..5b4ee1d6fd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/more_hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_28.svg b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_28.svg new file mode 100755 index 0000000000..da22546f98 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_28.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_36.svg b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_36.svg new file mode 100755 index 0000000000..d10b2700a0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_36.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/show_less.svg b/designer-base/src/main/resources/com/fr/design/startup/show_less.svg new file mode 100755 index 0000000000..b929630e7f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/show_less.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/show_more.svg b/designer-base/src/main/resources/com/fr/design/startup/show_more.svg new file mode 100755 index 0000000000..1b7c059d97 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/show_more.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java b/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java index 090838fd0c..cab7037cd2 100644 --- a/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java +++ b/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java @@ -1,12 +1,12 @@ package com.fr.design; -import com.fr.decision.webservice.v10.plugin.helper.PluginErrorRemindHandler; +import com.fr.design.plugin.remind.PluginErrorDesignReminder; +import com.fr.plugin.error.PluginErrorRemindHandler; import com.fr.design.env.DesignerWorkspaceInfo; import com.fr.design.env.DesignerWorkspaceType; import com.fr.design.env.LocalDesignerWorkspaceInfo; import com.fr.design.env.RemoteDesignerWorkspaceInfo; import com.fr.env.CheckServiceDialog; -import com.fr.env.PluginErrorRemindDialog; import com.fr.invoke.Reflect; import com.fr.workspace.WorkContext; import com.fr.workspace.Workspace; @@ -108,33 +108,4 @@ public class EnvChangeEntranceTest { Assert.assertFalse(Reflect.on(entrance).call("isNotRememberPwd", info3).get()); Assert.assertFalse(Reflect.on(entrance).call("isNotRememberPwd", info4).get()); } - - @Test - public void testPluginErrorRemind() { - - try { - - Workspace workspace = EasyMock.mock(Workspace.class); - EasyMock.expect(workspace.isLocal()).andReturn(false).once(); - EasyMock.expect(workspace.isLocal()).andReturn(true).once(); - PowerMock.mockStatic(WorkContext.class); - EasyMock.expect(WorkContext.getCurrent()).andReturn(workspace).anyTimes(); - - PowerMock.mockStatic(PluginErrorRemindHandler.class); - EasyMock.expect(PluginErrorRemindHandler.pluginErrorContent()).andReturn("").once(); - - EasyMock.replay(workspace); - PowerMock.replayAll(); - - EnvChangeEntrance entrance = EnvChangeEntrance.getInstance(); - - entrance.pluginErrorRemind(); - entrance.pluginErrorRemind(); - - EasyMock.verify(workspace); - PowerMock.verifyAll(); - } catch (Exception e) { - Assert.fail(); - } - } -} \ No newline at end of file +} diff --git a/designer-base/src/test/java/com/fr/design/plugin/remind/PluginErrorDesignReminderTest.java b/designer-base/src/test/java/com/fr/design/plugin/remind/PluginErrorDesignReminderTest.java new file mode 100644 index 0000000000..b7df5af5a7 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/plugin/remind/PluginErrorDesignReminderTest.java @@ -0,0 +1,72 @@ +package com.fr.design.plugin.remind; + +import com.fr.plugin.error.PluginErrorRemindHandler; +import com.fr.workspace.WorkContext; +import com.fr.workspace.empty.EmptyWorkspace; +import junit.framework.TestCase; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Yvan + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(PluginErrorRemindHandler.class) +public class PluginErrorDesignReminderTest extends TestCase { + + @Before + public void before() { + WorkContext.switchTo(EmptyWorkspace.getInstance()); + } + + public void testRemindStartFailedPlugins() { + PowerMock.mockStatic(PluginErrorRemindHandler.class); + EasyMock.expect(PluginErrorRemindHandler.pluginErrorContent()).andReturn("").once(); + + PowerMock.replayAll(); + PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); + + PowerMock.verifyAll(); + } + + public void testRemindInvalidatePlugins() { + PowerMock.mockStatic(PluginErrorRemindHandler.class); + EasyMock.expect(PluginErrorRemindHandler.getInvalidateEmbedPluginNames()).andReturn(new ArrayList<>()).once(); + + PowerMock.replayAll(); + PluginErrorDesignReminder.getInstance().remindInvalidatePlugins(); + + PowerMock.verifyAll(); + } + + public void testDealWithPluginNames() { + List pluginNames1 = Arrays.asList("1"); + String content1 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames1); + Assert.assertFalse(content1.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertFalse(content1.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + + List pluginNames2 = Arrays.asList("1", "2"); + String content2 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames2); + Assert.assertTrue(content2.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertFalse(content2.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + + List pluginNames3 = Arrays.asList("1", "2", "3", "4"); + String content3 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames3); + Assert.assertTrue(content3.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertTrue(content3.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + + List pluginNames4 = Arrays.asList("1", "2", "3"); + String content4 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames4); + Assert.assertTrue(content4.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertFalse(content4.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + } +} diff --git a/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java b/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java index af1d984ea4..60a294d260 100644 --- a/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java +++ b/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java @@ -7,6 +7,6 @@ public class DevDebugUtils { public static void main(String[] args) { - org.swingexplorer.Launcher.main(new String[]{"com.fr.design.utils.DevUtils"}); + org.swingexplorer.Launcher.main(new String[]{"com.fr.startup.ui.StartupPageWindowTest"}); } } diff --git a/designer-base/src/test/java/com/fr/design/utils/DevUtils.java b/designer-base/src/test/java/com/fr/design/utils/DevUtils.java index 2d88277555..dcba96f05f 100644 --- a/designer-base/src/test/java/com/fr/design/utils/DevUtils.java +++ b/designer-base/src/test/java/com/fr/design/utils/DevUtils.java @@ -48,6 +48,12 @@ public class DevUtils { } + public static void show(Runnable runnable) { + + DesignUtils.initLookAndFeel(); + UIUtil.invokeLaterIfNeeded(runnable); + } + public static void main(String[] args) { DevUtils.prepare(); diff --git a/designer-base/src/test/java/com/fr/startup/ui/StartupPageWindowTest.java b/designer-base/src/test/java/com/fr/startup/ui/StartupPageWindowTest.java new file mode 100644 index 0000000000..c1d33a66a6 --- /dev/null +++ b/designer-base/src/test/java/com/fr/startup/ui/StartupPageWindowTest.java @@ -0,0 +1,32 @@ +package com.fr.startup.ui; + +import com.fr.design.utils.DevUtils; +import com.fr.third.guava.collect.Lists; + +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class StartupPageWindowTest { + + public static void main(String[] args) { + + DevUtils.show(new Runnable() { + @Override + public void run() { + HashMap> recentOpenFileMap = new HashMap<>(); + recentOpenFileMap.put("111", Lists.newArrayList("111.cpt", "222//3333.cpt","333.cpt", "444.cpt", "555.cpt", "666.cpt")); + StartupPageModel model = new StartupPageModel(Stream.of( + StartupWorkspaceBean.create("111", "222333344455556663333444555566633334445555666"), StartupWorkspaceBean.create("113", "222"), + StartupWorkspaceBean.create("114", "222"), StartupWorkspaceBean.create("115", "222"), StartupWorkspaceBean.create("116", "222"), + StartupWorkspaceBean.create("117", "222"), StartupWorkspaceBean.create("118", "222"), StartupWorkspaceBean.create("119", "222"), + StartupWorkspaceBean.create("121", "222"), StartupWorkspaceBean.create("122", "222"), StartupWorkspaceBean.create("123", "222"), + StartupWorkspaceBean.create("124", "222"), StartupWorkspaceBean.create("125", "222"), StartupWorkspaceBean.create("126", "222") + ).collect(Collectors.toList()), recentOpenFileMap); + StartupPageWindow window = new StartupPageWindow(model); + window.setVisible(true); + } + }); + } +} \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/fit/common/NewUIModeAutoChangeLine.java b/designer-form/src/main/java/com/fr/design/fit/common/NewUIModeAutoChangeLine.java deleted file mode 100644 index 0037c738d8..0000000000 --- a/designer-form/src/main/java/com/fr/design/fit/common/NewUIModeAutoChangeLine.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.fr.design.fit.common; - -import com.fr.base.DefaultAutoChangeLine; -import com.fr.base.Style; -import com.fr.stable.unit.UNIT; - -import java.awt.Font; -import java.util.List; - -public class NewUIModeAutoChangeLine extends DefaultAutoChangeLine { - @Override - public List textAutoChangeLine(String text, Font font, Style style, UNIT unitWidth, int resolution) { - return autoChangeLine(text, font, style, unitWidth, resolution); - } - - protected double calculateShowWidth(double paintWidth, Style style, int resolution) { - return paintWidth - style.getPaddingLeft() - style.getPaddingRight() - style.getBorderLeftWidth(); - } - -} diff --git a/designer-form/src/main/java/com/fr/design/fit/common/NewUIModeRotationDraw.java b/designer-form/src/main/java/com/fr/design/fit/common/NewUIModeRotationDraw.java deleted file mode 100644 index 3e0b06721e..0000000000 --- a/designer-form/src/main/java/com/fr/design/fit/common/NewUIModeRotationDraw.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.fr.design.fit.common; - -import com.fr.base.BaseUtils; -import com.fr.base.DefaultRotationTextDrawProvider; -import com.fr.base.GraphHelper; -import com.fr.base.Style; -import com.fr.design.mainframe.PX; -import com.fr.stable.Constants; - -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.util.List; - -public class NewUIModeRotationDraw extends DefaultRotationTextDrawProvider { - @Override - public void drawRotationText(Graphics2D g2d, String text, Style style, Font rfont, int width, int height, int horizontalAlignment, int resolution) { - FontMetrics cellFM = GraphHelper.getFontMetrics(rfont); - List lineTextList = BaseUtils.getLineTextList(text, style, rfont, height, width, resolution, new NewUIModeAutoChangeLine()); - drawRotationText(g2d, lineTextList, style, cellFM, width, height, horizontalAlignment, resolution); - } - - - protected int calculateTextWidth(int width, Style style) { - return width - style.getPaddingRight(); - } - - protected double calculateTextX(Style style, int width, int textWidth, int horizontalAlignment, int resolution) { - double textX = padding2PixExcludeRight(style.getPaddingLeft(), resolution); - if (horizontalAlignment == Constants.CENTER) { - textX += (width - textWidth - textX) / 2f; - } else if (horizontalAlignment == Constants.RIGHT) { - textX = width - style.getPaddingRight() - textWidth; - } - return textX; - } - - protected int toPXWithResolution(double pt, int resolution) { - return (int) PX.toPixWithResolution(pt, resolution); - } - - protected double padding2PixExcludeRight(int padding, int resolution) { - return PX.toPixWithResolution(padding, resolution); - } - - protected int calculateTextY(Style style, int height, int textHeight, int textAscent, List lineTextList, int resolution) { - // 计算Y的高度. - int textY = 0; - int textAllHeight = textHeight * lineTextList.size(); - double spacingBefore = toPXWithResolution(style.getSpacingBefore(), resolution); - double spacingAfter = toPXWithResolution(style.getSpacingAfter(), resolution); - double lineSpacing = toPXWithResolution(style.getLineSpacing(), resolution); - textAllHeight += spacingBefore + spacingAfter + lineSpacing * lineTextList.size(); - if (style.getVerticalAlignment() == Constants.TOP) { - } else if (style.getVerticalAlignment() == Constants.CENTER) { - if (height > textAllHeight) {// 如果所有文本的高度小于当前可以绘区域的高度,就从0开始画字符. - textY = (height - textAllHeight) / 2; - } - } else if (style.getVerticalAlignment() == Constants.BOTTOM) { - if (height > textAllHeight) { - textY = height - textAllHeight; - } - } - textY += textAscent;// 在绘画的时候,必须添加Ascent的高度. - textY += spacingBefore + lineSpacing;//james:加上"段前间距"+“行间距” - return textY; - } - -} diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxGroupDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxGroupDefinePane.java index 74819ae452..579001b555 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxGroupDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxGroupDefinePane.java @@ -7,7 +7,7 @@ import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.present.dict.DictionaryPane; -import com.fr.design.widget.component.CheckBoxDictPane; +import com.fr.design.widget.component.ReturnTypePane; import com.fr.design.widget.ui.designer.btn.ButtonGroupDefinePane; import com.fr.form.ui.CheckBoxGroup; @@ -17,7 +17,7 @@ import java.awt.*; public class CheckBoxGroupDefinePane extends ButtonGroupDefinePane { private DictionaryPane dictPane; - private CheckBoxDictPane checkBoxDictPane; + private ReturnTypePane returnTypePane; private UICheckBox checkbox; public CheckBoxGroupDefinePane(XCreator xCreator) { @@ -40,12 +40,12 @@ public class CheckBoxGroupDefinePane extends ButtonGroupDefinePane { - private UICheckBox supportTagCheckBox; - private CheckBoxDictPane checkBoxDictPane; - private UITextField waterMarkDictPane; - private UICheckBox removeRepeatCheckBox; + private UICheckBox supportTagCheckBox; + private ReturnTypePane returnTypePane; + private UITextField waterMarkDictPane; + private UICheckBox removeRepeatCheckBox; public ComboCheckBoxDefinePane(XCreator xCreator) { super(xCreator); @@ -40,13 +40,13 @@ public class ComboCheckBoxDefinePane extends DictEditorDefinePane public JPanel createOtherPane(){ supportTagCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Support_Tag"), true); supportTagCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - checkBoxDictPane = new CheckBoxDictPane(); + returnTypePane = new ReturnTypePane(); double f = TableLayout.FILL; double p = TableLayout.PREFERRED; Component[][] components = new Component[][]{ new Component[]{supportTagCheckBox, null }, - new Component[]{checkBoxDictPane, null}, + new Component[]{returnTypePane, null}, }; double[] rowSize = {p, p}; double[] columnSize = {p, f}; @@ -56,7 +56,7 @@ public class ComboCheckBoxDefinePane extends DictEditorDefinePane } protected void populateSubDictionaryEditorBean(ComboCheckBox ob){ - this.checkBoxDictPane.populate(ob); + this.returnTypePane.populate(ob); waterMarkDictPane.setText(ob.getWaterMark()); formWidgetValuePane.populate(ob); this.supportTagCheckBox.setSelected(ob.isSupportTag()); @@ -65,7 +65,7 @@ public class ComboCheckBoxDefinePane extends DictEditorDefinePane protected ComboCheckBox updateSubDictionaryEditorBean(){ ComboCheckBox combo = (ComboCheckBox) creator.toData(); - checkBoxDictPane.update(combo); + returnTypePane.update(combo); formWidgetValuePane.update(combo); combo.setWaterMark(waterMarkDictPane.getText()); combo.setSupportTag(this.supportTagCheckBox.isSelected()); @@ -77,7 +77,7 @@ public class ComboCheckBoxDefinePane extends DictEditorDefinePane public DataCreatorUI dataUI() { return null; } - + @Override public String title4PopupWindow() { return "ComboCheckBox"; diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/TreeEditorDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/TreeEditorDefinePane.java index 9746c605d5..13049e4c95 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/TreeEditorDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/TreeEditorDefinePane.java @@ -1,78 +1,50 @@ package com.fr.design.widget.ui.designer; import com.fr.design.data.DataCreatorUI; -import com.fr.design.designer.IntervalConstants; import com.fr.design.designer.creator.XCreator; -import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itree.refreshabletree.TreeRootPane; -import com.fr.design.layout.TableLayout; -import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.widget.accessibles.AccessibleTreeModelEditor; +import com.fr.design.widget.component.ReturnTypePane; import com.fr.form.ui.TreeEditor; import javax.swing.BorderFactory; import javax.swing.JPanel; +import java.awt.BorderLayout; import java.awt.Component; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; /* * richer:tree editor */ public class TreeEditorDefinePane extends CustomWritableRepeatEditorPane { + private ReturnTypePane returnTypePane; protected TreeRootPane treeRootPane; - private UICheckBox mutiSelect; - private UICheckBox loadAsync; - private UICheckBox returnLeaf; - private UICheckBox returnPath; private AccessibleTreeModelEditor accessibleTreeModelEditor; public TreeEditorDefinePane(XCreator xCreator) { super(xCreator); - treeRootPane = new TreeRootPane(); } public JPanel createOtherPane() { - mutiSelect = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Mutiple_Selection_Or_Not")); - mutiSelect.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - - loadAsync = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Load_By_Async")); - loadAsync.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - loadAsync.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - UICheckBox checkBox = (UICheckBox) e.getSource(); - doLoadTypeChange(checkBox.isSelected()); + treeRootPane = new TreeRootPane(); + returnTypePane = new ReturnTypePane(); + JPanel panel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + panel.add(treeRootPane, BorderLayout.NORTH); + returnTypePane.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); + panel.add(returnTypePane, BorderLayout.CENTER); + treeRootPane.addTreeAttrChangeListener(treeAttr -> { + boolean showReturnTypePane = treeAttr.isMultipleSelection() && !treeAttr.isReturnFullPath(); + returnTypePane.setVisible(showReturnTypePane); + if (!showReturnTypePane) { + returnTypePane.setReturnType(ReturnTypePane.ReturnType.ARRAY); } }); - returnLeaf = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Return_Leaf")); - returnLeaf.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - - returnPath = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Return_Path")); - returnPath.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - - double f = TableLayout.FILL; - double p = TableLayout.PREFERRED; - Component[][] components = new Component[][]{ - new Component[]{mutiSelect}, - new Component[]{loadAsync}, - new Component[]{returnLeaf}, - new Component[]{returnPath} - }; - double[] rowSize = {p, p, p, p}; - double[] columnSize = {p}; - JPanel panel = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, IntervalConstants.INTERVAL_L2, IntervalConstants.INTERVAL_L1); return panel; } - private void doLoadTypeChange(Boolean selected) { - //给埋点插件提供一个方法,埋埋点用 - } - @Override public String title4PopupWindow() { return "tree"; @@ -89,10 +61,7 @@ public class TreeEditorDefinePane extends CustomWritableRepeatEditorPane { - CheckBoxDictPane checkBoxDictPane; + private ReturnTypePane returnTypePane; private UICheckBox checkbox; private ButtonGroupDictPane buttonGroupDictPane; @@ -28,25 +28,25 @@ public class CheckBoxGroupDefinePane extends FieldEditorDefinePane { - private CheckBoxDictPane checkBoxDictPane; + private ReturnTypePane returnTypePane; private AccessibleDictionaryEditor dictPane; - private UICheckBox supportTagCheckBox; + private UICheckBox supportTagCheckBox; public ComboCheckBoxDefinePane() { super.initComponents(); @@ -28,7 +28,7 @@ public class ComboCheckBoxDefinePane extends CustomWritableRepeatEditorPane { - protected AccessibleTreeModelEditor treeSettingPane; - protected TreeRootPane treeRootPane; + protected AccessibleTreeModelEditor treeSettingPane; - public TreeComboBoxEditorDefinePane() { - this.initComponents(); - } + private ReturnTypePane returnTypePane; + protected TreeRootPane treeRootPane; + public TreeComboBoxEditorDefinePane() { + this.initComponents(); + } - @Override - protected JPanel setForthContentPane() { - JPanel content = FRGUIPaneFactory.createBorderLayout_L_Pane(); - content.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - treeRootPane = new TreeRootPane(); - content.add(treeRootPane, BorderLayout.NORTH); - return content; - } - @Override - protected JPanel setFirstContentPane() { - treeSettingPane = new AccessibleTreeModelEditor(); - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel north = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{ - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Create_Tree")), treeSettingPane}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W2, IntervalConstants.INTERVAL_L1); - north.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); - JPanel center = super.setFirstContentPane(); - jPanel.add(north, BorderLayout.NORTH); - jPanel.add(center, BorderLayout.CENTER); - return jPanel; - } + @Override + protected JPanel setForthContentPane() { + JPanel content = FRGUIPaneFactory.createBorderLayout_L_Pane(); + treeRootPane = new TreeRootPane(); + returnTypePane = new ReturnTypePane(); + content.add(treeRootPane, BorderLayout.NORTH); + returnTypePane.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); + content.add(returnTypePane, BorderLayout.CENTER); + treeRootPane.addTreeAttrChangeListener(treeAttr -> { + boolean showReturnTypePane = treeAttr.isMultipleSelection() && !treeAttr.isReturnFullPath(); + returnTypePane.setVisible(showReturnTypePane); + if (!showReturnTypePane) { + returnTypePane.setReturnType(ReturnTypePane.ReturnType.ARRAY); + } + }); + content.add(treeRootPane, BorderLayout.NORTH); + return content; + } + @Override + protected JPanel setFirstContentPane() { + treeSettingPane = new AccessibleTreeModelEditor(); + JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + JPanel north = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{ + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Create_Tree")), treeSettingPane}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W2, IntervalConstants.INTERVAL_L1); + north.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); + JPanel center = super.setFirstContentPane(); + jPanel.add(north, BorderLayout.NORTH); + jPanel.add(center, BorderLayout.CENTER); + return jPanel; + } - @Override - protected String title4PopupWindow() { - return "treecombobox"; - } + @Override + protected String title4PopupWindow() { + return "treecombobox"; + } - @Override - protected void populateSubCustomWritableRepeatEditorBean(TreeEditor e) { - treeSettingPane.setValue(e.getBuildModelConfig()); - treeRootPane.populate(e.getTreeAttr()); - } + @Override + protected void populateSubCustomWritableRepeatEditorBean(TreeEditor e) { + treeSettingPane.setValue(e.getBuildModelConfig()); + treeRootPane.populate(e.getTreeAttr()); + returnTypePane.populate(e); + } - @Override - protected TreeComboBoxEditor updateSubCustomWritableRepeatEditorBean() { - TreeComboBoxEditor editor = new TreeComboBoxEditor(); - editor.setBuildModelConfig(treeSettingPane.getValue()); - editor.setTreeAttr(treeRootPane.update()); - return editor; - } + @Override + protected TreeComboBoxEditor updateSubCustomWritableRepeatEditorBean() { + TreeComboBoxEditor editor = new TreeComboBoxEditor(); + editor.setBuildModelConfig(treeSettingPane.getValue()); + editor.setTreeAttr(treeRootPane.update()); + returnTypePane.update(editor); + return editor; + } - @Override - public DataCreatorUI dataUI() { - return null; - } + @Override + public DataCreatorUI dataUI() { + return null; + } } \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/widget/ui/TreeEditorDefinePane.java b/designer-realize/src/main/java/com/fr/design/widget/ui/TreeEditorDefinePane.java index 89e54cdc8d..086ef88837 100644 --- a/designer-realize/src/main/java/com/fr/design/widget/ui/TreeEditorDefinePane.java +++ b/designer-realize/src/main/java/com/fr/design/widget/ui/TreeEditorDefinePane.java @@ -8,6 +8,7 @@ import com.fr.design.gui.itree.refreshabletree.TreeRootPane; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.widget.accessibles.AccessibleTreeModelEditor; +import com.fr.design.widget.component.ReturnTypePane; import com.fr.form.ui.TreeEditor; @@ -19,6 +20,8 @@ import java.awt.*; * richer:tree editor */ public class TreeEditorDefinePane extends FieldEditorDefinePane { + private ReturnTypePane returnTypePane; + protected TreeRootPane treeRootPane; private AccessibleTreeModelEditor accessibleTreeModelEditor; @@ -32,6 +35,7 @@ public class TreeEditorDefinePane extends FieldEditorDefinePane { protected void populateSubFieldEditorBean(TreeEditor e) { this.accessibleTreeModelEditor.setValue(e.getBuildModelConfig()); treeRootPane.populate(e.getTreeAttr()); + returnTypePane.populate(e); if (this.removeRepeatCheckBox != null) { this.removeRepeatCheckBox.setSelected(e.isRemoveRepeat()); } @@ -42,6 +46,7 @@ public class TreeEditorDefinePane extends FieldEditorDefinePane { TreeEditor editor = new TreeEditor(); editor.setBuildModelConfig(accessibleTreeModelEditor.getValue()); editor.setTreeAttr(treeRootPane.update()); + returnTypePane.update(editor); if (this.removeRepeatCheckBox != null) { editor.setRemoveRepeat(this.removeRepeatCheckBox.isSelected()); } @@ -75,9 +80,19 @@ public class TreeEditorDefinePane extends FieldEditorDefinePane { protected JPanel setThirdContentPane() { JPanel content = FRGUIPaneFactory.createBorderLayout_L_Pane(); - content.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); treeRootPane = new TreeRootPane(); + returnTypePane = new ReturnTypePane(); content.add(treeRootPane, BorderLayout.NORTH); + returnTypePane.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); + content.add(returnTypePane, BorderLayout.CENTER); + treeRootPane.addTreeAttrChangeListener(treeAttr -> { + boolean showReturnTypePane = treeAttr.isMultipleSelection() && !treeAttr.isReturnFullPath(); + returnTypePane.setVisible(showReturnTypePane); + if (!showReturnTypePane) { + returnTypePane.setReturnType(ReturnTypePane.ReturnType.ARRAY); + } + }); + //content.add(treeRootPane, BorderLayout.NORTH); return content; } diff --git a/designer-realize/src/main/java/com/fr/grid/GridUtils.java b/designer-realize/src/main/java/com/fr/grid/GridUtils.java index 21b032265f..03d125075c 100644 --- a/designer-realize/src/main/java/com/fr/grid/GridUtils.java +++ b/designer-realize/src/main/java/com/fr/grid/GridUtils.java @@ -448,7 +448,8 @@ public class GridUtils { int editElementcolumn = editCellElement.getColumn(); UNIT preferredHeight = PaintUtils.analyzeCellElementPreferredHeight( editCellElement, - columnWidthList.getRangeValue(editElementcolumn, editElementcolumn + editCellElement.getColumnSpan())); + columnWidthList.getRangeValue(editElementcolumn, editElementcolumn + editCellElement.getColumnSpan()), + DesignerUIModeConfig.getInstance().getAutoChangeLineStrategy()); if (editCellElement.getRowSpan() == 1) { rowHeightList.set(editCellElement.getRow(), UNIT.max(preferredHeight, rowHeightList.get(editCellElement.getRow()))); diff --git a/designer-realize/src/main/java/com/fr/start/DesignerInitial.java b/designer-realize/src/main/java/com/fr/start/DesignerInitial.java index 39c702af56..83d8a6fbdc 100644 --- a/designer-realize/src/main/java/com/fr/start/DesignerInitial.java +++ b/designer-realize/src/main/java/com/fr/start/DesignerInitial.java @@ -10,6 +10,7 @@ import com.fr.event.Listener; import com.fr.event.Null; import com.fr.invoke.Reflect; import com.fr.stable.bridge.StableFactory; +import com.fr.task.Once; /** * Created by juhaoyu on 2019-06-14. @@ -18,6 +19,26 @@ import com.fr.stable.bridge.StableFactory; public class DesignerInitial { private static volatile BaseDesigner designer; + + private static final Once OPEN_LAST_FILE_INIT = new Once(() -> { + + EventDispatcher.listen(DesignerLaunchStatus.OPEN_LAST_FILE_COMPLETE, new Listener() { + @Override + public void on(Event event, Null param) { + EventDispatcher.stopListen(this); + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + DesignerContext.getDesignerFrame().setVisible(true); + DesignerContext.getDesignerFrame().resizeFrame(); + //启动画面结束 + SplashContext.getInstance().hide(); + } + }); + DesignerLaunchStatus.setStatus(DesignerLaunchStatus.STARTUP_COMPLETE); + } + }); + }); public static void init(final String... args) { UIUtil.invokeLaterIfNeeded(new Runnable() { @@ -34,6 +55,8 @@ public class DesignerInitial { } public static void prepare() { + + DesignerLaunchStatus.setStatus(DesignerLaunchStatus.DESIGNER_INIT_STARTED); UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { @@ -42,21 +65,6 @@ public class DesignerInitial { } } }); - EventDispatcher.listen(DesignerLaunchStatus.OPEN_LAST_FILE_COMPLETE, new Listener() { - @Override - public void on(Event event, Null param) { - EventDispatcher.stopListen(this); - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - DesignerContext.getDesignerFrame().setVisible(true); - DesignerContext.getDesignerFrame().resizeFrame(); - //启动画面结束 - SplashContext.getInstance().hide(); - } - }); - DesignerLaunchStatus.setStatus(DesignerLaunchStatus.STARTUP_COMPLETE); - } - }); + OPEN_LAST_FILE_INIT.run(); } } diff --git a/designer-realize/src/main/java/com/fr/start/DesignerJavaRuntime.java b/designer-realize/src/main/java/com/fr/start/DesignerJavaRuntime.java index f65ae11f85..7abf5d963d 100644 --- a/designer-realize/src/main/java/com/fr/start/DesignerJavaRuntime.java +++ b/designer-realize/src/main/java/com/fr/start/DesignerJavaRuntime.java @@ -2,7 +2,6 @@ package com.fr.start; import com.fr.design.os.impl.SupportOSImpl; import com.fr.general.ComparatorUtils; -import com.fr.general.GeneralContext; import com.fr.general.GeneralUtils; import com.fr.general.IOUtils; import com.fr.locale.InterProviderFactory; @@ -15,7 +14,6 @@ import com.fr.stable.os.OperatingSystem; import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; diff --git a/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java b/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java index 3115781b3d..21d5fdf56e 100644 --- a/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java +++ b/designer-realize/src/main/java/com/fr/start/LifecycleFatalErrorHandler.java @@ -26,6 +26,7 @@ import com.fr.stable.lifecycle.ErrorType; import com.fr.stable.lifecycle.ErrorTypeHelper; import com.fr.stable.lifecycle.FineLifecycleFatalError; import com.fr.stable.project.ProjectConstants; +import com.fr.start.common.DesignerStartupContext; import javax.swing.JOptionPane; import java.util.Collection; @@ -54,6 +55,12 @@ public class LifecycleFatalErrorHandler { } public void handle(FineLifecycleFatalError fatal) { + + if (DesignerStartupContext.getInstance().onWarmup()) { + // 如果是预热过程中的错误,不理 + return; + } + SplashContext.getInstance().hide(); FineProcessContext.getParentPipe().fire(new CarryMessageEvent(ReportState.STOP.getValue())); diff --git a/designer-realize/src/main/java/com/fr/start/MainDesigner.java b/designer-realize/src/main/java/com/fr/start/MainDesigner.java index f60003c9a1..9d4d3eb145 100644 --- a/designer-realize/src/main/java/com/fr/start/MainDesigner.java +++ b/designer-realize/src/main/java/com/fr/start/MainDesigner.java @@ -1,6 +1,7 @@ package com.fr.start; +import com.fr.base.function.UITerminator; import com.fr.base.vcs.DesignerMode; import com.fr.design.DesignerEnvManager; import com.fr.design.actions.file.WebPreviewUtils; @@ -32,6 +33,8 @@ import com.fr.design.mainframe.alphafine.component.AlphaFinePane; import com.fr.design.mainframe.bbs.UserInfoLabel; import com.fr.design.mainframe.bbs.UserInfoPane; import com.fr.design.mainframe.guide.entry.GuideEntryPane; +import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector; +import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; import com.fr.design.menu.KeySetUtils; import com.fr.design.menu.MenuDef; @@ -44,6 +47,8 @@ import com.fr.design.monitor.DesignerLifecycleMonitorContext; import com.fr.design.notification.ui.NotificationCenterPane; import com.fr.design.share.SharableManager; import com.fr.design.ui.util.UIUtil; +import com.fr.design.utils.DesignUtils; +import com.fr.design.utils.DesignerPort; import com.fr.design.utils.concurrent.ThreadFactoryBuilder; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.env.utils.DesignerInteractionHistory; @@ -61,8 +66,10 @@ import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.lifecycle.FineLifecycleFatalError; import com.fr.stable.xml.XMLTools; +import com.fr.start.common.DesignerStartupContext; import com.fr.start.common.SplashCommon; import com.fr.start.module.StartupArgs; +import com.fr.start.preload.PreLoadService; import com.fr.start.server.ServerTray; import com.fr.third.org.apache.commons.lang3.time.StopWatch; import com.fr.van.chart.map.server.ChartMapEditorAction; @@ -74,11 +81,14 @@ import javax.swing.border.MatteBorder; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; @@ -109,14 +119,19 @@ public class MainDesigner extends BaseDesigner { * @param args 参数 */ public static void main(String[] args) { - + DesignerStartupContext.getRecorder().start(); showSplash(); + startPreload0(); + DeepLinkManager.getInstance().start(args); StopWatch watch = new StopWatch(); watch.start(); DesignerLifecycleMonitorContext.getMonitor().beforeStart(); //启动运行时 FineRuntime.start(); + + startPreload1(); + DesignerSubListener.getInstance().start(); EventDispatcher.listen(LifecycleErrorEvent.SELF, new Listener() { @Override @@ -125,6 +140,8 @@ public class MainDesigner extends BaseDesigner { } }); Module designerRoot = ModuleContext.parseRoot("designer-startup.xml"); + + FineLoggerFactory.getLogger().debug("designer-startup prepared cost {} ms", DesignerStartupContext.getRecorder().getTime(TimeUnit.MILLISECONDS)); //传递启动参数 designerRoot.setSingleton(StartupArgs.class, new StartupArgs(args)); try { @@ -141,6 +158,41 @@ public class MainDesigner extends BaseDesigner { watch.stop(); } + /** + * 在 {@link FineRuntime#start()} 运行后 + */ + private static void startPreload1() { + + CompletableFuture initLookAndFeel = CompletableFuture.runAsync(DesignUtils::initLookAndFeel); + PreLoadService.getInstance().addFuture(initLookAndFeel); + } + + /** + * 在 {@link FineRuntime#start()} 运行前 + */ + private static void startPreload0() { + + PreLoadService.getInstance().addRunnable(() -> { + if (DesignUtils.isPortOccupied()) { + UITerminator action = new UITerminator() { + @Override + protected void doRun() { + StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.PORT_OCCUPIED.getId(), + DesignerErrorMessage.PORT_OCCUPIED.getMessage()); + DesignerPort.getInstance().resetPort(); + } + }; + action.run(); + } + }); + + Runnable fontLoad = () -> { + Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + }; + PreLoadService.getInstance().addRunnable(fontLoad); + + } + private static void showSplash() { // 快快显示启动画面 UIUtil.invokeAndWaitIfNeeded(new Runnable() { diff --git a/designer-realize/src/main/java/com/fr/start/SplashContext.java b/designer-realize/src/main/java/com/fr/start/SplashContext.java index cc9eb19336..7fc909c5f3 100644 --- a/designer-realize/src/main/java/com/fr/start/SplashContext.java +++ b/designer-realize/src/main/java/com/fr/start/SplashContext.java @@ -83,7 +83,6 @@ public class SplashContext { //取消监听 EventDispatcher.stopListen(listener); splashStrategy.hide(); - // 一次性 splashStrategy = null; } } diff --git a/designer-realize/src/main/java/com/fr/start/common/SplashPane.java b/designer-realize/src/main/java/com/fr/start/common/SplashPane.java index 74500acc35..2bbb1b1527 100644 --- a/designer-realize/src/main/java/com/fr/start/common/SplashPane.java +++ b/designer-realize/src/main/java/com/fr/start/common/SplashPane.java @@ -4,17 +4,22 @@ import com.bulenkov.iconloader.IconLoader; import com.bulenkov.iconloader.util.JBUI; import com.fr.base.GraphHelper; import com.fr.design.locale.impl.SplashMark; -import com.fr.stable.GraphicsConfig; import com.fr.general.locale.LocaleCenter; import com.fr.general.locale.LocaleMark; import com.fr.stable.GraphDrawHelper; +import com.fr.stable.GraphicsConfig; import com.fr.stable.StringUtils; import com.fr.stable.os.OperatingSystem; import com.fr.value.NotNullLazyValue; import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; +import javax.swing.Icon; +import javax.swing.JPanel; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; import java.util.Locale; /** diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java b/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java index d3a30eb59b..8e8b5b519a 100644 --- a/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java +++ b/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java @@ -102,6 +102,8 @@ import com.fr.log.FineLoggerFactory; import com.fr.log.LogHandler; import com.fr.module.Activator; import com.fr.module.extension.Prepare; +import com.fr.plugin.beforeload.embed.DefaultPluginEmbedInfo; +import com.fr.plugin.beforeload.embed.PluginEmbedInfo; import com.fr.plugin.context.PluginContext; import com.fr.plugin.injectable.PluginModule; import com.fr.plugin.manage.PluginFilter; @@ -135,16 +137,19 @@ import com.fr.stable.script.ValueConverter; import com.fr.stable.xml.ObjectTokenizer; import com.fr.stable.xml.ObjectXMLWriterFinder; import com.fr.start.BBSGuestPaneProvider; +import com.fr.start.common.DesignerStartupExecutor; +import com.fr.start.common.DesignerStartupPool; import com.fr.task.Once; import com.fr.workspace.WorkContext; import com.fr.xml.ReportXMLUtils; +import javax.swing.SwingWorker; import java.awt.Image; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import java.util.Set; -import javax.swing.SwingWorker; +import java.util.concurrent.CompletableFuture; /** * Created by juhaoyu on 2018/1/31. @@ -154,7 +159,7 @@ import javax.swing.SwingWorker; public class DesignerActivator extends Activator implements Prepare { private LogHandler logHandler = null; - + private static final String PLUGIN_EXPORT_IMAGE_SETTING = "com.fr.plugin.exportimagesettings.v11"; private final Once pushUpdateTask = new Once(new Runnable() { @Override public void run() { @@ -164,40 +169,59 @@ public class DesignerActivator extends Activator implements Prepare { } }); + private boolean hasUpdated = false; + @Override public void start() { - startLoginAuthServer(); - migrateBBSInfoFromFineDB(); - FormThemeConfigMigrator.getInstance().upgrade(); - ReportThemeConfigMigrator.getInstance().upgrade(); + List markers = findMutable(InterMutableKey.Path); for (LocaleMarker marker : markers) { if (marker.match(LocaleScope.DESIGN)) { DesignI18nImpl.getInstance().addResource(marker.getPath()); } } - designerModuleStart(); - loadLogAppender(); - DesignerSocketIO.update(); - DesignerWorkspaceLoader.init(); - OSSupportCenter.buildAction(new OSBasedAction() { - @Override - public void execute(Object... objects) { - UserInfoPane.getInstance().updateBBSUserInfo(); - } - }, SupportOSImpl.BBS_USER_LOGIN_PANE); - storePassport(); - AlphaFineHelper.switchConfig4Locale(); - RecoverManager.register(new RecoverForDesigner()); - pushUpdateTask.run(); - PluginResourceLoader.INSTANCE.checkOldShopFile(); - UpmResourceLoader.INSTANCE.checkOldShopFile(); + + CompletableFuture themeConfigPrepare = CompletableFuture.runAsync(() -> { + FormThemeConfigMigrator.getInstance().upgrade(); + ReportThemeConfigMigrator.getInstance().upgrade(); + }, DesignerStartupPool.common()); + + CompletableFuture mainDesignerPrepare = CompletableFuture.runAsync(this::designerModuleStart, DesignerStartupPool.common()); + + CompletableFuture otherFeaturesPrepare = CompletableFuture.runAsync(() -> { + startBBSLoginAuthServer(); + migrateBBSInfoFromFineDB(); + OSSupportCenter.buildAction(new OSBasedAction() { + @Override + public void execute(Object... objects) { + UserInfoPane.getInstance().updateBBSUserInfo(); + } + }, SupportOSImpl.BBS_USER_LOGIN_PANE); + loadLogAppender(); + DesignerSocketIO.update(); + DesignerWorkspaceLoader.init(); + storePassport(); + AlphaFineHelper.switchConfig4Locale(); + RecoverManager.register(new RecoverForDesigner()); + }); + + CompletableFuture resourcePrepare = CompletableFuture.runAsync(() -> { + pushUpdateTask.run(); + PluginResourceLoader.INSTANCE.checkOldShopFile(); + UpmResourceLoader.INSTANCE.checkOldShopFile(); + }, DesignerStartupPool.common()); + + CompletableFuture + .allOf(mainDesignerPrepare, themeConfigPrepare, otherFeaturesPrepare, resourcePrepare) + .join(); } @Override public void afterAllStart() { - DesignerLaunchStatus.setStatus(DesignerLaunchStatus.DESIGNER_INIT_COMPLETE); + + DesignerStartupExecutor.getInstance().execute(() -> DesignerLaunchStatus.setStatus(DesignerLaunchStatus.DESIGNER_INIT_COMPLETE)); + //生成BasicChartQuickEditor对象,需要用到ChartDesignerActivator的注册信息(DesignModuleFactory.registerChartPropertyPaneClass(ChartPropertyPane.class);) //所以不能在registerCellEditor函数中进行注册 ActionFactory.registerCellEditor(ChartCollection.class, new BasicChartQuickEditor()); @@ -520,9 +544,14 @@ public class DesignerActivator extends Activator implements Prepare { }.execute(); } }); + prepareDefaultEmbedPluginInfo(); } - - private void startLoginAuthServer() { + + private void prepareDefaultEmbedPluginInfo() { + addMutable(PluginEmbedInfo.KEY, DefaultPluginEmbedInfo.create(PLUGIN_EXPORT_IMAGE_SETTING)); + } + + private void startBBSLoginAuthServer() { OptimizeUtil.open(() -> { // 设计器启动后启动 diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerStartup.java b/designer-realize/src/main/java/com/fr/start/module/DesignerStartup.java index fd8bd93079..ff7962f61a 100644 --- a/designer-realize/src/main/java/com/fr/start/module/DesignerStartup.java +++ b/designer-realize/src/main/java/com/fr/start/module/DesignerStartup.java @@ -17,7 +17,6 @@ import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector; import com.fr.design.mainframe.messagecollect.StartupMessageCollector; import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage; import com.fr.design.utils.DesignUtils; -import com.fr.design.utils.DesignerPort; import com.fr.env.utils.WorkspaceUtils; import com.fr.event.Event; import com.fr.event.Listener; @@ -35,12 +34,15 @@ import com.fr.stable.project.ProjectConstants; import com.fr.start.DesignerProcessType; import com.fr.start.ServerStarter; import com.fr.start.event.LazyStartupEvent; +import com.fr.start.preload.PreLoadService; import com.fr.start.server.FineEmbedServer; +import com.fr.third.guava.base.Stopwatch; import com.fr.value.NotNullLazyValue; import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; /** * Created by juhaoyu on 2018/1/8. @@ -58,17 +60,15 @@ public class DesignerStartup extends Activator { @Override public void beforeAllStart() { + BuildContext.setBuildFilePath("/com/fr/stable/build.properties"); - + registerDaoSelector(); - - // 初始化look and feel - DesignUtils.initLookAndFeel(); - if (DesignUtils.isPortOccupied()) { - StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.PORT_OCCUPIED.getId(), - DesignerErrorMessage.PORT_OCCUPIED.getMessage()); - DesignerPort.getInstance().resetPort(); - } + + Stopwatch beforeWatch = Stopwatch.createStarted(); + PreLoadService.getInstance().waitForAll(); + FineLoggerFactory.getLogger().debug( "DesignerStartup cost {} ms to wait load", beforeWatch.elapsed(TimeUnit.MILLISECONDS)); + if (DesignUtils.isStarted()) { // 如果端口被占用了 说明程序已经运行了一次,也就是说,已经建立一个监听服务器,现在只要给服务器发送命令就好了 final String[] args = startupArgsValue.getValue().get(); @@ -78,17 +78,17 @@ public class DesignerStartup extends Activator { FineLoggerFactory.getLogger().info("The Designer Has Been Started"); if (args.length == 0) { TipDialog dialog = new TipDialog(null, - DesignerProcessType.INSTANCE.obtain(), - Toolkit.i18nText("Fine-Design_Last_Designer_Process_Not_Exist"), - Toolkit.i18nText("Fine-Design_End_Occupied_Process"), - Toolkit.i18nText("Fine-Design_Basic_Cancel")) { + DesignerProcessType.INSTANCE.obtain(), + Toolkit.i18nText("Fine-Design_Last_Designer_Process_Not_Exist"), + Toolkit.i18nText("Fine-Design_End_Occupied_Process"), + Toolkit.i18nText("Fine-Design_Basic_Cancel")) { @Override protected void endEvent() { dispose(); DesignUtils.clientSend(new String[]{"end"}); RestartHelper.restart(); } - + @Override protected void cancelEvent() { dispose(); @@ -96,13 +96,13 @@ public class DesignerStartup extends Activator { }; dialog.setVisible(true); StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.DESIGNER_PROCESS_OCCUPIED.getId(), - DesignerErrorMessage.DESIGNER_PROCESS_OCCUPIED.getMessage(), - StringUtils.EMPTY); + DesignerErrorMessage.DESIGNER_PROCESS_OCCUPIED.getMessage(), + StringUtils.EMPTY); FineLoggerFactory.getLogger().error(DesignerErrorMessage.DESIGNER_PROCESS_OCCUPIED.getId() + ": " + DesignerErrorMessage.DESIGNER_PROCESS_OCCUPIED.getMessage()); } DesignerExiter.getInstance().execute(); - return; } + } @Override diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java index 5abeccc842..a440906aff 100644 --- a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java +++ b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java @@ -7,7 +7,7 @@ import com.fr.design.editlock.ConnectionLockChangeChecker; import com.fr.design.editlock.ServerTableDataLockChangeChecker; import com.fr.design.env.DesignerWorkspaceGenerator; import com.fr.design.env.DesignerWorkspaceInfo; -import com.fr.design.env.LocalDesignerWorkspaceInfo; +import com.fr.design.plugin.remind.PluginErrorDesignReminder; import com.fr.design.versioncheck.VersionCheckUtils; import com.fr.env.utils.WorkspaceUtils; import com.fr.event.Event; @@ -16,7 +16,6 @@ import com.fr.event.Listener; import com.fr.event.Null; import com.fr.log.FineLoggerFactory; import com.fr.module.Activator; -import com.fr.stable.StringUtils; import com.fr.value.NotNullLazyValue; import com.fr.workspace.WorkContext; import com.fr.workspace.Workspace; @@ -74,7 +73,8 @@ public class DesignerWorkspaceProvider extends Activator { EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener() { @Override public void on(Event event, Null aNull) { - EnvChangeEntrance.getInstance().pluginErrorRemind(); + PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); + PluginErrorDesignReminder.getInstance().remindInvalidatePlugins(); } }); } diff --git a/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerPluginActivator.java b/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerPluginActivator.java new file mode 100644 index 0000000000..fd6286e33d --- /dev/null +++ b/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerPluginActivator.java @@ -0,0 +1,24 @@ +package com.fr.start.module.optimized; + +import com.fr.module.Activator; +import com.fr.module.ModuleContext; +import com.fr.plugin.PluginActivator; +import com.fr.start.common.DesignerStartupExecutor; + +/** + * created by Harrison on 2022/06/22 + **/ +public class DesignerPluginActivator extends Activator { + + @Override + public void start() { + + DesignerStartupExecutor.getInstance().execute(() -> ModuleContext.getModule(PluginActivator.class).start()); + } + + @Override + public void stop() { + + ModuleContext.getModule(PluginActivator.class).stop(); + } +} diff --git a/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java b/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java new file mode 100644 index 0000000000..12e1e1f7c0 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java @@ -0,0 +1,119 @@ +package com.fr.start.module.optimized; + +import com.fr.design.ui.util.UIUtil; +import com.fr.log.FineLoggerFactory; +import com.fr.module.Activator; +import com.fr.start.SplashContext; +import com.fr.start.common.DesignerStartupContext; +import com.fr.start.module.StartupArgs; +import com.fr.start.util.DesignerStartupPageUtil; +import com.fr.start.warmup.DesignerPreWarmTask; +import com.fr.startup.ui.StartupPageModel; +import com.fr.startup.ui.StartupPageWindow; +import com.fr.third.org.apache.commons.lang3.time.StopWatch; +import com.fr.value.NotNullLazyValue; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.TimeUnit; + +/** + * 设计器起始页启动器 + * 见 设计文档 + * + * created by Harrison on 2022/07/03 + **/ +public class DesignerStartupPageActivator extends Activator { + + private final NotNullLazyValue startupArgsValue = new NotNullLazyValue() { + + @NotNull + @Override + protected StartupArgs compute() { + return findSingleton(StartupArgs.class); + } + }; + + @Override + public void start() { + + DesignerStartupContext context = DesignerStartupContext.getInstance(); + context.setStartupArgs(startupArgsValue.getValue()); + + if (context.isShowStartupPage()) { + showDesignerStartupPage(context); + } else { + DesignerStartupPageUtil.enterWorkspace(); + } + } + + private void showDesignerStartupPage(DesignerStartupContext context) { + + // 启动页关闭 + SplashContext.getInstance().hide(); + + // 预热任务启动 + DesignerPreWarmTask warmTask = new DesignerPreWarmTask(); + warmTask.start(); + + // 即时暂停 + DesignerStartupContext.getRecorder().suspend(); + + UIUtil.invokeLaterIfNeeded(() -> { + + StartupPageModel model = StartupPageModel.create(); + context.setStartupPageModel(model); + + // selectAndOpenLast + model.setOpenLastTemplateRunnable(() -> { + context.setOpenLastFile(true); + launchAfterWarmup(warmTask); + }); + + // selectAndOpenEmpty + model.setOpenEmptyTemplateRunnable(() -> { + context.setOpenEmpty(true); + launchAfterWarmup(warmTask); + }); + + // selectAndCreateNew + model.setCreateNewTemplateRunnable(() -> { + context.setCreateNew(true); + launchAfterWarmup(warmTask); + }); + + StartupPageWindow window = new StartupPageWindow(model); + window.setVisible(true); + context.setOnWaiting(true); + }); + } + + private void launchAfterWarmup(DesignerPreWarmTask warmTask) { + + StopWatch stopWatch = StopWatch.createStarted(); + + try { + DesignerStartupContext.getRecorder().resume(); + + // 等待中切换 + DesignerStartupContext.getInstance().setOnWaiting(false); + + warmTask.join(); + + FineLoggerFactory.getLogger().debug("designer-startup-page warm up cost {} ms", stopWatch.getTime(TimeUnit.MILLISECONDS)); + DesignerStartupContext.getInstance().setOnStartup(true); + DesignerStartupPageUtil.enterWorkspace(); + } finally { + UIUtil.invokeLaterIfNeeded(() -> { + // 换到 awt 线程中关闭,不然异步会出现问题。 + DesignerStartupContext.getInstance().setOnStartup(false); + }); + } + + FineLoggerFactory.getLogger().debug("designer-startup-page started cost {} ms", DesignerStartupContext.getRecorder().getTime(TimeUnit.MILLISECONDS)); + } + + @Override + public void stop() { + + } +} diff --git a/designer-realize/src/main/java/com/fr/start/preload/PreLoadService.java b/designer-realize/src/main/java/com/fr/start/preload/PreLoadService.java new file mode 100644 index 0000000000..b750210749 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/start/preload/PreLoadService.java @@ -0,0 +1,36 @@ +package com.fr.start.preload; + +import com.fr.start.common.DesignerStartupPool; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * created by Harrison on 2022/06/01 + **/ +public class PreLoadService { + + private List> futures = new ArrayList<>(); + + public static PreLoadService getInstance() { + return PreLoadServiceHolder.INSTANCE; + } + + private static class PreLoadServiceHolder { + private static final PreLoadService INSTANCE = new PreLoadService(); + } + + public void addFuture(CompletableFuture future) { + futures.add(future); + } + + public void addRunnable(Runnable runnable) { + futures.add(CompletableFuture.runAsync(runnable, DesignerStartupPool.common())); + } + + public void waitForAll() { + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + } + +} diff --git a/designer-realize/src/main/java/com/fr/start/util/DesignerStartupPageUtil.java b/designer-realize/src/main/java/com/fr/start/util/DesignerStartupPageUtil.java new file mode 100644 index 0000000000..2fd6abad93 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/start/util/DesignerStartupPageUtil.java @@ -0,0 +1,31 @@ +package com.fr.start.util; + +import com.fr.module.ModuleContext; +import com.fr.start.module.DesignerWorkspaceActivator; + +/** + * created by Harrison on 2022/07/11 + **/ +public class DesignerStartupPageUtil { + + /** + * 进入工作目录 + */ + public static void enterWorkspace() { + + ModuleContext + .getModule(DesignerWorkspaceActivator.class) + .start(); + } + + /** + * 退出工作目录 + */ + public static void exitWorkspace() { + + ModuleContext + .getModule(DesignerWorkspaceActivator.class) + .stop(); + } + +} diff --git a/designer-realize/src/main/java/com/fr/start/warmup/DesignerPreWarmTask.java b/designer-realize/src/main/java/com/fr/start/warmup/DesignerPreWarmTask.java new file mode 100644 index 0000000000..0130c3af3d --- /dev/null +++ b/designer-realize/src/main/java/com/fr/start/warmup/DesignerPreWarmTask.java @@ -0,0 +1,47 @@ +package com.fr.start.warmup; + +import com.fr.log.FineLoggerFactory; +import com.fr.start.common.DesignerStartupContext; +import com.fr.start.util.DesignerStartupPageUtil; + +import java.util.concurrent.CompletableFuture; + +/** + * 预热服务 + * + * created by Harrison on 2022/07/03 + **/ +public class DesignerPreWarmTask { + + private CompletableFuture warmupTask = null; + + public void start() { + + if (DesignerStartupContext.getInstance().canWarmup()) { + warmupTask = CompletableFuture.runAsync(() -> { + try { + DesignerStartupContext.getInstance().setOnWarmup(true); + + // 尝试预热,启动关闭 + // 这里测试直接启动/关闭,比等待插件启动更快 + // ps: 这里还有优化空间 + // 方向一:改成单纯的预热,不启动工程 + // 方向二:模块启动可以终止 + DesignerStartupPageUtil.enterWorkspace(); + DesignerStartupPageUtil.exitWorkspace(); + } catch (Exception e) { + FineLoggerFactory.getLogger().debug("designer warm up failed", e); + } finally { + DesignerStartupContext.getInstance().setOnWarmup(false); + } + }); + } + } + + public void join() { + + if (warmupTask != null) { + warmupTask.join(); + } + } +}