@ -0,0 +1,24 @@ |
|||||||
|
package com.fr.base.function; |
||||||
|
|
||||||
|
import com.fr.design.utils.DesignUtils; |
||||||
|
import com.fr.runtime.FineRuntime; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI 终止动作 |
||||||
|
* |
||||||
|
* created by Harrison on 2022/07/14 |
||||||
|
**/ |
||||||
|
public abstract class UITerminator { |
||||||
|
|
||||||
|
public void run() { |
||||||
|
|
||||||
|
// 先执行必须的逻辑
|
||||||
|
FineRuntime.start(); |
||||||
|
DesignUtils.initLookAndFeel(); |
||||||
|
|
||||||
|
// 在执行核心逻辑
|
||||||
|
doRun(); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract void doRun(); |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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 |
||||||
|
* 见 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=416850313">设计文档</a> |
||||||
|
* |
||||||
|
* 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<String> v = new Vector<String>(); |
||||||
|
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<String> 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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
package com.fr.design.update.actions; |
||||||
|
|
||||||
|
|
||||||
|
import com.fr.common.util.Strings; |
||||||
|
import com.fr.design.utils.BrowseUtils; |
||||||
|
import com.fr.general.CloudCenter; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
|
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.ActionListener; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 帮助-更新升级 |
||||||
|
* 点击查看新特性 |
||||||
|
* */ |
||||||
|
public class NewFeatureAction implements ActionListener { |
||||||
|
|
||||||
|
|
||||||
|
public static String DEFAULT_UPDATE_DETAIL_URL = "https://help.fanruan.com/finereport/doc-view-4699.html"; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
try { |
||||||
|
String url = CloudCenter.getInstance().acquireConf("fr.latest.update.detil"); |
||||||
|
if (Strings.isEmpty(url)) { |
||||||
|
url = DEFAULT_UPDATE_DETAIL_URL; |
||||||
|
} |
||||||
|
BrowseUtils.browser(url); |
||||||
|
} catch (Exception ex) { |
||||||
|
FineLoggerFactory.getLogger().error(ex.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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<String> envNameIterator = envManager.getEnvNameIterator(); |
||||||
|
ArrayList<String> 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; |
||||||
|
} |
||||||
|
} |
@ -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<Runnable> 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(); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
package com.fr.startup.ui; |
||||||
|
|
||||||
|
import com.fr.design.DesignerEnvManager; |
||||||
|
import com.fr.design.env.DesignerWorkspaceInfo; |
||||||
|
import com.fr.design.env.DesignerWorkspaceType; |
||||||
|
import com.fr.third.guava.collect.Lists; |
||||||
|
import com.fr.workspace.connect.WorkspaceConnectionInfo; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* created by Harrison on 2022/07/06 |
||||||
|
**/ |
||||||
|
public class StartupPageModel { |
||||||
|
|
||||||
|
private StartupWorkspaceBean selectWorkspaceInfo; |
||||||
|
|
||||||
|
private List<StartupWorkspaceBean> workspaceInfos = new ArrayList<>(); |
||||||
|
|
||||||
|
private Map<String, List<String>> recentFilesMap = new HashMap<>(); |
||||||
|
|
||||||
|
private Runnable openLastTemplateRunnable; |
||||||
|
|
||||||
|
private Runnable createNewTemplateRunnable; |
||||||
|
|
||||||
|
private Runnable openEmptyTemplateRunnable; |
||||||
|
|
||||||
|
public static StartupPageModel create() { |
||||||
|
|
||||||
|
DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); |
||||||
|
Iterator<String> envNameIterator = envManager.getEnvNameIterator(); |
||||||
|
List<StartupWorkspaceBean> infos = Lists.newArrayList(envNameIterator) |
||||||
|
.stream() |
||||||
|
.map((e) -> { |
||||||
|
DesignerWorkspaceInfo workspaceInfo = envManager.getWorkspaceInfo(e); |
||||||
|
if (workspaceInfo.getType() == DesignerWorkspaceType.Remote) { |
||||||
|
WorkspaceConnectionInfo connection = workspaceInfo.getConnection(); |
||||||
|
return new StartupWorkspaceBean(e, connection.getUrl(), workspaceInfo.getType()); |
||||||
|
} else { |
||||||
|
return new StartupWorkspaceBean(e, workspaceInfo.getPath(), workspaceInfo.getType()); |
||||||
|
} |
||||||
|
}) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
Map<String, List<String>> recentFileMap = new HashMap<>(); |
||||||
|
for (StartupWorkspaceBean info : infos) { |
||||||
|
String name = info.getName(); |
||||||
|
List<String> recentFiles = envManager.getRecentOpenedFilePathList4Env(name); |
||||||
|
recentFileMap.put(name, recentFiles); |
||||||
|
} |
||||||
|
return new StartupPageModel(infos, recentFileMap); |
||||||
|
} |
||||||
|
|
||||||
|
public StartupPageModel(List<StartupWorkspaceBean> workspaceInfos, Map<String, List<String>> 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<StartupWorkspaceBean> getWorkspaceInfos() { |
||||||
|
return workspaceInfos; |
||||||
|
} |
||||||
|
|
||||||
|
public void setWorkspaceInfos(List<StartupWorkspaceBean> workspaceInfos) { |
||||||
|
this.workspaceInfos = workspaceInfos; |
||||||
|
} |
||||||
|
|
||||||
|
public Map<String, List<String>> getRecentFilesMap() { |
||||||
|
return recentFilesMap; |
||||||
|
} |
||||||
|
|
||||||
|
public void setRecentFilesMap(Map<String, List<String>> 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; |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
|
||||||
|
/** |
||||||
|
* 启动页 |
||||||
|
* 见<a href="https://kms.fineres.com/pages/viewpage.action?pageId=416850313">设计文档</a> |
||||||
|
* <p> |
||||||
|
* 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<Void, Void> task = new SwingWorker<Void, Void>() { |
||||||
|
@Override |
||||||
|
protected Void doInBackground() throws Exception { |
||||||
|
action.run(); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void done() { |
||||||
|
|
||||||
|
try { |
||||||
|
Void result = get(); |
||||||
|
setVisible(false); |
||||||
|
} catch (Exception e) { |
||||||
|
// 处理错误
|
||||||
|
UIUtil.invokeLaterIfNeeded(() -> { |
||||||
|
UIExpandDialog.Builder() |
||||||
|
.owner(StartupPageWindow.this) |
||||||
|
.title(Toolkit.i18nText("Fine-Design_Basic_Remote_Env_Try")) |
||||||
|
.message(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed")) |
||||||
|
.messageType(UIExpandDialog.WARNING_MESSAGE) |
||||||
|
.detail(e.getMessage()) |
||||||
|
.expand(true) |
||||||
|
.modal(false) |
||||||
|
.build() |
||||||
|
.setVisible(true); |
||||||
|
}); |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
layeredPane.moveToFront(contentPane); |
||||||
|
} finally { |
||||||
|
loadingPane.stop(); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
task.execute(); |
||||||
|
} |
||||||
|
|
||||||
|
private JPanel generateRecentOpenPanel(StartupPageModel pageModel) { |
||||||
|
|
||||||
|
JPanel recentOpenPanel = new JPanel() { |
||||||
|
@Override |
||||||
|
protected void paintComponent(Graphics g) { |
||||||
|
Graphics2D g2d = (Graphics2D) g; |
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
||||||
|
g2d.setColor(Color.WHITE); |
||||||
|
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), StartupPageConstants.ARC_DIAMETER, StartupPageConstants.ARC_DIAMETER); |
||||||
|
} |
||||||
|
}; |
||||||
|
recentOpenPanel.setLayout(new BorderLayout()); |
||||||
|
recentOpenPanel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 6)); |
||||||
|
|
||||||
|
StartupWorkspaceBean workspaceInfo = pageModel.getSelectWorkspaceInfo(); |
||||||
|
JPanel workspaceWrapperYPanel = new JPanel(); |
||||||
|
workspaceWrapperYPanel.setName("workspace-wrapper"); |
||||||
|
{ |
||||||
|
workspaceWrapperYPanel.setLayout(new VerticalFlowLayout()); |
||||||
|
|
||||||
|
JPanel workspaceWrapperXPanel = new JPanel(); |
||||||
|
workspaceWrapperXPanel.setLayout(new FlowLayout()); |
||||||
|
workspaceWrapperXPanel.setBorder(BorderFactory.createEmptyBorder()); |
||||||
|
|
||||||
|
JPanel workspacePanel = new JPanel(); |
||||||
|
workspacePanel.setLayout(new BorderLayout(0, 15)); |
||||||
|
|
||||||
|
UILabel workspaceIcon = new UILabel(StartupPageUtil.getIcon4RecentAreaByWorkspace(workspaceInfo)); |
||||||
|
workspacePanel.add(workspaceIcon, BorderLayout.NORTH); |
||||||
|
|
||||||
|
UILabel nameLabel = new UILabel(workspaceInfo.getName()); |
||||||
|
nameLabel.setHorizontalAlignment(SwingConstants.CENTER); |
||||||
|
workspacePanel.add(nameLabel, BorderLayout.SOUTH); |
||||||
|
workspaceWrapperXPanel.add(workspacePanel); |
||||||
|
Dimension preferredSize = workspaceWrapperXPanel.getPreferredSize(); |
||||||
|
workspaceWrapperXPanel.setPreferredSize(new Dimension(WORKSPACE_PANEL_WIDTH, (int) preferredSize.getHeight())); |
||||||
|
|
||||||
|
workspaceWrapperYPanel.add(workspaceWrapperXPanel); |
||||||
|
} |
||||||
|
recentOpenPanel.add(workspaceWrapperYPanel, BorderLayout.WEST); |
||||||
|
|
||||||
|
JPanel separatorPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||||
|
{ |
||||||
|
JSeparator sep = new JSeparator(); |
||||||
|
sep.setOrientation(JSeparator.VERTICAL); |
||||||
|
sep.setForeground(SEP_COLOR); |
||||||
|
separatorPanel.add(sep, BorderLayout.CENTER); |
||||||
|
} |
||||||
|
recentOpenPanel.add(separatorPanel, BorderLayout.CENTER); |
||||||
|
|
||||||
|
JComponent recentOpenGroupPanel = generateRecentOpenGroupPanel(pageModel, workspaceInfo); |
||||||
|
recentOpenPanel.add(recentOpenGroupPanel, BorderLayout.EAST); |
||||||
|
|
||||||
|
ColorUtils.syncBackground(recentOpenPanel, Color.WHITE); |
||||||
|
|
||||||
|
Dimension preferredSize = recentOpenPanel.getPreferredSize(); |
||||||
|
recentOpenPanel.setPreferredSize(new Dimension(StartupPageConstants.CONTENT_WIDTH, (int) preferredSize.getHeight())); |
||||||
|
|
||||||
|
JPanel recentOpenWrapperPanel = new JPanel(); |
||||||
|
recentOpenWrapperPanel.setName("recentOpenWrapper"); |
||||||
|
recentOpenWrapperPanel.setLayout(new BorderLayout(0, 0)); |
||||||
|
recentOpenWrapperPanel.setBorder(new EmptyBorder(0, 0, 0, 20)); |
||||||
|
recentOpenWrapperPanel.add(recentOpenPanel, BorderLayout.CENTER); |
||||||
|
|
||||||
|
return recentOpenWrapperPanel; |
||||||
|
} |
||||||
|
|
||||||
|
@NotNull |
||||||
|
private JComponent generateRecentOpenGroupPanel(StartupPageModel pageModel, StartupWorkspaceBean workspaceInfo) { |
||||||
|
|
||||||
|
JPanel recentOpenGroupPanel = new JPanel(); |
||||||
|
Map<String, List<String>> recentFilesMap = pageModel.getRecentFilesMap(); |
||||||
|
|
||||||
|
boolean needScroll = false; |
||||||
|
double itemHeight = 0.0d; |
||||||
|
if (!CollectionUtils.isEmpty(recentFilesMap)) { |
||||||
|
String name = workspaceInfo.getName(); |
||||||
|
List<String> 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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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<List<StartupWorkspaceBean>> 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<StartupWorkspaceBean> 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<List<StartupWorkspaceBean>> partitions) { |
||||||
|
|
||||||
|
JPanel workspaceDescPanel = new JPanel(); |
||||||
|
workspaceDescPanel.setLayout(new GridLayout(partitions.size(), 1, 0, ITEM_VERTICAL_GAP)); |
||||||
|
for (List<StartupWorkspaceBean> 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<List<StartupWorkspaceBean>> 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<StartupWorkspaceBean> 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<StartupWorkspaceBean> 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<Color> 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<Color> 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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 407 B |
After Width: | Height: | Size: 407 B |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 561 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 921 B |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 887 B |
After Width: | Height: | Size: 887 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 191 B |
After Width: | Height: | Size: 190 B |
@ -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<String, List<String>> 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); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
package com.fr.start.module.optimized; |
||||||
|
|
||||||
|
import com.fr.design.ui.util.UIUtil; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import com.fr.module.Activator; |
||||||
|
import com.fr.start.SplashContext; |
||||||
|
import com.fr.start.common.DesignerStartupContext; |
||||||
|
import com.fr.start.module.StartupArgs; |
||||||
|
import com.fr.start.util.DesignerStartupPageUtil; |
||||||
|
import com.fr.start.warmup.DesignerPreWarmTask; |
||||||
|
import com.fr.startup.ui.StartupPageModel; |
||||||
|
import com.fr.startup.ui.StartupPageWindow; |
||||||
|
import com.fr.third.org.apache.commons.lang3.time.StopWatch; |
||||||
|
import com.fr.value.NotNullLazyValue; |
||||||
|
import org.jetbrains.annotations.NotNull; |
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
/** |
||||||
|
* 设计器起始页启动器 |
||||||
|
* 见 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=416850313">设计文档</a> |
||||||
|
* |
||||||
|
* created by Harrison on 2022/07/03 |
||||||
|
**/ |
||||||
|
public class DesignerStartupPageActivator extends Activator { |
||||||
|
|
||||||
|
private final NotNullLazyValue<StartupArgs> startupArgsValue = new NotNullLazyValue<StartupArgs>() { |
||||||
|
|
||||||
|
@NotNull |
||||||
|
@Override |
||||||
|
protected StartupArgs compute() { |
||||||
|
return findSingleton(StartupArgs.class); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void start() { |
||||||
|
|
||||||
|
DesignerStartupContext context = DesignerStartupContext.getInstance(); |
||||||
|
context.setStartupArgs(startupArgsValue.getValue()); |
||||||
|
|
||||||
|
if (context.isShowStartupPage()) { |
||||||
|
showDesignerStartupPage(context); |
||||||
|
} else { |
||||||
|
DesignerStartupPageUtil.enterWorkspace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void showDesignerStartupPage(DesignerStartupContext context) { |
||||||
|
|
||||||
|
// 启动页关闭
|
||||||
|
SplashContext.getInstance().hide(); |
||||||
|
|
||||||
|
// 预热任务启动
|
||||||
|
DesignerPreWarmTask warmTask = new DesignerPreWarmTask(); |
||||||
|
warmTask.start(); |
||||||
|
|
||||||
|
// 即时暂停
|
||||||
|
DesignerStartupContext.getRecorder().suspend(); |
||||||
|
|
||||||
|
UIUtil.invokeLaterIfNeeded(() -> { |
||||||
|
|
||||||
|
StartupPageModel model = StartupPageModel.create(); |
||||||
|
context.setStartupPageModel(model); |
||||||
|
|
||||||
|
// selectAndOpenLast
|
||||||
|
model.setOpenLastTemplateRunnable(() -> { |
||||||
|
context.setOpenLastFile(true); |
||||||
|
launchAfterWarmup(warmTask); |
||||||
|
}); |
||||||
|
|
||||||
|
// selectAndOpenEmpty
|
||||||
|
model.setOpenEmptyTemplateRunnable(() -> { |
||||||
|
context.setOpenEmpty(true); |
||||||
|
launchAfterWarmup(warmTask); |
||||||
|
}); |
||||||
|
|
||||||
|
// selectAndCreateNew
|
||||||
|
model.setCreateNewTemplateRunnable(() -> { |
||||||
|
context.setCreateNew(true); |
||||||
|
launchAfterWarmup(warmTask); |
||||||
|
}); |
||||||
|
|
||||||
|
StartupPageWindow window = new StartupPageWindow(model); |
||||||
|
window.setVisible(true); |
||||||
|
context.setOnWaiting(true); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
private void launchAfterWarmup(DesignerPreWarmTask warmTask) { |
||||||
|
|
||||||
|
StopWatch stopWatch = StopWatch.createStarted(); |
||||||
|
|
||||||
|
try { |
||||||
|
DesignerStartupContext.getRecorder().resume(); |
||||||
|
|
||||||
|
// 等待中切换
|
||||||
|
DesignerStartupContext.getInstance().setOnWaiting(false); |
||||||
|
|
||||||
|
warmTask.join(); |
||||||
|
|
||||||
|
FineLoggerFactory.getLogger().debug("designer-startup-page warm up cost {} ms", stopWatch.getTime(TimeUnit.MILLISECONDS)); |
||||||
|
DesignerStartupContext.getInstance().setOnStartup(true); |
||||||
|
DesignerStartupPageUtil.enterWorkspace(); |
||||||
|
} finally { |
||||||
|
UIUtil.invokeLaterIfNeeded(() -> { |
||||||
|
// 换到 awt 线程中关闭,不然异步会出现问题。
|
||||||
|
DesignerStartupContext.getInstance().setOnStartup(false); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
FineLoggerFactory.getLogger().debug("designer-startup-page started cost {} ms", DesignerStartupContext.getRecorder().getTime(TimeUnit.MILLISECONDS)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void stop() { |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -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<CompletableFuture<?>> 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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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<Void> 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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |