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 8301a0ca3..823a551ff 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/actions/file/PreferenceAction.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java index 08273202d..a41f6cb56 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 15f731b77..cf3581e98 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 @@ -18,6 +18,7 @@ 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; @@ -56,6 +57,7 @@ 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; @@ -67,10 +69,12 @@ 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; @@ -183,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; @@ -195,7 +200,7 @@ 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; @@ -215,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); @@ -232,6 +241,8 @@ public class PreferencePane extends BasicPane { createLogPane(advancePane); createLanPane(generalPane); + + createStartupPagePane(generalPane); createLengthPane(advancePane); @@ -296,7 +307,7 @@ 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")); @@ -325,6 +336,14 @@ public class PreferencePane extends BasicPane { 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); @@ -631,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) @@ -820,6 +854,7 @@ public class PreferencePane extends BasicPane { previewResolutionBtnM.setEnabled(enabled); this.cloudAnalyticsDelayCheckBox.setSelected(designerEnvManager.isCloudAnalyticsDelay()); + this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled()); } private int chooseCase(int sign) { @@ -886,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() { 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 000000000..25b0fe181 --- /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 000000000..0a01f8bbf --- /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 4b532b92d..4720c8e10 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/gui/itooltip/UIToolTip.java b/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java index 8db73f8e6..ab6fb70b4 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/layout/FRGUIPaneFactory.java b/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java index 071feee6a..94ad141a4 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,49 @@ public class FRGUIPaneFactory { public static LayoutManager createNColumnGridLayout(int nColumn) { return new FRGridLayout(nColumn); } + + /** + * + * @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 4751649b8..da8f28f60 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/TransparentPane.java b/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java index 8861a7591..26f240698 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/utils/DesignUtils.java b/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java index f9fb484a6..67fb91866 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/start/BaseDesigner.java b/designer-base/src/main/java/com/fr/start/BaseDesigner.java index 97355c8fe..a83800aec 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,18 +123,7 @@ 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()); } @@ -152,21 +140,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 +156,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 000000000..e89598ae2 --- /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 000000000..5aae98f03 --- /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 000000000..b996fbe4b --- /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 000000000..1a033e8cd --- /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 000000000..524c474df --- /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 000000000..5bc55e80c --- /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 000000000..ae27e1a9e --- /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 000000000..84304cc13 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageModel.java @@ -0,0 +1,104 @@ +package com.fr.startup.ui; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.third.guava.collect.Lists; + +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); + 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 000000000..896b42595 --- /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 000000000..4c7135d4a --- /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, 25)); + + 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 000000000..a22c32b03 --- /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 000000000..04d660db9 --- /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_zh.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties index dd6b0623d..e66559302 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,6 +15,7 @@ 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 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 000000000..cccd52cb5 --- /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 000000000..777e87831 --- /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 000000000..0fcdcf70a --- /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 000000000..eaf43b0cf --- /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 000000000..514e4c500 --- /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 000000000..fd61e745b --- /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 000000000..a79e50277 --- /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 000000000..8ea966cbc --- /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 000000000..65f7b7c70 --- /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 000000000..5b4ee1d6f --- /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 000000000..da22546f9 --- /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 000000000..d10b2700a --- /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 000000000..b929630e7 --- /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 000000000..1b7c059d9 --- /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/utils/DevDebugUtils.java b/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java index af1d984ea..60a294d26 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 2d8827755..dcba96f05 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 000000000..c1d33a66a --- /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-realize/src/main/java/com/fr/start/DesignerInitial.java b/designer-realize/src/main/java/com/fr/start/DesignerInitial.java index 39c702af5..83d8a6fbd 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 f65ae11f8..7abf5d963 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 3115781b3..21d5fdf56 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 f60003c9a..ec9be2f39 100644 --- a/designer-realize/src/main/java/com/fr/start/MainDesigner.java +++ b/designer-realize/src/main/java/com/fr/start/MainDesigner.java @@ -32,6 +32,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 +46,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; @@ -63,6 +67,8 @@ import com.fr.stable.lifecycle.FineLifecycleFatalError; import com.fr.stable.xml.XMLTools; import com.fr.start.common.SplashCommon; import com.fr.start.module.StartupArgs; +import com.fr.start.common.DesignerStartupContext; +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 +80,16 @@ 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.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; @@ -110,7 +121,10 @@ public class MainDesigner extends BaseDesigner { */ public static void main(String[] args) { - showSplash(); + DesignerStartupContext.getRecorder().start(); + + startPreload(); + DeepLinkManager.getInstance().start(args); StopWatch watch = new StopWatch(); watch.start(); @@ -125,6 +139,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 +157,29 @@ public class MainDesigner extends BaseDesigner { watch.stop(); } + private static void startPreload() { + + PreLoadService.getInstance().addRunnable(() -> { + if (DesignUtils.isPortOccupied()) { + StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.PORT_OCCUPIED.getId(), + DesignerErrorMessage.PORT_OCCUPIED.getMessage()); + DesignerPort.getInstance().resetPort(); + } + }); + + Runnable fontLoad = () -> { + Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + }; + PreLoadService.getInstance().addRunnable(fontLoad); + + CompletableFuture splashFuture = CompletableFuture.runAsync(() -> { + DesignerEnvManager.getEnvManager(false); + }) + .thenRunAsync(DesignUtils::initLookAndFeel) + .thenRun(MainDesigner::showSplash); + PreLoadService.getInstance().addFuture(splashFuture); + } + 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 cc9eb1933..7fc909c5f 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 74500acc3..2bbb1b152 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 53ef2525e..99d923c6c 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 @@ -137,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. @@ -165,41 +168,60 @@ public class DesignerActivator extends Activator implements Prepare { DesignerMessageHelper.getInstance().prepareShowMessage(); } }); + + 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()); @@ -500,9 +522,9 @@ public class DesignerActivator extends Activator implements Prepare { @Override public void prepare() { - OptimizeUtil.close(() -> { + if (!OptimizeUtil.isOpen()) { LoginAuthServer.getInstance().compatibleStart(); - }); + } ContentReplacerCenter.getInstance().register(); EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener() { @Override @@ -530,7 +552,7 @@ public class DesignerActivator extends Activator implements Prepare { addMutable(PluginEmbedInfo.KEY, DefaultPluginEmbedInfo.create(PLUGIN_EXPORT_IMAGE_SETTING)); } - private void startLoginAuthServer() { + 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 fd8bd9307..ff75e1223 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; @@ -33,14 +32,17 @@ import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.project.ProjectConstants; import com.fr.start.DesignerProcessType; +import com.fr.start.preload.PreLoadService; import com.fr.start.ServerStarter; import com.fr.start.event.LazyStartupEvent; 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,11 @@ 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 +74,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 +92,18 @@ 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; } + + BuildContext.setBuildFilePath("/com/fr/stable/build.properties"); + + registerDaoSelector(); + } @Override 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 000000000..fd6286e33 --- /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 000000000..b639233e5 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java @@ -0,0 +1,116 @@ +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 { + DesignerStartupContext.getInstance().setOnStartup(false); + } + + FineLoggerFactory.getLogger().debug("designer-startup-page started cost {} ms", stopWatch.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 000000000..b75021074 --- /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 000000000..2fd6abad9 --- /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 000000000..0130c3af3 --- /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(); + } + } +}