package com.fr.startup.ui; import com.fr.base.svg.IconUtils; import com.fr.design.DesignerEnvManager; 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.ThemeUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.exit.DesignerExiter; import com.fr.general.GeneralUtils; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; import com.fanruan.product.ProductConstants; import com.fr.stable.collections.CollectionUtils; import com.fr.stable.os.OperatingSystem; import com.fr.start.common.DesignerStartupContext; import com.fr.startup.metric.DesignerMetrics; import org.jetbrains.annotations.NotNull; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JFrame; 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.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.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.util.List; import java.util.Map; /** * 启动页 * 见设计文档 *

* created by Harrison on 2022/07/06 **/ public class StartupPageWindow extends JFrame { 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 = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); private static final BufferedImage BACKGROUND_IMAGE = IOUtils.readImage("com/fr/design/startup/startup_page_background.jpg"); private StartupPageWorkspacePanel workspacePanel; private JPanel recentOpenPanel; private JPanel contentPane; private JPanel body; public StartupPageWindow(StartupPageModel pageModel) { patchUIAction(pageModel); setLayout(new BorderLayout()); initCenter(pageModel); // Workspace-detail setSize(SCREEN_SIZE); setDefaultTitle(); addDefaultListeners(); repaint(); validate(); revalidate(); setFullScreen(); } private void initCenter(StartupPageModel pageModel) { initHeaderPanel(); initWorkspacePanel(pageModel); initRecentOpenPanel(pageModel); initContentPanel(); } private void initHeaderPanel() { this.body = FRGUIPaneFactory.createBorderLayout_S_Pane(); this.body.setBackground(new Color(0, 0, 0, 0)); JPanel headerPanel = createHeader(); this.body.add(headerPanel, BorderLayout.NORTH); } private void initRecentOpenPanel(StartupPageModel pageModel) { this.recentOpenPanel = generateRecentOpenPanel(pageModel); this.body.add(recentOpenPanel, BorderLayout.SOUTH); } private void initContentPanel() { this.contentPane = new JPanel() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(BACKGROUND_IMAGE, 0, 0, SCREEN_SIZE.width, SCREEN_SIZE.height, this); } }; this.contentPane.setLayout(getCenterLayout(body)); this.contentPane.add(this.body, BorderLayout.CENTER); this.contentPane.setPreferredSize(this.body.getPreferredSize()); add(this.contentPane, BorderLayout.CENTER); } private void initWorkspacePanel(StartupPageModel pageModel) { // 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(); } }); } @NotNull private static JPanel createHeader() { // 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); headerPanel.setBackground(new Color(0, 0, 0, 0)); return headerPanel; } /** * 1-mac启动时全屏 * 2-windows 则居中处理 */ private void setFullScreen() { if (OperatingSystem.isMacos()) { this.setLocation(0, 0); this.setSize(SCREEN_SIZE.width, SCREEN_SIZE.height); } else { GUICoreUtils.setWindowFullScreen(this); } } private void addDefaultListeners() { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { DesignerExiter.getInstance().execute(); } }); } private void setDefaultTitle() { StringBuilder sb = new StringBuilder(); sb.append(ProductConstants.APP_NAME); sb.append(" "); sb.append(GeneralUtils.getVersion()); sb.append(" "); sb.append(ProductConstants.BRANCH); sb.append(" "); sb.append(Toolkit.i18nText("Fine-Design_Startup_Page_Title")); setTitle(sb.toString()); } 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) { UIUtil.invokeAndWaitIfNeeded(() -> { // 必须直接初始化 // 见 https://work.fineres.com/browse/REPORT-85293 StartupLoadingPanel loadingPanel = new StartupLoadingPanel(this); loadingPanel.show(); setEnabled(false); 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); setEnabled(true); }); FineLoggerFactory.getLogger().error(e.getMessage(), e); } finally { loadingPanel.hide(); } } }; 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); ColorUtils.syncBackgroundIfAbsent(recentOpenWrapperPanel, new Color(0,0,0,0), ThemeUtils.BACK_COLOR); 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"))); 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); StartupPageUtil.repaintAll(recentOpenGroupPanel); } @Override public void mouseExited(MouseEvent e) { recentFileLabel.setForeground(recentFileLabelForeground); StartupPageUtil.repaintAll(recentOpenGroupPanel); } @Override public void mouseClicked(MouseEvent e) { doOpenLastTemplateAction(recentFile, pageModel); } }); 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_LIMIT)); 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) { StartupPageWorkspacePanel startupPageWorkspacePanel = new StartupPageWorkspacePanel(pageModel); ColorUtils.syncBackgroundIfAbsent(startupPageWorkspacePanel, new Color(0, 0, 0, 0), ThemeUtils.BACK_COLOR); return startupPageWorkspacePanel; } protected LayoutManager getCenterLayout(JComponent centerBody) { return FRGUIPaneFactory.createCenterLayout(centerBody); } private void doOpenLastTemplateAction(String recentFile, StartupPageModel pageModel) { DesignerEnvManager.getEnvManager().setLastOpenFile(recentFile); pageModel.getOpenLastTemplateRunnable().run(); DesignerMetrics designerMetrics = DesignerStartupContext.getInstance().getDesignerMetrics(); designerMetrics.getStatistic().recordOpenLastTemplate(recentFile); } }