diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java index 0175102e0..e61932d7f 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java @@ -1436,6 +1436,7 @@ public abstract class JTemplate> }; button.setToolTipText(getTemplateTheme().getName()); button.setText(getTemplateTheme().getName()); + button.setName(getTemplateTheme().getName()); button.setAlignmentX(SwingConstants.LEFT); button.set4ToolbarButton(); button.setEnabled(true); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java index b07071057..f15b3517f 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java @@ -116,6 +116,7 @@ public class NorthRegionContainerPane extends JPanel { if (!DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isEnabled()) { ad.createAlphaFinePane().setVisible(false); } + northEastPane.add(ad.createGuideEntryPane()); northEastPane.add(ad.createNotificationCenterPane()); OSSupportCenter.buildAction(new OSBasedAction() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java new file mode 100644 index 000000000..5f5747c59 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java @@ -0,0 +1,167 @@ +package com.fr.design.mainframe.guide.base; + +import com.fr.design.mainframe.guide.collect.GuideCollector; +import com.fr.design.mainframe.guide.scene.GuideScene; +import com.fr.design.mainframe.guide.ui.GuideCompleteDialog; +import com.fr.design.mainframe.guide.ui.GuideManageDialog; +import com.fr.stable.StringUtils; + +import javax.swing.SwingUtilities; + +public class Guide { + public enum GuideState { + NONE, DONE + } + private String id; + private String name; + private String description; + private GuideState state; + private GuideView guideView; + private GuideLifecycle lifecycle; + private boolean isComplete; + private GuideScene scene; + + public Guide() { + this(null, null, null); + } + + public Guide(String id, String name, String description) { + this.id = id; + this.name = name; + this.description = description; + this.state = GuideState.NONE; + } + + public String getID() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDescription() { + if (StringUtils.isNotEmpty(description)) { + return description; + } + return name; + } + + public GuideState getState() { + return state; + } + + public void setState(GuideState state) { + this.state = state; + } + + public void setGuideView(GuideView guideView) { + this.guideView = guideView; + } + + public GuideView getGuideView() { + return guideView; + } + + public void setComplete(boolean complete) { + isComplete = complete; + } + + public boolean isComplete() { + return isComplete; + } + + public void setScene(GuideScene scene) { + this.scene = scene; + } + + public GuideScene getScene() { + return scene; + } + + /** + * 开启引导流程 + */ + public void go() { + // 同时只能启动一个引导 + if (GuideManager.getInstance().getCurrentGuide() != null) { + return; + } + try { + if (lifecycle != null && !lifecycle.prepared()) { + return; + } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + start(); + } + }); + } catch (Exception e) { + e.printStackTrace(); + end(); + } + + } + + public void start() { + if (scene != null) { + guideView.setScene(scene); + guideView.showGuide(); + GuideManager.getInstance().setCurrentGuide(this); + if (lifecycle != null) { + lifecycle.onStart(); + } + } else { + complete(); + } + + } + + public void complete() { + if (lifecycle != null) { + lifecycle.onComplete(); + } + setComplete(true); + GuideCollector.getInstance().saveInfo(); + guideView.dismissGuide(); + GuideCompleteDialog.getInstance().showDialog(getName()); + end(); + } + + public void terminate() { + if (lifecycle != null) { + lifecycle.onTerminate(); + } + end(); + } + + public void end() { + GuideManager.getInstance().setCurrentGuide(null); + guideView.dismissGuide(); + if (lifecycle != null) { + lifecycle.onEnd(); + } + GuideManageDialog.getInstance().showDialog(); + } + + public void registerLifecycle(GuideLifecycle lifecycle) { + this.lifecycle = lifecycle; + } + + public void removeGuideLifecycle() { + this.lifecycle = null; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideBuilder.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideBuilder.java new file mode 100644 index 000000000..51aa82118 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideBuilder.java @@ -0,0 +1,46 @@ +package com.fr.design.mainframe.guide.base; + +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.guide.scene.GuideScene; + +public class GuideBuilder { + private Guide guide; + + public static GuideBuilder newInstance() { + return new GuideBuilder(); + } + + public GuideBuilder() { + guide = new Guide(); + guide.setGuideView(new GuideView(DesignerContext.getDesignerFrame(), guide)); + } + + public GuideBuilder setID(String id) { + guide.setId(id); + return this; + } + + public GuideBuilder setName(String name) { + guide.setName(name); + return this; + } + + public GuideBuilder setDescription(String description) { + guide.setDescription(description); + return this; + } + + public GuideBuilder addScene(GuideScene scene) { + guide.setScene(scene); + return this; + } + + public GuideBuilder registerLifecycle(GuideLifecycle lifecycle) { + guide.registerLifecycle(lifecycle); + return this; + } + + public Guide getGuide() { + return guide; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideGroup.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideGroup.java new file mode 100644 index 000000000..25310fb57 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideGroup.java @@ -0,0 +1,51 @@ +package com.fr.design.mainframe.guide.base; + +import java.util.ArrayList; +import java.util.List; + +public class GuideGroup { + private List guideList; + private String id; + private String name; + + public GuideGroup(String id, String name) { + this.id = id; + this.name = name; + guideList = new ArrayList<>(); + } + + public String getID() { + return id; + } + + public String getName() { + return name; + } + + public void addGuide(Guide guide) { + guideList.add(guide); + } + + public List getGuideList() { + return guideList; + } + + public List getCompleteGuideList() { + List complete = new ArrayList<>(); + for (Guide guide : getGuideList()) { + if (guide.isComplete()) { + complete.add(guide); + } + } + return complete; + } + + public boolean isCompleteAll() { + return getCompleteGuideList().size() == getGuideList().size(); + } + + public boolean isCompleteSome() { + List completeGuides = getCompleteGuideList(); + return completeGuides.size() > 0 && completeGuides.size() < getGuideList().size(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideLifecycle.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideLifecycle.java new file mode 100644 index 000000000..2ddfd975f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideLifecycle.java @@ -0,0 +1,32 @@ +package com.fr.design.mainframe.guide.base; + +public interface GuideLifecycle{ + /** + * 准备环境 + * @return 返回true引导可继续执行 + */ + boolean prepared(); + + /** + * 开始引导教程 + */ + void onStart(); + + /** + * 完成引导教程 + */ + + void onComplete(); + + /** + * 终止引导教程 + */ + + void onTerminate(); + + /** + * 结束引导教程 + */ + void onEnd(); + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideLifecycleAdaptor.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideLifecycleAdaptor.java new file mode 100644 index 000000000..c67f47e35 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideLifecycleAdaptor.java @@ -0,0 +1,28 @@ +package com.fr.design.mainframe.guide.base; + +public abstract class GuideLifecycleAdaptor implements GuideLifecycle{ + @Override + public boolean prepared() { + return true; + } + + @Override + public void onStart() { + + } + + @Override + public void onComplete() { + + } + + @Override + public void onTerminate() { + + } + + @Override + public void onEnd() { + + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideManager.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideManager.java new file mode 100644 index 000000000..b14cae486 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideManager.java @@ -0,0 +1,109 @@ +package com.fr.design.mainframe.guide.base; + +import com.fr.design.mainframe.guide.collect.GuideCollector; +import com.fr.stable.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +public class GuideManager { + private static GuideManager guideManager; + + private Guide currentGuide; + private List guideVersionList; + + public static GuideManager getInstance() { + if (guideManager == null) { + guideManager = new GuideManager(); + } + return guideManager; + } + + public GuideManager() { + guideVersionList = new ArrayList<>(); + } + + public Guide getCurrentGuide() { + return currentGuide; + } + + public void setCurrentGuide(Guide currentGuide) { + this.currentGuide = currentGuide; + } + + public void addGuideGroup(String version, GuideGroup guideGroup) { + GuideVersion guideVersion = getGuideVersion(version); + if (guideVersion == null) { + guideVersion = new GuideVersion(version); + guideVersionList.add(guideVersion); + } + guideVersion.addGuideGroup(guideGroup); + } + + public void addGuide(String groupId, Guide guide) { + GuideGroup guideGroup = getGuideGroup(groupId); + if (guideGroup != null) { + guideGroup.addGuide(guide); + } + } + + public List getGuideVersionList() { + return guideVersionList; + } + + public List getAllGuide() { + List guideList = new ArrayList<>(); + for (GuideVersion version : guideVersionList) { + for (GuideGroup group : version.getGuideGroupList()) { + for (Guide guide : group.getGuideList()) { + guideList.add(guide); + } + } + } + return guideList; + } + + public GuideVersion getGuideVersion(String version) { + for (GuideVersion guideVersion : guideVersionList) { + if (StringUtils.equals(version, guideVersion.getVersion())) { + return guideVersion; + } + } + return null; + } + + public GuideGroup getGuideGroup(String groupId) { + for (GuideVersion version : guideVersionList) { + for (GuideGroup group : version.getGuideGroupList()) { + if (StringUtils.equals(groupId, group.getID())) { + return group; + } + } + } + return null; + } + + public Guide getGuide(String guideId) { + for (GuideVersion version : guideVersionList) { + for (GuideGroup group : version.getGuideGroupList()) { + for (Guide guide : group.getGuideList()) { + if (StringUtils.equals(guideId, guide.getID())) { + return guide; + } + } + } + } + return null; + } + + public void completeAll() { + for (GuideVersion version : guideVersionList) { + for (GuideGroup group : version.getGuideGroupList()) { + for (Guide guide : group.getGuideList()) { + guide.setComplete(true); + } + } + } + GuideCollector.getInstance().saveInfo(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideVersion.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideVersion.java new file mode 100644 index 000000000..3c365aa94 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideVersion.java @@ -0,0 +1,29 @@ +package com.fr.design.mainframe.guide.base; + +import java.util.ArrayList; +import java.util.List; + +public class GuideVersion { + private String version; + private List guideGroupList; + public GuideVersion(String version) { + guideGroupList = new ArrayList<>(); + this.version = version; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List getGuideGroupList() { + return guideGroupList; + } + + public void addGuideGroup(GuideGroup guideGroup) { + guideGroupList.add(guideGroup); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java new file mode 100644 index 000000000..22fbfbd5e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java @@ -0,0 +1,124 @@ +package com.fr.design.mainframe.guide.base; + +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.guide.scene.AbstractGuideScene; +import com.fr.design.mainframe.guide.scene.GuideScene; + +import javax.swing.JDialog; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Window; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; + +public class GuideView extends JDialog { + private static GuideView guideView; + private Guide invoker; + private GuideScene scene; + private Color modalColor; + private float modalOpacity; + private Window window; + + public static GuideView getInstance(Guide guide) { + if (guideView == null) { + guideView = new GuideView(DesignerContext.getDesignerFrame(), guide); + } + return guideView; + } + + public GuideView(Window window) { + super(window); + this.setUndecorated(true); + this.window = window; + this.modalColor = Color.BLACK; + this.modalOpacity = 0.4f; + this.setPreferredSize(window.getSize()); + this.setSize(window.getSize()); + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + setBg(); + } + + private WindowFocusListener windowFocusListener = new WindowFocusListener() { + @Override + public void windowGainedFocus(WindowEvent e) { + requestFocus(); + setLocationRelativeTo(window); + } + + @Override + public void windowLostFocus(WindowEvent e) { + + } + }; + + private ComponentListener componentListener = new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + setLocationRelativeTo(window); + } + + @Override + public void componentMoved(ComponentEvent e) { + setLocation(window.getLocation()); + } + }; + + public GuideView(Window window, Guide guide) { + this(window); + this.invoker = guide; + } + + public void setModalColor(Color color) { + modalColor = color; + setBg(); + } + + public void setModalOpacity(float opacity){ + modalOpacity = opacity; + setBg(); + } + + private void setBg() { + Color newColor = new Color(modalColor.getRed(), modalColor.getGreen(), modalColor.getBlue(), (int) (255 * modalOpacity)); + this.setBackground(newColor); + } + + public void setScene(GuideScene scene) { + if (scene instanceof AbstractGuideScene) { + ((AbstractGuideScene) scene).setContainer(this); + } + this.scene = scene; + } + + public void showGuide() { + window.addComponentListener(componentListener); + window.addWindowFocusListener(windowFocusListener); + this.setLocationRelativeTo(window); + this.setSize(window.getSize()); + this.setLocation(window.getLocation()); + this.setVisible(true); + if (scene != null) { + scene.start(); + } else { + GuideManager.getInstance().getCurrentGuide().complete(); + } + } + + public void dismissGuide() { + window.removeComponentListener(componentListener); + window.removeWindowFocusListener(windowFocusListener); + this.getLayeredPane().removeAll(); + revalidate(); + repaint(); + setVisible(false); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/collect/GuideCollector.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/collect/GuideCollector.java new file mode 100644 index 000000000..b1d85761c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/collect/GuideCollector.java @@ -0,0 +1,155 @@ +package com.fr.design.mainframe.guide.collect; + +import com.fr.base.io.XMLReadHelper; +import com.fr.design.mainframe.guide.base.Guide; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ProductConstants; +import com.fr.stable.StableUtils; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLReadable; +import com.fr.stable.xml.XMLTools; +import com.fr.stable.xml.XMLable; +import com.fr.stable.xml.XMLableReader; +import com.fr.third.javax.xml.stream.XMLStreamException; +import com.fr.third.org.apache.commons.io.FileUtils; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class GuideCollector implements XMLable { + private static final String ROOT_XML = "GuideCollector"; + private static final String GUIDE_XML = "Guide"; + private static final String FILE_NAME = "guide.info"; + private static GuideCollector collector; + + private boolean showHint; + private List cacheGuides; + + public static GuideCollector getInstance() { + if (collector == null) { + collector = new GuideCollector(); + } + return collector; + } + + public GuideCollector() { + cacheGuides = new ArrayList<>(); + } + + public boolean isShowHint() { + return showHint; + } + + public void setShowHint(boolean showHint) { + this.showHint = showHint; + saveInfo(); + } + + public void load() { + for(Guide cacheGuide : cacheGuides) { + Guide guide = GuideManager.getInstance().getGuide(cacheGuide.getID()); + if (guide != null) { + guide.setComplete(cacheGuide.isComplete()); + } + } + } + + public void saveInfo() { + cacheGuides = GuideManager.getInstance().getAllGuide(); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + XMLTools.writeOutputStreamXML(this, out); + out.flush(); + out.close(); + String fileContent = new String(out.toByteArray(), StandardCharsets.UTF_8); + FileUtils.writeStringToFile(getInfoFile(), fileContent, StandardCharsets.UTF_8); + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage()); + } + } + + private File getInfoFile() { + File file = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), FILE_NAME)); + try { + if (!file.exists()) { + file.createNewFile(); + } + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + return file; + } + + public void loadFromFile() { + if (!getInfoFile().exists()) { + return; + } + XMLableReader reader = null; + try (InputStream in = new FileInputStream(getInfoFile())) { + reader = XMLReadHelper.createXMLableReader(in, XMLPrintWriter.XML_ENCODER); + if (reader == null) { + return; + } + reader.readXMLObject(this); + } catch (FileNotFoundException e) { + } catch (XMLStreamException | IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (XMLStreamException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } + + @Override + public void readXML(XMLableReader xmLableReader) { + String tagName = xmLableReader.getTagName(); + if (tagName.equals(ROOT_XML)) { + showHint = xmLableReader.getAttrAsBoolean("showHint", false); + xmLableReader.readXMLObject(new XMLReadable() { + public void readXML(XMLableReader reader) { + String tagName = reader.getTagName(); + if (tagName.equals(GUIDE_XML)) { + Guide guide = new Guide(); + guide.setId(reader.getAttrAsString("id", null)); + guide.setComplete(reader.getAttrAsBoolean("isComplete", false)); + cacheGuides.add(guide); + } + + } + }); + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(ROOT_XML); + writer.attr("showHint", showHint); + for(Guide guide : GuideManager.getInstance().getAllGuide()) { + writer.startTAG(GUIDE_XML); + writer.attr("id", guide.getID()); + writer.attr("isComplete", guide.isComplete()); + writer.end(); + } + writer.end(); + + + } + + @Override + public Object clone() throws CloneNotSupportedException { + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java new file mode 100644 index 000000000..e3f844c5f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java @@ -0,0 +1,478 @@ +package com.fr.design.mainframe.guide.scene; + +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.design.mainframe.guide.base.GuideView; +import com.fr.design.mainframe.guide.utils.ScreenImage; +import com.fr.design.mainframe.guide.tip.BubbleTip; +import com.fr.design.mainframe.guide.tip.GuideTip; +import com.fr.stable.StringUtils; + +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import java.awt.AWTException; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Component; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractGuideScene extends JPanel implements GuideScene { + private static final int DEFAULT_ARROW_HEIGHT = 12; + private static final int DEFAULT_ARROW_WIDTH = 18; + + private GuideScene nextScene; + private SceneFilter sceneFilter; + private GuideSceneLifecycle lifecycle; + private GuideView container; + private List targetList; + private List highlightList; + private Component nextButton; + private List pointsList; + + + public AbstractGuideScene() { + this.setLayout(null); + this.setOpaque(false); + targetList = new ArrayList<>(); + highlightList = new ArrayList<>(); + pointsList = new ArrayList<>(); + } + + /** + * 根据设计器上组件添加高亮区域视图, + * JComponent 采用组件绘制方式 + * Component 采用屏幕截图方式 + * @param component 设计器组件对象 + * @return + */ + public boolean addTarget(Component component) { + try { + if (component == null || container == null) { + return false; + } + + Point point = SwingUtilities.convertPoint(component,0,0, container.getRootPane()); + Rectangle rectangle = new Rectangle(point, component.getSize()); + BufferedImage image; + + if (component instanceof JComponent) { + JComponent jComponent = (JComponent) component; + image = ScreenImage.createImage(jComponent); + } else { + image = captureImage(component); + showContainer(); + } + targetList.add(component); + highlightList.add(getTargetComponentWithImage(image, rectangle)); + return true; + } catch (AWTException e) { + e.printStackTrace(); + GuideManager.getInstance().getCurrentGuide().terminate(); + return false; + } + } + + /** + * 根据设计器上选定区域获取高亮视图,采用截屏的方式 + * @param rectangle 选定区域,相对屏幕 + * @return + */ + public boolean addTarget(Rectangle rectangle) { + try { + targetList.add(null); + BufferedImage image = captureImage(rectangle); + highlightList.add(getTargetComponentWithImage(image, rectangle)); + return true; + } catch (AWTException e) { + e.printStackTrace(); + GuideManager.getInstance().getCurrentGuide().terminate(); + return false; + } + } + + /** + * 根据设计器组件,选定其中某个区域,添加高亮视图 + * @param component 设计器组件 + * @param origin 相对组件的区域 + * @return + */ + public boolean addTarget(Component component, Rectangle origin) { + try { + if (component == null) { + return false; + } + Point point = SwingUtilities.convertPoint(component,0,0, container.getRootPane()); + + origin = origin.intersection(new Rectangle(0,0,component.getWidth(), component.getHeight())); + Rectangle rectangle = new Rectangle(point.x + origin.x, point.y + origin.y, origin.width, origin.height); + + BufferedImage image; + + if (component instanceof JComponent) { + JComponent jComponent = (JComponent) component; + image = ScreenImage.createImage(jComponent, origin); + } else { + image = ScreenImage.createImage(component).getSubimage(origin.x, origin.y, origin.width, origin.height); + } + targetList.add(component); + highlightList.add(getTargetComponentWithImage(image, rectangle)); + return true; + } catch (AWTException e) { + e.printStackTrace(); + GuideManager.getInstance().getCurrentGuide().terminate(); + return false; + } + } + + /** + * 添加自定义组件 + * @param component 自定义组件 + * @param rectangle 相对引导页的区域 + * @return + */ + public boolean addCustomTarget(Component component, Rectangle rectangle) { + if (component == null) { + return false; + } + component.setBounds(rectangle); + targetList.add(component); + highlightList.add(component); + return true; + } + + public boolean addCustomTarget(Component component, Point location) { + return addCustomTarget(component, new Rectangle(location, component.getPreferredSize())); + } + + protected List getTargetList() { + return targetList; + } + + public List getHighlightList() { + return highlightList; + } + + private UILabel getTargetComponentWithImage(BufferedImage image, Rectangle rectangle) { + ImageIcon ic = new ImageIcon(image); + UILabel label = new UILabel(ic); + label.setOpaque(true); + label.setBounds(rectangle); + return label; + } + + private BufferedImage captureImage(Rectangle rectangle) throws AWTException { + container.setVisible(false); + BufferedImage image = ScreenImage.createImage(rectangle); + showContainer(); + return image; + } + + private BufferedImage captureImage(Component component) throws AWTException { + container.setVisible(false); + BufferedImage image = ScreenImage.createImage(component); + showContainer(); + return image; + } + + private void showContainer() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + container.setVisible(true); + container.toFront(); + container.requestFocus(); + } + }); + } + + + /** + * 自定义位置添加气泡提示组件 + * @param title 提示标题 + * @param content 提示内容 + * @param direction 气泡窗口位置方向 + * @param anchor 气泡窗口箭头坐标 + * @param bubbleTailStart 气泡窗口箭头坐标相对于位置方向交叉轴的比例(从左到右,从上到下) + */ + public void addBubbleTip(String title,String content, GuideTip.Direction direction, Point anchor, float bubbleTailStart) { + BubbleTip bt = new BubbleTip(title, content, direction, bubbleTailStart); + bt.setAnchor(anchor); + this.add(bt.getTip()); + } + + /** + * 以上一个添加的引导目标窗口为基础,添加对应的气泡窗 + * @param title 提示标题 + * @param content 提示内容 + * @param direction + * @param anchorStart + * @param bubbleTailStart + */ + public void addBubbleTip(String title, String content, GuideTip.Direction direction, float anchorStart, float bubbleTailStart) { + if (highlightList.size() == 0) { + return; + } + Component lastTarget = highlightList.get(highlightList.size() - 1); + Rectangle bounds = lastTarget.getBounds(); + Point anchor = new Point(0,0); + if (direction == GuideTip.Direction.TOP) { + anchor = new Point(bounds.x + (int)(bounds.width * anchorStart), bounds.y); + } else if (direction == GuideTip.Direction.BOTTOM) { + anchor = new Point(bounds.x + (int)(bounds.width * anchorStart), bounds.y + bounds.height); + } else if (direction == GuideTip.Direction.LEFT) { + anchor = new Point(bounds.x, bounds.y + (int)(bounds.height * anchorStart)); + } else if (direction == GuideTip.Direction.RIGHT) { + anchor = new Point(bounds.x + bounds.width, bounds.y + (int) (bounds.height * anchorStart)); + } + addBubbleTip(title, content, direction, anchor, bubbleTailStart); + } + + public void addBubbleTip(String title, String content, GuideTip.Direction direction) { + addBubbleTip(title, content, direction, 0.5f, 0.5f); + } + + public void addBubbleTip(String title, GuideTip.Direction direction) { + addBubbleTip(title, StringUtils.EMPTY, direction); + } + + public void addTip(GuideTip tip) { + this.add(tip.getTip()); + } + + public void addLineArrow(Point... points) { + pointsList.add(points); + } + + public void setContainer(GuideView container) { + this.container = container; + } + + public GuideView getContainer() { + return container; + } + + @Override + public GuideScene nextScene(GuideScene scene) { + nextScene = scene; + return nextScene; + } + + @Override + public void addSceneFilter(SceneFilter filter) { + sceneFilter = filter; + } + + @Override + public void start() { + clear(); + showContainer(); + if (lifecycle != null && !lifecycle.prepared()) { + return; + } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showScene(); + } + }); + } + + @Override + public void showScene() { + if (container != null) { + container.setContentPane(this); + this.setBounds(0, 0 , getSceneWidth(), getSceneWidth()); + + // show target + for (int index = highlightList.size() - 1; index >= 0; index--) { + this.add(highlightList.get(index)); + } + // show next button + if (nextButton != null) { + nextButton.setBounds((getSceneWidth() - 60) / 2, getSceneHeight() - 100, 60, 30); + this.add(nextButton); + } + + container.revalidate(); + container.repaint(); + } + if (lifecycle != null) { + lifecycle.onShow(); + } + } + + @Override + public void complete() { + container.getLayeredPane().remove(this); + container.repaint(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (lifecycle != null) { + lifecycle.onComplete(); + } + if (sceneFilter != null) { + nextScene = sceneFilter.getFilterScene(); + } + if (nextScene != null) { + if (nextScene instanceof AbstractGuideScene) { + ((AbstractGuideScene) nextScene).setContainer(container); + } + nextScene.start(); + } else { + GuideManager.getInstance().getCurrentGuide().complete(); + } + + } + }); + } + + @Override + public void registerLifecycle(GuideSceneLifecycle lifecycle) { + this.lifecycle = lifecycle; + } + + @Override + public void removeLifecycle() { + this.lifecycle = null; + } + + public void showNextButton() { + UIButton nextButton = new UIButton("Next"); + nextButton.setPreferredSize(new Dimension(60, 30)); + nextButton.setOpaque(false); + nextButton.setFont(nextButton.getFont().deriveFont(20)); + nextButton.setRoundBorder(true, 8); + nextButton.setForeground(Color.WHITE); + nextButton.setNormalPainted(false); + nextButton.setPressedPainted(false); + nextButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + complete(); + } + }); + this.nextButton = nextButton; + } + + private int getSceneWidth() { + if (container == null) { + return 0; + } + return container.getLayeredPane().getWidth(); + + } + + private int getSceneHeight() { + if (container == null) { + return 0; + } + return container.getLayeredPane().getHeight(); + } + + private void clear() { + targetList = new ArrayList<>(); + highlightList = new ArrayList<>(); + this.nextButton = null; + this.removeAll(); + invalidate(); + repaint(); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + if (pointsList.isEmpty()) { + return; + } + Graphics2D g2d = (Graphics2D) g; + Composite oldComposite = g2d.getComposite(); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + g2d.setColor(Color.WHITE); + for (Point[] points : pointsList) { + if (points.length <= 1) { + continue; + } + Point startPoint = points[0]; + Point endPoint = startPoint; + for (int index = 1; index < points.length; index++) { + startPoint = endPoint; + endPoint = points[index]; + g2d.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y); + } + + drawArrow(g2d, startPoint, endPoint); + } + g2d.setComposite(oldComposite); + } + + /** + * 根据最后两点坐标计算出三角箭头的三个点坐标,绘制箭头 + * 这里实现以终点坐标为坐标轴圆点计算 + * @param start 起始点坐标 + * @param end 重点坐标 + */ + private void drawArrow(Graphics2D g2d, Point start, Point end) { + try{ + double dealtPointX = start.x - end.x; + double dealtPointY = -(start.y - end.y); + + double pointDistance = calDistance(dealtPointX, dealtPointY); + double triangleHeight = Math.min(DEFAULT_ARROW_HEIGHT, pointDistance); + double triangleWidth = triangleHeight * (DEFAULT_ARROW_WIDTH / 2) / DEFAULT_ARROW_WIDTH; + if (triangleHeight < 1 || triangleWidth < 1 || pointDistance < 1) { + return; + } + + double pointAngle; + double abs = 1; + if (dealtPointX == 0) { + pointAngle = Math.PI / 2; + } else { + pointAngle = Math.atan(dealtPointY / dealtPointX); + } + if (dealtPointY < 0) { + pointAngle += Math.PI; + abs = -1; + } + + double deltaAngle = Math.atan(triangleWidth / triangleHeight); + double triangleDistance = calDistance(triangleWidth, triangleHeight); + + Point p1 =calPoint(end, triangleDistance, pointAngle - deltaAngle, abs); + Point p2 = calPoint(end, triangleDistance, pointAngle + deltaAngle, abs); + + int xPoints[] = {end.x, p1.x, p2.x}; + int yPoints[] = {end.y, p1.y, p2.y}; + + g2d.fillPolygon(xPoints, yPoints, 3); + } catch (Exception e) { + e.printStackTrace(); + GuideManager.getInstance().getCurrentGuide().terminate(); + } + } + + private double calDistance(double x, double y) { + return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + } + + private Point calPoint(Point relativePoint, double distance, double angle, double abs) { + int x = (int)(relativePoint.x + abs * distance * Math.cos(angle)); + int y = (int)(relativePoint.y - abs * distance * Math.sin(angle)); + return new Point(x, y); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java new file mode 100644 index 000000000..234783fa4 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java @@ -0,0 +1,101 @@ +package com.fr.design.mainframe.guide.scene; + +import com.fr.design.mainframe.guide.base.GuideManager; + +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class ClickScene extends AbstractGuideScene{ + public enum ClickType { + LEFT, LEFT_DOUBLE, RIGHT + } + + public void addClickTarget(Component component, ClickType clickType) { + addClickTarget(component, clickType, false); + } + + public void addClickTarget(Component component, ClickType clickType, boolean isDispatch) { + if (super.addTarget(component)) { + addTargetClickListener(clickType, isDispatch); + } + } + + public void addClickTarget(Rectangle rectangle, ClickType clickType) { + if (super.addTarget(rectangle)) { + addTargetClickListener(clickType,false); + } + } + + public void addClickTarget(Component component, Rectangle rectangle, ClickType clickType) { + if (super.addTarget(component, rectangle)) { + addTargetClickListener(clickType, false); + } + } + + public void addCustomClickTarget(Component component, Rectangle rectangle, ClickType clickType) { + if (super.addCustomTarget(component, rectangle)) { + addTargetClickListener(clickType, false); + } + } + + public void addCustomClickTarget(Component component, Point location, ClickType clickType) { + if (super.addCustomTarget(component, location)) { + addTargetClickListener(clickType, false); + } + } + + private void addTargetClickListener(ClickType clickType, boolean isDispatch) { + Component highlight = getHighlightList().get(getHighlightList().size() - 1); + Component target = getTargetList().get(getTargetList().size() - 1); + highlight.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + if ((e.getClickCount() == 1 && clickType == ClickType.LEFT) || (e.getClickCount() == 2 && clickType == ClickType.LEFT_DOUBLE)) { + if (isDispatch) { + redispatchMouseEvent(e, target); + } + complete(); + } + } else if (e.getButton() == MouseEvent.BUTTON3 && clickType == ClickType.RIGHT) { + if (isDispatch) { + redispatchMouseEvent(e, target); + } + complete(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + if (isDispatch) { + redispatchMouseEvent(e, target); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (isDispatch) { + redispatchMouseEvent(e, target); + } + } + }); + } + + private void redispatchMouseEvent(MouseEvent e, Component component) { + component.dispatchEvent(new MouseEvent(component, e.getID(), e + .getWhen(), e.getModifiers(), e.getX(), + e.getY(), e.getClickCount(), e.isPopupTrigger())); + } + + @Override + public void showScene() { + super.showScene(); + // 交互类的 scene 如果没有高亮内容块载,需要及时终止Guide,否则就没法去掉模态框影响到设计器主功能的使用了 + if (this.getComponentCount() == 0) { + GuideManager.getInstance().getCurrentGuide().terminate(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/DisplayScene.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/DisplayScene.java new file mode 100644 index 000000000..1c44012d1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/DisplayScene.java @@ -0,0 +1,33 @@ +package com.fr.design.mainframe.guide.scene; + +import java.util.Timer; +import java.util.TimerTask; + +public class DisplayScene extends AbstractGuideScene { + private long delay; + private static final long DEFAULT_DELAY = 1000; + + public DisplayScene() { + this(DEFAULT_DELAY); + } + + public DisplayScene(long delay) { + super(); + this.delay = delay; + } + + public void setDelay(long delay) { + this.delay = delay; + } + + @Override + public void showScene() { + super.showScene(); + // 实例化Timer类 + new Timer().schedule(new TimerTask() { + public void run() { + complete(); + } + }, delay); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/DragScene.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/DragScene.java new file mode 100644 index 000000000..c6a36d2ef --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/DragScene.java @@ -0,0 +1,63 @@ +package com.fr.design.mainframe.guide.scene; + +import com.fr.design.mainframe.guide.scene.drag.DragAndDropDragGestureListener; + +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDropEvent; + +public class DragScene extends AbstractGuideScene{ + public enum DragType{ + NONE, FROM, TO + } + + public void addDragTarget(Component component, DragType type) { + if (super.addTarget(component)) { + addDragTargetListener(type); + } + } + + public void addDragTarget(Rectangle rectangle, DragType type) { + if (super.addTarget(rectangle)) { + addDragTargetListener(type); + } + } + + public void addDragTarget(Component component, Rectangle rectangle, DragType type) { + if (super.addTarget(component, rectangle)) { + addDragTargetListener(type); + } + } + + public void addCustomDragTarget(Component component, Rectangle rectangle, DragType type) { + if (super.addCustomTarget(component, rectangle)) { + addDragTargetListener(type); + } + } + + private void addDragTargetListener(DragType dragType) { + Component target = getHighlightList().get(getHighlightList().size() - 1); + + if (dragType == DragType.FROM) { + new DragAndDropDragGestureListener(target, DnDConstants.ACTION_COPY_OR_MOVE){ + @Override + public void dragDropEnd(DragSourceDropEvent dsde) { + complete(); + } + }; + } else if (dragType == DragType.TO) { + target.setDropTarget(new DropTarget()); + } + } + + private class DropSceneTarget extends DropTarget { + @Override + public synchronized void drop(DropTargetDropEvent dtde) { + super.drop(dtde); + complete(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideScene.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideScene.java new file mode 100644 index 000000000..e62ca4d9a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideScene.java @@ -0,0 +1,18 @@ +package com.fr.design.mainframe.guide.scene; + + +public interface GuideScene { + GuideScene nextScene(GuideScene scene); + + void addSceneFilter(SceneFilter filter); + + void start(); + + void showScene(); + + void complete(); + + void registerLifecycle(GuideSceneLifecycle lifecycle); + + void removeLifecycle(); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideSceneLifecycle.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideSceneLifecycle.java new file mode 100644 index 000000000..9b9e07278 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideSceneLifecycle.java @@ -0,0 +1,20 @@ +package com.fr.design.mainframe.guide.scene; + +public interface GuideSceneLifecycle { + /** + * 引导场景准备工作 + * 给 scene 添加 target 应该在这个阶段处理 + * @return + */ + boolean prepared(); + + /** + * scene 显示后 + */ + void onShow(); + + /** + * scene 完成后 + */ + void onComplete(); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideSceneLifecycleAdaptor.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideSceneLifecycleAdaptor.java new file mode 100644 index 000000000..06c40ad11 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/GuideSceneLifecycleAdaptor.java @@ -0,0 +1,18 @@ +package com.fr.design.mainframe.guide.scene; + +public abstract class GuideSceneLifecycleAdaptor implements GuideSceneLifecycle { + @Override + public boolean prepared() { + return true; + } + + @Override + public void onShow() { + + } + + @Override + public void onComplete() { + + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/SceneFilter.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/SceneFilter.java new file mode 100644 index 000000000..ea4ccf28f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/SceneFilter.java @@ -0,0 +1,5 @@ +package com.fr.design.mainframe.guide.scene; + +public interface SceneFilter { + GuideScene getFilterScene(); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/drag/DragAndDropDragGestureListener.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/drag/DragAndDropDragGestureListener.java new file mode 100644 index 000000000..25979925d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/drag/DragAndDropDragGestureListener.java @@ -0,0 +1,60 @@ +package com.fr.design.mainframe.guide.scene.drag; + +import com.fr.general.ComparatorUtils; +import org.jetbrains.annotations.NotNull; + +import java.awt.Component; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; + +public class DragAndDropDragGestureListener extends DragSourceAdapter implements DragGestureListener { + private Component component; + + public DragAndDropDragGestureListener(Component component, int actions) { + this.component = component; + DragSource source = new DragSource(); + source.createDefaultDragGestureRecognizer(component, actions, this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + if (component != null) { + try { + DragAndDropTransferable dragAndDropTransferable = new DragAndDropTransferable(component); + dge.startDrag(DragSource.DefaultCopyDrop, dragAndDropTransferable, this); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private static class DragAndDropTransferable implements Transferable { + private Component component; + + public DragAndDropTransferable(Component component) { + this.component = component; + } + + DataFlavor[] flavors = {new DataFlavor(Component.class, "Component")}; + + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + for (DataFlavor df : flavors) { + if (ComparatorUtils.equals(df, flavor)) { + return true; + } + } + return false; + } + @NotNull + public Object getTransferData(DataFlavor df) { + return component; + } + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java new file mode 100644 index 000000000..1d56fa534 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java @@ -0,0 +1,97 @@ +package com.fr.design.mainframe.guide.tip; + +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.mainframe.guide.base.Guide; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.design.mainframe.guide.ui.bubble.Bubble; +import com.fr.design.mainframe.guide.ui.bubble.BubbleWithClose; + +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class BubbleTip implements GuideTip { + private BubbleWithClose bubbleBox; + private Point anchor; + + /** + * + * @param title 标题 + * @param content 内容 + * @param direction 气泡提示相对anchor的方向,这里方向会和气泡组件箭头方向相反 + * @param tailStart 气泡尾巴相对当前边垂直方向偏移位置比例,值在0-1范围 + */ + public BubbleTip(String title, String content, Direction direction, float tailStart) { + bubbleBox = new BubbleWithClose(title, content, getBubbleBoxTailDirection(direction), tailStart); + bubbleBox.addCloseActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Guide currentGuide = GuideManager.getInstance().getCurrentGuide(); + if (currentGuide != null) { + + int returnVal = FineJOptionPane.showConfirmDialog( + currentGuide.getGuideView(), + "确认退出当前教学引导?", + Toolkit.i18nText("Fine-Design_Basic_Confirm"), + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (returnVal == JOptionPane.YES_OPTION) { + currentGuide.terminate(); + } + } + } + }); + } + @Override + public JComponent getTip() { + if(anchor == null) { + return new BubbleWithClose(bubbleBox.getTitle(), bubbleBox.getContent(), Bubble.TailDirection.TOP, 0); + } else { + setBubbleBoxBound(); + return bubbleBox; + } + } + + /** + * 设置锚点坐标 + * 这里可以指定气泡组件箭头坐标的箭头坐标 + * @param anchor + */ + public void setAnchor(Point anchor) { + this.anchor = anchor; + } + + private void setBubbleBoxBound() { + int bubbleW = bubbleBox.getPreferredSize().width; + int bubbleH = bubbleBox.getPreferredSize().height; + if (bubbleBox.isTailHorizontal()) { + int x = bubbleBox.isTailLeft() ? anchor.x : anchor.x - bubbleW; + int y = anchor.y - (int) (bubbleH * bubbleBox.getTailStart()); + bubbleBox.setBounds(x, y, bubbleW, bubbleH); + } else if (bubbleBox.isTailVertical()) { + int x = anchor.x - (int) (bubbleW * bubbleBox.getTailStart()); + int y = bubbleBox.isTailTop() ? anchor.y : anchor.y - bubbleH; + bubbleBox.setBounds(x, y, bubbleW, bubbleH); + } + } + + private Bubble.TailDirection getBubbleBoxTailDirection(Direction direction) { + switch (direction) { + case TOP: + return Bubble.TailDirection.BOTTOM; + case BOTTOM: + return Bubble.TailDirection.TOP; + case LEFT: + return Bubble.TailDirection.RIGHT; + case RIGHT: + default: + return Bubble.TailDirection.LEFT; + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/GuideTip.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/GuideTip.java new file mode 100644 index 000000000..e1573601f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/GuideTip.java @@ -0,0 +1,14 @@ +package com.fr.design.mainframe.guide.tip; + +import javax.swing.JComponent; +import java.awt.Point; + +public interface GuideTip { + enum Direction { + TOP, BOTTOM, LEFT, RIGHT + } + + JComponent getTip(); + + void setAnchor(Point anchor); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHint.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHint.java new file mode 100644 index 000000000..56f978731 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHint.java @@ -0,0 +1,74 @@ +package com.fr.design.mainframe.guide.ui; + +import com.fr.design.gui.ibutton.UIButton; +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.mainframe.guide.ui.bubble.Bubble; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.ActionListener; + +public class BubbleHint extends Bubble { + private UIButton confirmButton; + + public BubbleHint() { + super(TailDirection.TOP, 0.9f); + initComponent(); + } + + private void initComponent() { + this.setLayout(new BorderLayout()); + this.setBorder(BorderFactory.createEmptyBorder(10 + Bubble.TAIL_HEIGHT, 15, 10, 15)); + this.setPreferredSize(new Dimension(220, 140)); + + JPanel contentPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(false, VerticalFlowLayout.CENTER, 0, 0); + contentPane.setOpaque(false); + + UILabel title = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Tips_Title")); + title.setFont(title.getFont().deriveFont(16.0f)); + title.setForeground(new Color(62, 155, 249)); + title.setPreferredSize(new Dimension(190, 30)); + title.setHorizontalAlignment(SwingConstants.CENTER); + title.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); + + UILabel content1 = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Tips_Content1")); + content1.setPreferredSize(new Dimension(190,20)); + content1.setHorizontalAlignment(SwingConstants.CENTER); + + UILabel content2 = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Tips_Content2")); + content2.setPreferredSize(new Dimension(190,20)); + content2.setHorizontalAlignment(SwingConstants.CENTER); + + JPanel buttonContainer= FRGUIPaneFactory.createCenterFlowZeroGapBorderPane(); + buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0)); + buttonContainer.setPreferredSize(new Dimension(190,40)); + buttonContainer.setOpaque(false); + + confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Guide_Tips_Know")); + confirmButton.setPreferredSize(new Dimension(78, 24)); + buttonContainer.add(confirmButton); + + contentPane.add(title); + contentPane.add(content1); + contentPane.add(content2); + contentPane.add(buttonContainer); + + this.add(contentPane, BorderLayout.CENTER); + } + + public void addConfirmAction(ActionListener listener) { + confirmButton.addActionListener(listener); + } + + public void removeConfirmAction(ActionListener listener) { + confirmButton.removeActionListener(listener); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHintDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHintDialog.java new file mode 100644 index 000000000..6e67114af --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHintDialog.java @@ -0,0 +1,30 @@ +package com.fr.design.mainframe.guide.ui; + +import com.fr.design.mainframe.guide.collect.GuideCollector; + +import javax.swing.JDialog; +import java.awt.Color; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class BubbleHintDialog extends JDialog { + private static final int DIALOG_WIDTH = 220; + private static final int DIALOG_HEIGHT = 140; + public BubbleHintDialog(Window parent) { + super(parent); + setUndecorated(true); + this.setBackground(new Color(0,0,0,0)); + setSize(DIALOG_WIDTH, DIALOG_HEIGHT); + BubbleHint bubbleHint = new BubbleHint(); + bubbleHint.addConfirmAction(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + dispose(); + GuideCollector.getInstance().setShowHint(true); + } + }); + this.setContentPane(bubbleHint); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ExpandPane.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ExpandPane.java new file mode 100644 index 000000000..c71a15ea7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ExpandPane.java @@ -0,0 +1,78 @@ +package com.fr.design.mainframe.guide.ui; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.general.IOUtils; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class ExpandPane extends JPanel { + private static final Icon downIcon = IOUtils.readIcon("/com/fr/design/mainframe/guide/arrow_down.png"); + private static final Icon rightIcon = IOUtils.readIcon("/com/fr/design/mainframe/guide/arrow_right.png"); + private String title; + private boolean expand; + private UILabel arrow; + private JPanel headerPane; + private JPanel contentPane; + + public ExpandPane(String title, JPanel contentPane) { + this.title = title; + this.expand = true; + this.contentPane = contentPane; + initComponent(); + } + + private void initComponent() { + VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP, 10, 5); + layout.setAlignLeft(true); + this.setLayout(layout); + + JPanel headerPane = createHeader(); + this.add(headerPane); + this.add(contentPane); + headerPane.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + setExpand(!expand); + } + }); + } + + private JPanel createHeader() { + headerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + headerPane.setPreferredSize(new Dimension(200, 24)); + UILabel headerTitle = new UILabel(this.title); + headerTitle.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); + arrow = new UILabel(downIcon); + arrow.setOpaque(false); + arrow.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + headerPane.add(headerTitle, BorderLayout.CENTER); + headerPane.add(arrow, BorderLayout.WEST); + return headerPane; + } + + @Override + public void setPreferredSize(Dimension preferredSize) { + super.setPreferredSize(preferredSize); + headerPane.setPreferredSize(new Dimension(preferredSize.width, headerPane.getPreferredSize().height)); + contentPane.setPreferredSize(new Dimension(preferredSize.width, contentPane.getPreferredSize().height)); + } + + public void setExpand(boolean isExpand) { + this.expand = isExpand; + arrow.setIcon(isExpand ? downIcon : rightIcon); + contentPane.setVisible(isExpand); + } + + public boolean isExpand() { + return expand; + } +} + diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideCompleteDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideCompleteDialog.java new file mode 100644 index 000000000..15d14df9b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideCompleteDialog.java @@ -0,0 +1,117 @@ +package com.fr.design.mainframe.guide.ui; + +import com.fr.design.gui.frpane.UITextPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.general.IOUtils; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class GuideCompleteDialog extends JDialog { + private static final int DIALOG_WIDTH = 340; + private static final int DIALOG_HEIGHT = 367; + private static final Icon SUCCESS_ICON = IOUtils.readIcon("/com/fr/design/mainframe/guide/success.png"); + private static final int ICON_HEIGHT = 182; + private static final Color FONT_COLOR = new Color(51, 51, 52); + private static final Color BUTTON_BG_COLOR = new Color(65, 155,249); + private static GuideCompleteDialog dialog; + + public static GuideCompleteDialog getInstance() { + if (dialog == null) { + dialog = new GuideCompleteDialog(DesignerContext.getDesignerFrame()); + } + return dialog; + } + + private UITextPane textArea; + + public GuideCompleteDialog(Window window) { + super(window); + setSize(DIALOG_WIDTH, DIALOG_HEIGHT); + setUndecorated(true); + setModal(true); + setLocationRelativeTo(window); + this.setContentPane(getContentPane()); + } + + @Override + public Container getContentPane() { + JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + UILabel completeImage = new UILabel(SUCCESS_ICON); + completeImage.setPreferredSize(new Dimension(DIALOG_WIDTH, ICON_HEIGHT)); + + JPanel container = new JPanel(new BorderLayout(0, 10)); + container.setBorder(BorderFactory.createEmptyBorder(0, 52, 25, 52)); + + UILabel title = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Complete_Confirm")); + title.setFont(title.getFont().deriveFont(22.0f)); + title.setPreferredSize(new Dimension(190, 30)); + title.setHorizontalAlignment(SwingConstants.CENTER); + title.setForeground(FONT_COLOR); + + textArea = new UITextPane(); + textArea.setEnabled(false); + textArea.setOpaque(false); + textArea.setFont(textArea.getFont().deriveFont(18.0f)); + textArea.setPreferredSize(new Dimension(236, 52)); + textArea.setBorder(null); + textArea.setDisabledTextColor(FONT_COLOR); + StyledDocument doc = textArea.getStyledDocument(); + SimpleAttributeSet center = new SimpleAttributeSet(); + StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); + doc.setParagraphAttributes(0, doc.getLength(), center, false); + + JPanel buttonContainer= FRGUIPaneFactory.createCenterFlowZeroGapBorderPane(); + buttonContainer.setPreferredSize(new Dimension(190,38)); + buttonContainer.setOpaque(false); + + JButton button = new JButton(Toolkit.i18nText("Fine-Design_Guide_Complete_End")); + button.setPreferredSize(new Dimension(122, 38)); + button.setBackground(BUTTON_BG_COLOR); + button.setForeground(Color.WHITE); + button.setBorder(null); + button.setContentAreaFilled(false); + button.setOpaque(true); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + dispose(); + } + }); + + buttonContainer.add(button); + container.add(title, BorderLayout.NORTH); + container.add(textArea, BorderLayout.CENTER); + container.add(buttonContainer,BorderLayout.SOUTH); + + contentPane.add(completeImage, BorderLayout.NORTH); + contentPane.add(container, BorderLayout.CENTER); + + return contentPane; + } + + public void showDialog(String str) { + textArea.setText(Toolkit.i18nText("Fine-Design_Guide_Complete_Hint", str)); + repaint(); + this.setVisible(true); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java new file mode 100644 index 000000000..07059ad05 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java @@ -0,0 +1,233 @@ +package com.fr.design.mainframe.guide.ui; + + +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.guide.base.Guide; +import com.fr.design.mainframe.guide.base.GuideGroup; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.design.mainframe.guide.base.GuideVersion; +import com.fr.design.mainframe.guide.collect.GuideCollector; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.IOUtils; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.border.Border; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class GuideManageDialog extends JDialog { + private static final int DEFAULT_HEIGHT = 400; + private static final int DEFAULT_WIDTH = 600; + private static final Icon GROUP_COMPLETE_NONE = IOUtils.readIcon("/com/fr/design/mainframe/guide/complete_none.png"); + private static final Icon GROUP_COMPLETE_SOME = IOUtils.readIcon("/com/fr/design/mainframe/guide/complete_some.png"); + private static final Icon GROUP_COMPLETE_ALL = IOUtils.readIcon("/com/fr/design/mainframe/guide/complete_all.png"); + private static final Color BORDER_COLOR = new Color(224, 224, 225); + private static final Color UNCOMPLETE_FONT_COLOR = new Color(51, 51, 52); + private static final Color COMPLETE_FONT_COLOR = new Color(51,51,52,128); + private static GuideManageDialog dialog; + + private JPanel scrollContent; + + public static GuideManageDialog getInstance() { + if (dialog == null) { + dialog = new GuideManageDialog(DesignerContext.getDesignerFrame()); + } + return dialog; + } + + public GuideManageDialog(Window parent) { + super(parent); + GuideCollector.getInstance().load(); + initComponent(); + } + + private void initComponent() { + this.setTitle(Toolkit.i18nText("Fine-Design_Guide_Manager_Dialog_Title")); + setResizable(false); + setModal(true); + setLayout(FRGUIPaneFactory.createBorderLayout()); + setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); + GUICoreUtils.centerWindow(this); + JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + contentPane.add(createContentPanel(), BorderLayout.CENTER); + contentPane.add(createActionsPane(), BorderLayout.SOUTH); + setContentPane(contentPane); + } + + private UIScrollPane createContentPanel() { + scrollContent = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 5); + UIScrollPane scrollPane = new UIScrollPane(scrollContent); + return scrollPane; + } + + private JPanel createGuideVersionPane(GuideVersion guideVersion) { + JPanel expandContent = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 5); + for (GuideGroup guideGroup : guideVersion.getGuideGroupList()) { + JPanel guideGroupCard = createGuideGroupCard(guideGroup); + expandContent.add(guideGroupCard); + } + ExpandPane expandPane = new ExpandPane(Toolkit.i18nText("Fine-Design_Guide_Manager_Dialog_Version_Title", guideVersion.getVersion()), expandContent); + return expandPane; + } + + + private JPanel createGuideGroupCard(GuideGroup guideGroup) { + JPanel card = FRGUIPaneFactory.createBorderLayout_S_Pane(); + card.setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); + card.setBackground(Color.WHITE); + + JPanel cardContainer = FRGUIPaneFactory.createBorderLayout_S_Pane(); + cardContainer.setOpaque(false); + cardContainer.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + card.add(cardContainer, BorderLayout.CENTER); + + cardContainer.add(createGroupTitlePane(guideGroup), BorderLayout.NORTH); + cardContainer.add(createGroupContentPane(guideGroup), BorderLayout.CENTER); + return card; + } + + private JPanel createGroupTitlePane(GuideGroup guideGroup) { + JPanel titleContainer = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.CENTER, 0, 0); + titleContainer.setBorder(getBottomBorder()); + titleContainer.setOpaque(false); + + titleContainer.setPreferredSize(new Dimension(500, 40)); + JPanel titlePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(0, 8,0 ); + titlePane.setOpaque(false); + + UILabel iconLabel = new UILabel(getGroupStateIcon(guideGroup)); + iconLabel.setPreferredSize(new Dimension(16, 16)); + iconLabel.setOpaque(false); + + UILabel titleLabel = new UILabel(guideGroup.getName()); + titleLabel.setPreferredSize(new Dimension(200, 16)); + titleLabel.setForeground(new Color(65, 155, 249)); + titleLabel.setOpaque(false); + + titlePane.add(iconLabel); + titlePane.add(titleLabel); + titleContainer.add(titlePane); + return titleContainer; + } + + private JPanel createGroupContentPane(GuideGroup guideGroup) { + JPanel groupContainer = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 0); + groupContainer.setBorder(BorderFactory.createEmptyBorder(0,10,0,0)); + groupContainer.setOpaque(false); + for (int index = 0; index < guideGroup.getGuideList().size(); index++) { + JPanel guidePane = createGuidePane(guideGroup.getGuideList().get(index), index); + if (index != guideGroup.getGuideList().size() - 1) { + guidePane.setBorder(getBottomBorder()); + } + groupContainer.add(guidePane); + } + return groupContainer; + } + + + + private JPanel createGuidePane(Guide guide, int index) { + JPanel guidePaneContainer = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.CENTER, 0, 0); + guidePaneContainer.setPreferredSize(new Dimension(540, 40)); + guidePaneContainer.setOpaque(false); + + JPanel guidePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(0, 50,0 ); + guidePane.setOpaque(false); + + UILabel title = new UILabel((index + 1) + "、" + guide.getDescription()); + title.setPreferredSize(new Dimension(440, 20)); + title.setForeground(guide.isComplete() ? COMPLETE_FONT_COLOR : UNCOMPLETE_FONT_COLOR); + title.setOpaque(false); + + + UIButton button = new UIButton(guide.isComplete() ? Toolkit.i18nText("Fine-Design_Guide_Manager_Dialog_Retry") : Toolkit.i18nText("Fine-Design_Guide_Manager_Dialog_Show")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + guide.go(); + } + }); + + button.setPreferredSize(new Dimension(48, 20)); + guidePane.add(title); + guidePane.add(button); + + guidePaneContainer.add(guidePane); + return guidePaneContainer; + } + + private Border getBottomBorder() { + return BorderFactory.createMatteBorder( + 0,0,1, 0, BORDER_COLOR + ); + } + + public void showDialog() { + resetScrollContent(); + this.setVisible(true); + } + + private Icon getGroupStateIcon(GuideGroup guideGroup) { + if (guideGroup.isCompleteAll()) { + return GROUP_COMPLETE_ALL; + } else if (guideGroup.isCompleteSome()) { + return GROUP_COMPLETE_SOME; + } else { + return GROUP_COMPLETE_NONE; + } + } + + private UIButton createCompleteAllButton() { + UIButton button = new UIButton(Toolkit.i18nText(Toolkit.i18nText("Fine-Design_Guide_Manager_Dialog_Complete_All"))); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + GuideManager.getInstance().completeAll(); + resetScrollContent(); + } + }); + return button; + } + + private UIButton createCloseButton() { + UIButton button = new UIButton(Toolkit.i18nText(Toolkit.i18nText("Fine-Design_Guide_Manager_Dialog_Close"))); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + }); + return button; + } + + private JPanel createActionsPane() { + JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane(); + container.setBorder(BorderFactory.createEmptyBorder(7, 10, 7, 10)); + container.add(createCompleteAllButton(), BorderLayout.WEST); + container.add(createCloseButton(), BorderLayout.EAST); + return container; + } + + private void resetScrollContent() { + scrollContent.removeAll(); + for (GuideVersion guideVersion : GuideManager.getInstance().getGuideVersionList()) { + scrollContent.add(createGuideVersionPane(guideVersion)); + } + revalidate(); + repaint(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/Bubble.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/Bubble.java new file mode 100644 index 000000000..10b04362e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/Bubble.java @@ -0,0 +1,152 @@ +package com.fr.design.mainframe.guide.ui.bubble; + +import javax.swing.JComponent; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +public class Bubble extends JComponent { + public enum TailDirection { + TOP, BOTTOM, LEFT, RIGHT + } + protected static final int TAIL_HEIGHT = 7; + protected static final int TAIL_WIDTH = 14; + protected static final int BUBBLE_WIDTH = 170; + protected static final Color BG_COLOR = new Color(240,240,241); + protected static final int BORDER_RADIUS = 10; + + + private TailDirection tailDirection; + private float tailStart; + + public Bubble() { + this(TailDirection.LEFT, 0.5f); + } + + public Bubble(TailDirection tailDirection, float tailStart) { + this.tailDirection = tailDirection; + this.tailStart = tailStart; + this.setOpaque(false); + } + + public void setTailDirection(TailDirection tailDirection) { + this.tailDirection = tailDirection; + } + + public TailDirection getTailDirection() { + return tailDirection; + } + + public void setTailStart(float tailStart) { + this.tailStart = tailStart; + } + + public float getTailStart() { + return tailStart; + } + + + @Override + public Dimension getPreferredSize() { + if (isPreferredSizeSet()) { + return super.getPreferredSize(); + } + return new Dimension(getDefaultWidth(), getDefaultHeight()); + + } + + protected int getDefaultWidth() { + return (isTailHorizontal() ? TAIL_HEIGHT : 0) + BUBBLE_WIDTH; + } + + protected int getDefaultHeight() { + return (isTailVertical() ? TAIL_HEIGHT : 0); + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + Composite oldComposite = g2.getComposite(); + paintBubbleBg(g2); + g2.setComposite(oldComposite); + super.paintComponent(g); + } + + protected void paintBubbleBg(Graphics2D g2) { + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + paintRectBg(g2); + paintTailBg(g2); + } + + protected void paintRectBg(Graphics2D g2) { + g2.setColor(BG_COLOR); + Rectangle bounds = getRectBounds(); + g2.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, BORDER_RADIUS, BORDER_RADIUS); + } + + protected void paintTailBg(Graphics2D g2) { + int width = getWidth(); + int height = getHeight(); + if (isTailVertical()) { + int tailX = (int) (width * tailStart); + int startX = Math.max(tailX - TAIL_WIDTH / 2, 0); + int endX = startX + TAIL_WIDTH; + int[] xPoints = {startX, endX, tailX}; + int[] yPoints = isTailTop() ? new int[]{TAIL_HEIGHT, TAIL_HEIGHT, 0} : new int[]{height - TAIL_HEIGHT, height - TAIL_HEIGHT, height}; + g2.fillPolygon(xPoints, yPoints, 3); + } else if (isTailHorizontal()) { + int tailY = (int) (height * tailStart); + int startY = Math.max(tailY - TAIL_WIDTH / 2, 0); + int endY = startY + TAIL_WIDTH; + int[] xPoints = isTailLeft() ? new int[]{TAIL_HEIGHT, TAIL_HEIGHT, 0} : new int[]{width - TAIL_HEIGHT, width - TAIL_HEIGHT, width}; + int[] yPoints = {startY, endY, tailY}; + g2.fillPolygon(xPoints, yPoints, 3); + } + } + + public Rectangle getRectBounds() { + int width = getWidth(); + int height = getHeight(); + switch (tailDirection) { + case TOP: + return new Rectangle(0, TAIL_HEIGHT, width, height - TAIL_HEIGHT); + case LEFT: + return new Rectangle(TAIL_HEIGHT, 0, width - TAIL_HEIGHT, height); + case RIGHT: + return new Rectangle(0, 0 , width - TAIL_HEIGHT, height); + case BOTTOM: + return new Rectangle(0, 0, width, height - TAIL_HEIGHT); + default: + return new Rectangle(0,0,0,0); + } + } + + public boolean isTailHorizontal() { + return isTailLeft() || isTailRight(); + } + + public boolean isTailVertical() { + return isTailTop() || isTailBottom(); + } + + public boolean isTailLeft() { + return tailDirection == TailDirection.LEFT; + } + + public boolean isTailRight() { + return tailDirection == TailDirection.RIGHT; + } + + public boolean isTailTop() { + return tailDirection == TailDirection.TOP; + } + + public boolean isTailBottom() { + return tailDirection == TailDirection.BOTTOM; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java new file mode 100644 index 000000000..b5e966063 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java @@ -0,0 +1,255 @@ +package com.fr.design.mainframe.guide.ui.bubble; + + +import com.fr.base.GraphHelper; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.itextarea.UITextArea; +import com.fr.general.IOUtils; +import com.fr.stable.StringUtils; + +import javax.swing.JTextArea; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.font.FontRenderContext; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + +public class BubbleWithClose extends Bubble { + private static final Font FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 14); + private static final int HEADER_HEIGHT = 24; + private static final Color HEADER_COLOR = new Color(245, 245, 246); + private static final Color TITLE_COLOR = new Color(51, 51, 52); + private static final Color CONTENT_COLOR = new Color(51,51,52,128); + private static final Insets DEFAULT_INSET = new Insets(10, 15, 10, 15); + + private String title; + private String content; + private UITextArea titleTextArea; + private UITextArea contentTextArea; + private UIButton closeButton; + + public BubbleWithClose(String title, String content) { + this(title, content, TailDirection.LEFT, 0.5f); + } + + public BubbleWithClose(String title, String content, TailDirection tailDirection, float tailStart) { + super(tailDirection, tailStart); + this.title = title; + this.content = content; + this.initComponent(); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + protected void initComponent() { + this.setLayout(getLayoutManager()); + createCloseButton(); + createContentPane(); + this.addComponentListener(new ComponentAdapter() { + @Override + public void componentShown(ComponentEvent e) { + super.componentShown(e); + } + + @Override + public void componentResized(ComponentEvent e) { + Rectangle rectBounds = getRectBounds(); + Dimension buttonSize = closeButton.getPreferredSize(); + + closeButton.setBounds(getWidth() - 10 - buttonSize.width, rectBounds.y + (HEADER_HEIGHT - buttonSize.height) / 2, buttonSize.width, buttonSize.height); + + Dimension titleSize = new Dimension(0,0); + Dimension contentSize = new Dimension(0, 0); + if (titleTextArea != null) { + titleSize = calTextSize(titleTextArea, getTextAreaMaxWidth()); + int x = rectBounds.x + (rectBounds.width - getHorizontalInsets() - titleSize.width) / 2 + DEFAULT_INSET.left; + int y = rectBounds.y + HEADER_HEIGHT + DEFAULT_INSET.top; + titleTextArea.setBounds(x, y, titleSize.width, titleSize.height); + } + + if (contentTextArea != null) { + contentSize = calTextSize(contentTextArea, getTextAreaMaxWidth()); + int x = rectBounds.x + (rectBounds.width - getHorizontalInsets() - contentSize.width) / 2 + DEFAULT_INSET.left; + int y = rectBounds.y = HEADER_HEIGHT + DEFAULT_INSET.top + (titleSize.height == 0 ? 0 : titleSize.height + 10); + contentTextArea.setBounds(x,y, contentSize.width, contentSize.height); + } + setSize(getPreferredSize().width, getPreferredSize().height); + repaint(); + } + }); + } + + private void createCloseButton() { + closeButton = new UIButton(); + closeButton.setIcon(IOUtils.readIcon("/com/fr/design/mainframe/guide/close.png")); + closeButton.set4ToolbarButton(); + closeButton.setPreferredSize(new Dimension(16, 16)); + closeButton.setRolloverEnabled(false); + closeButton.setPressedPainted(false); + this.add(closeButton); + } + + public void addCloseActionListener(ActionListener actionListener) { + closeButton.addActionListener(actionListener); + + } + + public void removeCloseActionListener(ActionListener actionListener){ + closeButton.removeActionListener(actionListener); + } + + private void createContentPane() { + createTitleTextArea(); + createContentTextArea(); + } + + private void createTitleTextArea() { + if (StringUtils.isNotEmpty(title)) { + titleTextArea = createTextArea(title, FONT, TITLE_COLOR); + this.add(titleTextArea); + } + + } + + private void createContentTextArea() { + if (StringUtils.isNotEmpty(content)) { + contentTextArea = createTextArea(content, FONT, CONTENT_COLOR); + this.add(contentTextArea); + } + } + + private UITextArea createTextArea(String str, Font font, Color foreground) { + UITextArea textArea= new UITextArea(str){ + @Override + public Insets getInsets() { + return new Insets(0, 0, 0, 0); + } + }; + textArea.setEnabled(true); + textArea.setBorder(null); + textArea.setFont(font); + textArea.setOpaque(false); + textArea.setForeground(foreground); + return textArea; + } + + protected int getDefaultHeight() { + Dimension titleSize = calTextSize(titleTextArea, getDefaultTextAreaMaxWidth()); + Dimension contentSize = calTextSize(contentTextArea, getDefaultTextAreaMaxWidth()); + return (isTailVertical() ? TAIL_HEIGHT : 0) + HEADER_HEIGHT + titleSize.height + (titleSize.height == 0 ? 0 : 5) + contentSize.height + getVerticalInsets(); + } + + private LayoutManager getLayoutManager() { + return new LayoutManager() { + @Override + public void addLayoutComponent(String name, Component comp) { + } + + @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 + protected void paintBubbleBg(Graphics2D g2) { + super.paintBubbleBg(g2); + paintHeaderBg(g2); + } + + private void paintHeaderBg(Graphics2D g2) { + g2.setColor(HEADER_COLOR); + Rectangle bounds = getRectBounds(); + g2.fillRoundRect(bounds.x, bounds.y, bounds.width, HEADER_HEIGHT, 10, 10); + } + + private int countLines(JTextArea textArea, int max_width) { + AttributedString text = new AttributedString(textArea.getText()); + text.addAttribute(TextAttribute.FONT, textArea.getFont()); + FontRenderContext frc = textArea.getFontMetrics(textArea.getFont()) + .getFontRenderContext(); + AttributedCharacterIterator charIt = text.getIterator(); + LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(charIt, frc); + lineMeasurer.setPosition(charIt.getBeginIndex()); + int lines = 0; + while (lineMeasurer.getPosition() < charIt.getEndIndex()) { + lineMeasurer.nextLayout(max_width); + lines++; + } + return lines; + } + + private Dimension calTextSize(JTextArea textArea, int maxWidth) { + if (textArea == null) { + return new Dimension(0, 0); + } + FontMetrics fontMetrics = GraphHelper.getFontMetrics(textArea.getFont()); + int line = countLines(textArea, maxWidth); + int width = maxWidth; + if (line == 1) { + width = fontMetrics.stringWidth(textArea.getText()); + } + int height = fontMetrics.getHeight() * line; + return new Dimension(width, height); + } + + private int getTextAreaMaxWidth() { + return getWidth() - (isTailHorizontal() ? TAIL_HEIGHT : 0) -getHorizontalInsets(); + } + + private int getDefaultTextAreaMaxWidth() { + return BUBBLE_WIDTH - getHorizontalInsets(); + } + + private int getHorizontalInsets() { + return DEFAULT_INSET.left + DEFAULT_INSET.right; + } + + private int getVerticalInsets() { + return DEFAULT_INSET.top + DEFAULT_INSET.bottom; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/utils/ScreenImage.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/utils/ScreenImage.java new file mode 100644 index 000000000..3d718ec1c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/utils/ScreenImage.java @@ -0,0 +1,98 @@ +package com.fr.design.mainframe.guide.utils; + +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import java.awt.AWTException; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; + +public class ScreenImage { + + public static BufferedImage createImage(JComponent component) { + return ScreenImage.createImage(component, getRegion(component)); + } + + public static BufferedImage createImage(JComponent component, Rectangle region) { + if (! component.isDisplayable()) { + Dimension d = component.getSize(); + + if (d.width == 0 || d.height == 0) { + d = component.getPreferredSize(); + component.setSize( d ); + } + + layoutComponent( component ); + } + + BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + + if (! component.isOpaque()) { + g2d.setColor( component.getBackground() ); + g2d.fillRect(region.x, region.y, region.width, region.height); + } + + g2d.translate(-region.x, -region.y); + component.print( g2d ); + g2d.dispose(); + return image; + } + + public static BufferedImage createImage(Component component) + throws AWTException { + Point p = new Point(0, 0); + SwingUtilities.convertPointToScreen(p, component); + Rectangle region = component.getBounds(); + region.x = p.x; + region.y = p.y; + return ScreenImage.createImage(region); + } + + public static BufferedImage createImageWithModal(JComponent component) { + Rectangle region = getRegion(component); + BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + g2d.drawImage(createImage(component), 0, 0, null); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f)); + g2d.setColor(Color.BLACK); + g2d.fillRect(0, 0, region.width, region.height); + g2d.dispose(); + return image; + } + + public static BufferedImage createImage(Rectangle region) + throws AWTException { + BufferedImage image = new Robot().createScreenCapture( region ); + return image; + } + + private static Rectangle getRegion(Component component) { + Dimension d = component.getSize(); + if (d.width == 0 || d.height == 0) { + d = component.getPreferredSize(); + component.setSize( d ); + } + return new Rectangle(0, 0, d.width, d.height); + } + + static void layoutComponent(Component component) { + synchronized (component.getTreeLock()) { + component.doLayout(); + + if (component instanceof Container) { + for (Component child : ((Container)component).getComponents()) { + layoutComponent(child); + } + } + } + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java index 543df64eb..ea649033e 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java @@ -64,6 +64,7 @@ public class TemplateThemeBlock extends JPanel { TemplateThemeConfig config, TemplateThemeProfilePane profilePane) { this.name = name; + this.setName(name); this.displayTheme4NewTemplateMarker = displayTheme4NewTemplateMarker; this.config = config; this.profilePane = profilePane; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java index 9c9f9220e..9038b097a 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java @@ -25,8 +25,8 @@ import java.awt.event.ActionListener; * @version 1.0 * Created by Starryi on 2021/8/13 */ -public class -TemplateThemeUsingDialog extends TemplateThemeDialog { +public class TemplateThemeUsingDialog extends TemplateThemeDialog { + public static final String COMPLETE_BUTTON = "theme_button_complete"; public static final int CONTENT_WIDTH = TemplateThemeListPane.CONTENT_WIDTH + 42; public static final int CONTENT_HEIGHT = TemplateThemeListPane.CONTENT_HEIGHT + 23; @@ -94,6 +94,7 @@ TemplateThemeUsingDialog extends TemplateThemeDialog { private UIButton createCompleteButton() { UIButton button = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Using_Dialog_Complete")); + button.setName(COMPLETE_BUTTON); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java index cfc4483c9..c4ad83ca7 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java @@ -469,6 +469,10 @@ public abstract class ToolBarMenuDock { return new UILabel(); } + public Component createGuideEntryPane() { + return new UILabel(); + } + public Component createNotificationCenterPane(){ return new UILabel(); } diff --git a/designer-base/src/main/java/com/fr/design/utils/ComponentUtils.java b/designer-base/src/main/java/com/fr/design/utils/ComponentUtils.java index 1d9361138..24134dce1 100644 --- a/designer-base/src/main/java/com/fr/design/utils/ComponentUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/ComponentUtils.java @@ -1,11 +1,13 @@ package com.fr.design.utils; import com.fr.general.ComparatorUtils; +import com.fr.stable.StringUtils; import javax.swing.*; import java.awt.*; import java.awt.geom.Rectangle2D; import java.util.ArrayList; +import java.util.List; /** * 工具类,提供常用的工具方法 @@ -151,4 +153,62 @@ public class ComponentUtils { } return false; } + + public static Component findComponentByName(Component container, String componentName) { + Component target = null; + if (container instanceof Container) { + for (Component component: ((Container)container).getComponents()) { + if (componentName.equals(component.getName())) { + return component; + } + if (component instanceof JRootPane) { + JRootPane nestedJRootPane = (JRootPane)component; + target = findComponentByName(nestedJRootPane.getContentPane(), componentName); + } else if (component instanceof Container){ + target = findComponentByName( component, componentName); + } + if (target != null) { + return target; + } + } + } + return null; + } + + public static Component findComponentByClass(Component container, Class clazz) { + Component target = null; + if (container instanceof Container) { + for (Component component: ((Container)container).getComponents()) { + if (clazz.isInstance(component)) { + return component; + } + if (component instanceof JRootPane) { + JRootPane nestedJRootPane = (JRootPane)component; + target = findComponentByClass(nestedJRootPane.getContentPane(), clazz); + } else if (component instanceof Container){ + target = findComponentByClass(component, clazz); + } + if (target != null) { + return target; + } + } + } + return null; + } + + public static List findComponentsByClass(Component container, Class clazz) { + List components= new ArrayList<>(); + if (container instanceof Container) { + for (Component component: ((Container)container).getComponents()) { + if (clazz.isInstance(component)) { + components.add(component); + continue; + } + if (component instanceof Container){ + components.addAll(findComponentsByClass(component, clazz)); + } + } + } + return components; + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/write/submit/CustomJobPane.java b/designer-base/src/main/java/com/fr/design/write/submit/CustomJobPane.java index d07d42b3e..6e4f2d803 100644 --- a/designer-base/src/main/java/com/fr/design/write/submit/CustomJobPane.java +++ b/designer-base/src/main/java/com/fr/design/write/submit/CustomJobPane.java @@ -13,6 +13,7 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.DialogActionAdapter; +import com.fr.stable.ListMap; import com.fr.stable.StringUtils; import com.fr.design.utils.gui.GUICoreUtils; @@ -115,7 +116,12 @@ public abstract class CustomJobPane extends BasicBeanPane { @Override public void populateBean(Object ob) { - if (ob instanceof AbstractClassJob) { + if (ob == null) { + // 自定义提交新增时初始化页面 REPORT-59256 + this.classNameTextField.setText(StringUtils.EMPTY); + this.objectProperiesPane.populateBean(new ListMap()); + } + else if (ob instanceof AbstractClassJob) { AbstractClassJob cj = (AbstractClassJob) ob; this.classNameTextField.setText(cj.getClassName()); this.objectProperiesPane.populateBean(cj.getPropertyMap()); diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/arrow_down.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/arrow_down.png new file mode 100644 index 000000000..cf65b3bc4 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/arrow_down.png differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/arrow_right.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/arrow_right.png new file mode 100644 index 000000000..a1ac42cfe Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/arrow_right.png differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/close.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/close.png new file mode 100644 index 000000000..22e3caa53 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/close.png differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.png new file mode 100644 index 000000000..c696cba4d Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.png differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.png new file mode 100644 index 000000000..4c6c6f2bb Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.png differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.png new file mode 100644 index 000000000..b3443318b Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.png differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/guide.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/guide.png new file mode 100644 index 000000000..ef5a19783 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/guide.png differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/success.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/success.png new file mode 100644 index 000000000..efd7a04f4 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/mainframe/guide/success.png differ diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java index 3e255d2a4..84013aadf 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java @@ -160,8 +160,10 @@ public class FRFitLayoutAdapter extends FRBodyLayoutAdapter { //布局控件要先判断是不是可编辑 XLayoutContainer topLayout = XCreatorUtils.getHotspotContainer((XCreator) comp).getTopLayout(); - boolean access = topLayout != null && !isMatchEdge && !topLayout.isEditable() && !topLayout.acceptType(XWAbsoluteLayout.class) && !isExtraContainer(comp) && !topLayout.isDragInAble(); - if (access) { + boolean access = topLayout != null && !isMatchEdge && !topLayout.acceptType(XWAbsoluteLayout.class) && !isExtraContainer(comp) && !topLayout.isDragInAble(); + //topLayout.getParent() != container说明当前增加的组件所在容器是嵌套在外部的自适应容器内部的,此时需要判断增加组件所在容器是否可编辑,不可编辑的话就直接返回 false + //否则说明就是往当前自适应容器内部添加组件,不需要判断其是否可编辑 + if (access && (topLayout.getParent() != container && !topLayout.isEditable())) { return false; } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java index e55aa86d3..1926b57b1 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java @@ -4,8 +4,8 @@ import com.fr.design.designer.beans.AdapterBus; import com.fr.design.designer.beans.ComponentAdapter; import com.fr.design.designer.beans.adapters.component.CompositeComponentAdapter; import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XCreatorUtils; import com.fr.design.designer.creator.XLayoutContainer; -import com.fr.design.designer.creator.XWAbsoluteLayout; import com.fr.design.designer.creator.XWParameterLayout; import com.fr.design.mainframe.FormDesigner; import com.fr.design.utils.ComponentUtils; @@ -124,11 +124,10 @@ public class AddingModel { */ public boolean add2Container(FormDesigner designer, XLayoutContainer container, int x, int y) { //考虑不同布局嵌套的情况,获取顶层容器 - XLayoutContainer xLayoutContainer = container.getTopLayout(); - if (xLayoutContainer != null && xLayoutContainer.acceptType(XWAbsoluteLayout.class)) { + XLayoutContainer xLayoutContainer = XCreatorUtils.getTopEditableContainer(container); + if (xLayoutContainer != null) { container = xLayoutContainer; } - Rectangle rect = ComponentUtils.getRelativeBounds(container); if (!ComparatorUtils.equals(container.getOuterLayout(), container.getBackupParent())) { added = container.getLayoutAdapter().addBean(creator, @@ -141,4 +140,5 @@ public class AddingModel { y + designer.getVerticalScaleValue() - rect.y); return added; } + } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java index 38fb9d73e..02ac912c3 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java @@ -402,4 +402,22 @@ public class XCreatorUtils { FineColorFlushUtils.replaceCacheObject(container.toData(), colorGather); FineColorManager.traverse(container.toData(), colorGather); } + + + /** + * 获取容器组件的顶层正编辑的组件 + */ + @Nullable + public static XLayoutContainer getTopEditableContainer(XLayoutContainer container) { + if (container == null) { + return null; + } + XLayoutContainer xLayoutContainer = container.getTopLayout(); + if (xLayoutContainer != null && xLayoutContainer.getParent() != null) { + if (!xLayoutContainer.isEditable()) { + return (XLayoutContainer) xLayoutContainer.getParent(); + } + } + return null; + } } \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XWFitLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/XWFitLayout.java index b9814a0f3..5b9a13334 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XWFitLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XWFitLayout.java @@ -796,6 +796,7 @@ public class XWFitLayout extends XLayoutContainer { layout.setContainerHeight(containerHeight); layout.setContainerWidth(containerWidth); addCompInterval(getAcualInterval()); + LayoutUtils.layoutContainer(this); // REPORT-54410: 决策报表,模板中其他组件的宽高修改会影响绝对画布块中组件的宽高和位置 // 绝对布局内的组件尺寸调整需要在绝对布局的bound排除GAP后进行,否则计算出的 diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java b/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java index 82b8e3f1f..e08c1c652 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java @@ -74,6 +74,7 @@ public class FormArea extends JComponent implements ScrollRulerComponent { private static final double SLIDER_MIN = 10.0; private static final String SCALE_PLUS_COMMAND = "scale_plus"; private static final String SCALE_MINUS_COMMAND = "scale_minus"; + public static final String FIX_LAYOUT_SWITCH_BUTTON = "fix_layout_switch_button"; public static final double DEFAULT_SLIDER = 100.0; private static final int ROTATIONS = 50; public static final int SHOWVALMAX = 400; @@ -188,6 +189,7 @@ public class FormArea extends JComponent implements ScrollRulerComponent { private UIButton createFixLayoutSwitchButton(){ UIButton button = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout_No_Fix_Layout")); button.setIcon(IOUtils.readIcon("/com/fr/base/images/share/filter_combo.png")); + button.setName(FIX_LAYOUT_SWITCH_BUTTON); button.setUI(new UIButtonUI(){ @Override protected void paintBorder(Graphics g, UIButton b) { @@ -202,15 +204,16 @@ public class FormArea extends JComponent implements ScrollRulerComponent { } }); button.setHorizontalTextPosition(SwingConstants.LEFT); + UIPopupMenu popupMenu = new UIPopupMenu(); + popupMenu.setPreferredSize(new Dimension(180, 59)); + popupMenu.setOnlyText(true); + popupMenu.setBackground(UIConstants.DEFAULT_BG_RULER); + popupMenu.add(new PopupMenuItem(new Switch2NoFixLayoutAction())); + popupMenu.add(new PopupMenuItem(new Switch2FixLayoutAction())); + button.setComponentPopupMenu(popupMenu); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - UIPopupMenu popupMenu = new UIPopupMenu(); - popupMenu.setPreferredSize(new Dimension(180, 59)); - popupMenu.setOnlyText(true); - popupMenu.setBackground(UIConstants.DEFAULT_BG_RULER); - popupMenu.add(new PopupMenuItem(new Switch2NoFixLayoutAction())); - popupMenu.add(new PopupMenuItem(new Switch2FixLayoutAction())); GUICoreUtils.showPopupMenu(popupMenu, fixLayoutSwitchButton, 0, -59); } }); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java b/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java index 926b6be5e..af4d2ae2d 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormCreatorDropTarget.java @@ -79,7 +79,7 @@ public class FormCreatorDropTarget extends DropTarget { this.tabDragInner = new TabDragInner(designer); } - private void adding(int x, int y) { + public void adding(int x, int y) { // 当前鼠标所在的组件 XCreator hoveredComponent = designer.getComponentAt(x, y); // 获取该组件所在的焦点容器 @@ -193,7 +193,6 @@ public class FormCreatorDropTarget extends DropTarget { private void dealWithContainer(int x, int y, XLayoutContainer container) { HoverPainter painter = null; - if (container != current || designer.getPainter() == null) { // 如果焦点容器不是当前容器 if (current != null) { @@ -204,15 +203,9 @@ public class FormCreatorDropTarget extends DropTarget { throw new IllegalArgumentException("container can not be null!"); } //获取painter的时候要考虑布局之间嵌套的问题 - XLayoutContainer xLayoutContainer = container.getTopLayout(); - if (xLayoutContainer != null && xLayoutContainer.getParent() != null - && ((XLayoutContainer) xLayoutContainer.getParent()).acceptType(XWAbsoluteLayout.class)) { - if (!xLayoutContainer.isEditable()) { - xLayoutContainer = (XLayoutContainer) xLayoutContainer.getParent(); - } - } + XLayoutContainer xLayoutContainer = XCreatorUtils.getTopEditableContainer(container); painter = AdapterBus.getContainerPainter(designer, - xLayoutContainer != null && xLayoutContainer.acceptType(XWAbsoluteLayout.class) ? xLayoutContainer : container); + xLayoutContainer != null ? xLayoutContainer : container); // 为界面设计器设置提示渲染提示器 designer.setPainter(painter); @@ -227,8 +220,9 @@ public class FormCreatorDropTarget extends DropTarget { } } if (painter != null) { + XLayoutContainer xLayoutContainer = XCreatorUtils.getTopEditableContainer(container); // 为提示渲染器设置焦点位置、区域等渲染参数 - Rectangle rect = ComponentUtils.getRelativeBounds(container); + Rectangle rect = ComponentUtils.getRelativeBounds(xLayoutContainer != null ? xLayoutContainer : container); rect.x -= designer.getArea().getHorizontalValue(); rect.y -= designer.getArea().getVerticalValue(); painter.setRenderingBounds(rect); @@ -236,7 +230,7 @@ public class FormCreatorDropTarget extends DropTarget { painter.setCreator(addingModel.getXCreator()); } } - + private void promptUser(int x, int y, XLayoutContainer container) { if (!addingModel.getXCreator().canEnterIntoParaPane() && container.acceptType(XWParameterLayout.class)) { promptButton.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Forbid_Drag_Into_Para_Pane")); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java index 683bf9b71..25bd5749f 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java @@ -1120,6 +1120,10 @@ public class FormDesigner extends TargetComponent
implements TreeSelection return addingModel; } + public void setAddingModel(AddingModel addingModel) { + this.addingModel = addingModel; + } + public XCreator getComponentAt(MouseEvent e) { return getComponentAt(e.getX(), e.getY()); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java b/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java index d792f0eca..f2268c86c 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormWidgetDetailPane.java @@ -36,6 +36,7 @@ public class FormWidgetDetailPane extends FormDockView{ private JPanel centerPane; private UIHeadGroup headGroup; private List paneList; + private CardLayout cardLayout; private boolean isEmptyPane = false; @@ -86,7 +87,7 @@ public class FormWidgetDetailPane extends FormDockView{ initPaneList(); this.setBorder(null); - final CardLayout cardLayout = new CardLayout(); + cardLayout = new CardLayout(); centerPane = new JPanel(cardLayout); String[] paneNames = new String[paneList.size()]; for (int i = 0; i < paneList.size(); i++) { @@ -137,6 +138,14 @@ public class FormWidgetDetailPane extends FormDockView{ this.add(panel, BorderLayout.CENTER); } + public void switch2Local() { + cardLayout.show(centerPane, paneList.get(0).getTitle()); + } + + public void swich2Online() { + cardLayout.show(centerPane, paneList.get(1).getTitle()); + } + private UILabel tipLabel(String text) { UILabel tipLabel = new UILabel(text); tipLabel.setHorizontalAlignment(SwingConstants.CENTER); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/AbstractWidgetSelectPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/AbstractWidgetSelectPane.java index 96b321c93..1b36f08d1 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/AbstractWidgetSelectPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/AbstractWidgetSelectPane.java @@ -1,6 +1,7 @@ package com.fr.design.mainframe.share; -import com.fr.design.mainframe.share.ui.base.PopupPreviewPane; +import com.fr.design.mainframe.share.ui.base.AbstractWidgetPopupPreviewPane; +import com.fr.design.mainframe.share.ui.base.LocalWidgetPopupPreviewPane; import com.fr.design.mainframe.share.ui.block.PreviewWidgetBlock; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.ComparatorUtils; @@ -13,16 +14,16 @@ import java.awt.Container; * @Author: Yuan.Wang * @Date: 2021/1/15 */ -public abstract class AbstractWidgetSelectPane extends JPanel { +public abstract class AbstractWidgetSelectPane extends JPanel { private static final int SCROLL_BAR_HEIGHT = 10; - private final PopupPreviewPane previewPane; + private final AbstractWidgetPopupPreviewPane previewPane; private String currentShowWidgetID; public AbstractWidgetSelectPane() { - this.previewPane = new PopupPreviewPane(); + this.previewPane = createPopupPreviewPane(); } - public void showPreviewPane(PreviewWidgetBlock comp, String showWidgetID) { + public void showPreviewPane(PreviewWidgetBlock comp, String showWidgetID) { if (ComparatorUtils.equals(currentShowWidgetID, showWidgetID)) { return; } @@ -36,7 +37,7 @@ public abstract class AbstractWidgetSelectPane extends JPanel { this.currentShowWidgetID = StringUtils.EMPTY; } - private void popupPreviewPane(PreviewWidgetBlock comp, String showWidgetID) { + private void popupPreviewPane(PreviewWidgetBlock comp, String showWidgetID) { if (previewPane.isVisible()) { previewPane.setVisible(false); } @@ -44,7 +45,7 @@ public abstract class AbstractWidgetSelectPane extends JPanel { if (!previewPane.isVisible() && comp.getWidth() != 0 && comp.getHeight() != 0) { //父容器是GroupPane,要获得的是GroupPane的父容器 Container parentContainer =getParentContainer(); - previewPane.setComp(comp.getPreviewImage()); + previewPane.populateBean(comp); int popupPosY = comp.getLocationOnScreen().y - parentContainer.getLocationOnScreen().y; if (previewPane.getHeight() + popupPosY > parentContainer.getHeight() + SCROLL_BAR_HEIGHT) { popupPosY -= (previewPane.getHeight() + popupPosY - parentContainer.getHeight() - SCROLL_BAR_HEIGHT); @@ -58,5 +59,7 @@ public abstract class AbstractWidgetSelectPane extends JPanel { } } + protected abstract AbstractWidgetPopupPreviewPane createPopupPreviewPane(); + abstract protected Container getParentContainer(); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/AbstractWidgetPopupPreviewPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/AbstractWidgetPopupPreviewPane.java new file mode 100644 index 000000000..12c2c33ff --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/AbstractWidgetPopupPreviewPane.java @@ -0,0 +1,15 @@ +package com.fr.design.mainframe.share.ui.base; + +import com.fr.design.mainframe.share.ui.block.PreviewWidgetBlock; + +import javax.swing.JPopupMenu; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/15 + */ +public abstract class AbstractWidgetPopupPreviewPane extends JPopupMenu { + + public abstract void populateBean(PreviewWidgetBlock block); +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/PopupPreviewPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/LocalWidgetPopupPreviewPane.java similarity index 81% rename from designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/PopupPreviewPane.java rename to designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/LocalWidgetPopupPreviewPane.java index 91b1eae89..f78dbf701 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/PopupPreviewPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/base/LocalWidgetPopupPreviewPane.java @@ -1,6 +1,9 @@ package com.fr.design.mainframe.share.ui.base; import com.fr.design.constants.UIConstants; +import com.fr.design.mainframe.share.ui.block.LocalWidgetBlock; +import com.fr.design.mainframe.share.ui.block.PreviewWidgetBlock; +import com.fr.form.share.DefaultSharableWidget; import com.fr.general.IOUtils; import javax.swing.BorderFactory; @@ -17,17 +20,16 @@ import java.awt.Toolkit; /** * Created by kerry on 2020-06-23 */ -public class PopupPreviewPane extends JPopupMenu { - private Container contentPane; +public class LocalWidgetPopupPreviewPane extends AbstractWidgetPopupPreviewPane { private Image compImage; private static final int WIDTH = 400; private static final int STANDARD_DPI = 128; private static final int MAX_HEIGHT = 400; private static final int HEIGHT = 210; - public PopupPreviewPane() { + public LocalWidgetPopupPreviewPane() { setFocusable(false); - contentPane = new JPanel(); + Container contentPane = new JPanel(); contentPane.setBackground(Color.white); this.setLayout(new BorderLayout()); this.add(contentPane, BorderLayout.CENTER); @@ -36,9 +38,9 @@ public class PopupPreviewPane extends JPopupMenu { setBorder(BorderFactory.createLineBorder(UIConstants.LINE_COLOR)); } - public void setComp(Image compImage) { + public void populateBean(PreviewWidgetBlock block) { try { - this.compImage = compImage; + this.compImage = block.getPreviewImage(); this.updateSize(); } catch (Exception e) { e.printStackTrace(); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/AbstractOnlineWidgetBlock.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/AbstractOnlineWidgetBlock.java index 06e513b80..404c319db 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/AbstractOnlineWidgetBlock.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/AbstractOnlineWidgetBlock.java @@ -1,27 +1,57 @@ package com.fr.design.mainframe.share.ui.block; +import com.fr.base.theme.FormTheme; +import com.fr.base.theme.FormThemeConfig; +import com.fr.base.theme.TemplateTheme; +import com.fr.base.theme.TemplateThemeConfig; +import com.fr.design.DesignerEnvManager; +import com.fr.design.actions.UpdateAction; +import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.imenu.UIPopupMenu; +import com.fr.design.i18n.Toolkit; +import com.fr.design.login.DesignerLoginHelper; +import com.fr.design.login.DesignerLoginSource; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.share.ui.online.OnlineResourceManager; import com.fr.design.mainframe.share.ui.online.OnlineWidgetSelectPane; import com.fr.design.mainframe.share.ui.online.ResourceLoader; +import com.fr.design.mainframe.share.util.DownloadUtils; +import com.fr.design.utils.gui.GUICoreUtils; import com.fr.form.share.bean.OnlineShareWidget; import com.fr.form.share.constants.ShareComponentConstants; import com.fr.log.FineLoggerFactory; import com.fr.stable.EncodeConstants; +import com.fr.stable.StringUtils; import com.fr.third.springframework.web.util.UriUtils; +import com.fr.transaction.CallBackAdaptor; +import com.fr.workspace.WorkContext; import org.jetbrains.annotations.NotNull; import javax.imageio.ImageIO; +import javax.swing.Action; import javax.swing.ImageIcon; +import javax.swing.JOptionPane; +import javax.swing.JPopupMenu; +import javax.swing.SwingWorker; +import java.awt.Desktop; import java.awt.Dimension; import java.awt.Image; +import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; /** * Created by kerry on 2020-11-22 */ public abstract class AbstractOnlineWidgetBlock extends PreviewWidgetBlock implements ResourceLoader { + private static final String ONLINE_WIDGET_DETAIL_FORMATTED_URL = "https://market.fanruan.com/reuse/%s"; private final OnlineWidgetSelectPane parentPane; private UILabel coverLabel; @@ -91,4 +121,168 @@ public abstract class AbstractOnlineWidgetBlock extends PreviewWidgetBlock template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + new SwingWorker() { + + @Override + protected Boolean doInBackground() { + FormTheme theme = fetchRemoteTheme(); + if (theme == null) { + return false; + } + + theme = ensureThemeHasUniqueName(theme, theme.getName()); + if (theme == null) { + return false; + } + + String themeName = theme.getName(); + saveThemeToConfig(theme, new CallBackAdaptor() { + @Override + public void afterCommit() { + super.afterCommit(); + int returnVal = FineJOptionPane.showConfirmDialog( + DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Share_Apply_Suitable_Theme_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Confirm"), + FineJOptionPane.OK_CANCEL_OPTION); + if (returnVal == JOptionPane.YES_OPTION) { + applyTheme(template, themeName); + } + } + }); + + return true; + + } + + @Override + protected void done() { + downloading = false; + } + }.execute(); + } + + private FormTheme fetchRemoteTheme() { + return DownloadUtils.downloadThemeFile(themePath); + } + + private FormTheme ensureThemeHasUniqueName(FormTheme theme, String expectedName) { + if (!FormThemeConfig.getInstance().contains(expectedName)) { + theme.setName(expectedName); + return theme; + } else { + String newName = (String) FineJOptionPane.showInputDialog( + DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Share_Rename_Suitable_Theme_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Rename"), + FineJOptionPane.QUESTION_MESSAGE, null, null, + expectedName); + + return StringUtils.isEmpty(newName) ? null : ensureThemeHasUniqueName(theme, newName); + } + } + + private void saveThemeToConfig(final FormTheme theme, CallBackAdaptor callback) { + FormThemeConfig.getInstance().addTheme(theme, true, callback); + } + + private void applyTheme(JTemplate template, final String name) { + TemplateThemeConfig config = template.getUsingTemplateThemeConfig(); + TemplateTheme theme = config.cachedFetch(name); + template.setTemplateTheme(theme); + } + } + + private class Jump2DetailAction extends UpdateAction { + public Jump2DetailAction() { + this.putValue(Action.SMALL_ICON, null); + this.setName(Toolkit.i18nText("Fine-Design_Share_Jump_To_Detail")); + } + + @Override + public void actionPerformed(ActionEvent e) { + OnlineShareWidget widget = getWidget(); + String id = widget.getId(); + if (StringUtils.isNotEmpty(id)) { + Desktop desktop = Desktop.getDesktop(); + try { + desktop.browse(new URI(String.format(ONLINE_WIDGET_DETAIL_FORMATTED_URL, id))); + } catch (IOException | URISyntaxException ioException) { + ioException.printStackTrace(); + } + } + } + } + } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/LocalWidgetBlock.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/LocalWidgetBlock.java index d92755502..c8a004d04 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/LocalWidgetBlock.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/LocalWidgetBlock.java @@ -195,30 +195,36 @@ public class LocalWidgetBlock extends PreviewWidgetBlock hidePreview(); ComponentCollector.getInstance().collectPopupJump(); Object source = e.getSource(); - Widget creatorSource; - String shareId; if (source instanceof LocalWidgetBlock) { LocalWidgetBlock no = (LocalWidgetBlock) e.getSource(); if (no == null) { return; } - shareId = no.getBindInfo().getId(); - creatorSource = getGroup().getElCaseEditorById(shareId); - if (creatorSource == null) { - ShareUIUtils.showErrorMessageDialog(Toolkit.i18nText("Fine-Design_Share_Drag_Error_Info")); + XCreator xCreator= transformXCreator(no); + if (xCreator == null) { return; } - creatorSource.setWidgetID(UUID.randomUUID().toString()); - ((AbstractBorderStyleWidget) creatorSource).addWidgetAttrMark(new SharableAttrMark(true)); - //tab布局WCardMainBorderLayout通过反射出来的大小是960*480 - String suitableTemplateThemeName = no.getWidget().getSuitableTemplateThemeName(); - XCreator xCreator = ShareComponentUtils.createThemedXCreator(creatorSource, suitableTemplateThemeName, shareId, no.getBindInfo()); WidgetToolBarPane.getTarget().startDraggingBean(xCreator); lastPressEvent = null; this.setBorder(null); } } + public XCreator transformXCreator(LocalWidgetBlock block) { + String shareId = block.getBindInfo().getId(); + Widget creatorSource = getGroup().getElCaseEditorById(shareId); + if (creatorSource == null) { + ShareUIUtils.showErrorMessageDialog(Toolkit.i18nText("Fine-Design_Share_Drag_Error_Info")); + return null; + } + creatorSource.setWidgetID(UUID.randomUUID().toString()); + ((AbstractBorderStyleWidget) creatorSource).addWidgetAttrMark(new SharableAttrMark(true)); + //tab布局WCardMainBorderLayout通过反射出来的大小是960*480 + String suitableTemplateThemeName = block.getWidget().getSuitableTemplateThemeName(); + XCreator xCreator = ShareComponentUtils.createThemedXCreator(creatorSource, suitableTemplateThemeName, shareId, block.getBindInfo()); + return xCreator; + } + @Override public void paint(Graphics g) { super.paint(g); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java index 8ad419b03..dffddc81c 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java @@ -112,7 +112,8 @@ public class OnlineWidgetBlock extends AbstractOnlineWidgetBlock { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); - if (!checkWidgetInstalled() && getDownloadIconRec().contains(e.getX(), e.getY())) { + boolean isLeftClickDownloadIcon = e.getButton() != MouseEvent.BUTTON3 && getDownloadIconRec().contains(e.getX(), e.getY()); + if (isLeftClickDownloadIcon && !checkWidgetInstalled()) { downLoadWidget(); } } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetPackageBlock.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetPackageBlock.java index 4b8458594..c3965f0da 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetPackageBlock.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetPackageBlock.java @@ -35,7 +35,7 @@ public class OnlineWidgetPackageBlock extends AbstractOnlineWidgetBlock { detailLabel.addMouseListener(new MouseClickListener() { @Override public void mouseClicked(MouseEvent e) { - parentPane.showWidgetDetailPane(widget.getId()); + parentPane.showWidgetDetailPane(widget); } }); southPane.add(detailLabel, BorderLayout.EAST); @@ -51,7 +51,6 @@ public class OnlineWidgetPackageBlock extends AbstractOnlineWidgetBlock { this.setPreferredSize(new Dimension(ShareComponentConstants.SHARE_PACKAGE_BLOCK_WIDTH, ShareComponentConstants.SHARE_PACKAGE_BLOCK_HEIGHT)); this.add(createSouthPane(widget, parentPane), BorderLayout.SOUTH); } - } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/local/LocalWidgetSelectPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/local/LocalWidgetSelectPane.java index 44bdd0fa5..90f1f30c2 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/local/LocalWidgetSelectPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/local/LocalWidgetSelectPane.java @@ -1,6 +1,8 @@ package com.fr.design.mainframe.share.ui.local; import com.fr.design.mainframe.share.AbstractWidgetSelectPane; +import com.fr.design.mainframe.share.ui.base.AbstractWidgetPopupPreviewPane; +import com.fr.design.mainframe.share.ui.base.LocalWidgetPopupPreviewPane; import com.fr.design.mainframe.share.ui.block.LocalWidgetBlock; import com.fr.form.share.DefaultSharableWidget; import com.fr.form.share.SharableWidgetProvider; @@ -22,7 +24,7 @@ import java.awt.event.MouseEvent; /** * created by Harrison on 2020/03/23 **/ -public class LocalWidgetSelectPane extends AbstractWidgetSelectPane { +public class LocalWidgetSelectPane extends AbstractWidgetSelectPane { private LocalWidgetBlock selectedBlock; private final Group group; @@ -105,6 +107,11 @@ public class LocalWidgetSelectPane extends AbstractWidgetSelectPane { return selectedBlock; } + @Override + protected AbstractWidgetPopupPreviewPane createPopupPreviewPane() { + return new LocalWidgetPopupPreviewPane(); + } + @Override protected Container getParentContainer() { return this.getParent().getParent(); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetPopupPreviewPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetPopupPreviewPane.java new file mode 100644 index 000000000..0bbc4851e --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetPopupPreviewPane.java @@ -0,0 +1,212 @@ +package com.fr.design.mainframe.share.ui.online; + +import com.fr.design.designer.IntervalConstants; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.share.ui.base.AbstractWidgetPopupPreviewPane; +import com.fr.design.mainframe.share.ui.block.PreviewWidgetBlock; +import com.fr.form.share.bean.OnlineShareWidget; +import com.fr.general.FRFont; +import com.fr.general.IOUtils; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.Toolkit; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/14 + */ +public class OnlineWidgetPopupPreviewPane extends AbstractWidgetPopupPreviewPane { + private static final int POPUP_WIDTH = 412; + private static final int POPUP_TOP_HEIGHT = 28; + private static final int POPUP_BOTTOM_HEIGHT = 54; + + private PreviewImagePane previewImagePane; + private UILabel versionLabel; + private UILabel downloadsLabel; + private UILabel priceLabel; + + private final JPanel suitableThemeNamePane; + private UILabel suitableThemeNameLabel; + + public OnlineWidgetPopupPreviewPane() { + setPreferredSize(new Dimension(POPUP_WIDTH, getPreferredSize().height)); + setLayout(new BorderLayout(0, 0)); + setOpaque(true); + setBackground(new Color(0xF0F0F1)); + + suitableThemeNamePane = createSuitableThemeNamePane(); + JPanel previewImagePane = createPreviewImagePane(); + JPanel widgetInfoPane = createWidgetInfoPane(); + + addComponents(suitableThemeNamePane, previewImagePane, widgetInfoPane); + } + + private JPanel createSuitableThemeNamePane() { + suitableThemeNameLabel = new UILabel(); + suitableThemeNameLabel.setOpaque(false); + suitableThemeNameLabel.setBackground(new Color(0xF5F5F7)); + suitableThemeNameLabel.setIcon(IOUtils.readIcon("/com/fr/design/icon/icon_predefined_style.png")); + suitableThemeNameLabel.setIconTextGap(IntervalConstants.INTERVAL_L6); + + JPanel content = FRGUIPaneFactory.createBorderLayout_S_Pane(); + content.setPreferredSize(new Dimension(POPUP_WIDTH, POPUP_TOP_HEIGHT)); + content.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + content.setOpaque(true); + content.setBackground(new Color(0xF5F5F7)); + content.add(suitableThemeNameLabel, BorderLayout.CENTER); + + JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane(); + container.add(content, BorderLayout.CENTER); + + JSeparator separator = new JSeparator(); + separator.setPreferredSize(new Dimension(POPUP_WIDTH, 1)); + separator.setBackground(new Color(0xE8E8E9)); + container.add(separator, BorderLayout.SOUTH); + + return container; + } + + private JPanel createPreviewImagePane() { + previewImagePane = new PreviewImagePane(); + JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane(); + container.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10)); + container.add(previewImagePane, BorderLayout.CENTER); + return container; + } + + private JPanel createWidgetInfoPane() { + versionLabel = new UILabel(); + versionLabel.setVerticalAlignment(SwingConstants.CENTER); + versionLabel.setFont(FRFont.getInstance(versionLabel.getFont()).deriveFont(12.0F)); + + downloadsLabel = new UILabel(); + downloadsLabel.setVerticalAlignment(SwingConstants.TOP); + downloadsLabel.setFont(FRFont.getInstance(downloadsLabel.getFont()).deriveFont(12.0F)); + + priceLabel = new UILabel(); + priceLabel.setVerticalAlignment(SwingConstants.CENTER); + priceLabel.setHorizontalAlignment(SwingConstants.RIGHT); + priceLabel.setFont(FRFont.getInstance(priceLabel.getFont()).deriveFont(14.0F)); + priceLabel.setForeground(new Color(0xE65251)); + + JPanel container = new JPanel(); + container.setPreferredSize(new Dimension(POPUP_WIDTH - 20, POPUP_BOTTOM_HEIGHT)); + container.setLayout(new GridBagLayout()); + container.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + + GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.BOTH; + + constraints.gridx = 0; + constraints.gridy = 0; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 1; + constraints.weighty = 1; + container.add(versionLabel, constraints); + + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridwidth = 1; + constraints.gridheight = 1; + constraints.weightx = 1; + constraints.weighty = 1; + container.add(downloadsLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 0; + constraints.gridwidth = 1; + constraints.gridheight = 2; + constraints.weightx = 1; + constraints.weighty = 2; + container.add(priceLabel, constraints); + + return container; + } + + private void addComponents(JComponent... components) { + if (components == null) { + return; + } + JComponent container = this; + for (int i = 0; i < components.length; i++) { + JComponent component = components[i]; + if (component != null) { + container.add(component, BorderLayout.NORTH); + if (i < components.length - 1) { + JPanel nextContainer = FRGUIPaneFactory.createBorderLayout_S_Pane(); + container.add(nextContainer, BorderLayout.CENTER); + container = nextContainer; + } + } + } + } + + @Override + public void populateBean(PreviewWidgetBlock block) { + OnlineShareWidget widget = block.getWidget(); + OnlineShareWidget parentPackage = widget.getParentPackage(); + if (parentPackage != null && StringUtils.isNotEmpty(parentPackage.getThemeName())) { + suitableThemeNamePane.setVisible(true); + suitableThemeNameLabel.setText(parentPackage.getThemeName()); + } else { + suitableThemeNamePane.setVisible(false); + } + + String priceText = "¥" + widget.getPrice(); + if (widget.getPrice() <= 0) { + priceText = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share_Price_Free"); + } + priceLabel.setText(priceText); + + versionLabel.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share_Version") + ": " + widget.getDesignerVersion()); + downloadsLabel.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share_Download_Times") + ": " + widget.getDownloadTimes()); + previewImagePane.setPreviewImage(block.getPreviewImage()); + + int height = (suitableThemeNamePane.isVisible() ? POPUP_TOP_HEIGHT : 0) + 10 + previewImagePane.getPreferredSize().height + POPUP_BOTTOM_HEIGHT; + setPreferredSize(new Dimension(POPUP_WIDTH, height)); + } + + private static class PreviewImagePane extends JPanel { + private static final Image DEFAULT_IMAGE = IOUtils.readImage("com/fr/base/images/share/component_error.png"); + private static final int PREVIEW_IMAGE_WIDTH = POPUP_WIDTH - 20; + private static final int STANDARD_DPI = 128; + + private Image previewImage; + + public void setPreviewImage(Image previewImage) { + this.previewImage = previewImage; + if (this.previewImage == null) { + this.previewImage = DEFAULT_IMAGE; + } + + int dpi = Toolkit.getDefaultToolkit().getScreenResolution(); + int imageWidth = this.previewImage.getWidth(null); + int imageHeight = this.previewImage.getHeight(null); + + double imageAspectRatio = (double) imageWidth / imageHeight; + int width = (PREVIEW_IMAGE_WIDTH * dpi) / STANDARD_DPI; + int height = (int) (width / imageAspectRatio); + setPreferredSize(new Dimension(width, height)); + } + + @Override + public void paint(Graphics g) { + g.drawImage(this.previewImage, 0, 0, getWidth(), getHeight(), null); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetSelectPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetSelectPane.java index 61e3ced83..c1a556fc5 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetSelectPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetSelectPane.java @@ -3,6 +3,7 @@ package com.fr.design.mainframe.share.ui.online; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.share.AbstractWidgetSelectPane; +import com.fr.design.mainframe.share.ui.base.AbstractWidgetPopupPreviewPane; import com.fr.design.mainframe.share.ui.base.LoadingPane; import com.fr.design.mainframe.share.ui.base.NoMatchPane; import com.fr.design.mainframe.share.ui.base.PagingFiledPane; @@ -30,7 +31,7 @@ import java.util.concurrent.ExecutionException; /** * Created by kerry on 2020-10-19 */ -public class OnlineWidgetSelectPane extends AbstractWidgetSelectPane { +public class OnlineWidgetSelectPane extends AbstractWidgetSelectPane { protected static final int H_GAP = 5; protected static final int V_GAP = 10; @@ -219,6 +220,11 @@ public class OnlineWidgetSelectPane extends AbstractWidgetSelectPane { } } + @Override + protected AbstractWidgetPopupPreviewPane createPopupPreviewPane() { + return new OnlineWidgetPopupPreviewPane(); + } + protected Container getParentContainer() { return this.getParent(); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackageSelectPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackageSelectPane.java index 2271f0c89..15b880483 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackageSelectPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackageSelectPane.java @@ -25,8 +25,8 @@ public class OnlineWidgetPackageSelectPane extends OnlineWidgetSelectPane { } - public void showWidgetDetailPane(String id) { - this.parentPane.showWidgetDetailPane(id); + public void showWidgetDetailPane(OnlineShareWidget widgetPackage) { + this.parentPane.showWidgetDetailPane(widgetPackage); } protected PreviewWidgetBlock createWidgetBlock(OnlineShareWidget provider) { diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java index 887b7c34a..662df3d8d 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java @@ -150,10 +150,11 @@ public class OnlineWidgetPackagesShowPane extends AbstractOnlineWidgetShowPane { return onlineShareWidgets.toArray(new OnlineShareWidget[onlineShareWidgets.size()]); } - public void showWidgetDetailPane(final String id) { + public void showWidgetDetailPane(final OnlineShareWidget widgetPackage) { + String id = widgetPackage.getId(); currentPackageId = id; boolean containsCache = cachePanelMap.containsKey(id); - onlineWidgetSelectPane = containsCache ? cachePanelMap.get(id) : new OnlineWidgetSelectPane(() -> ShareUtils.getPackageWidgets(id), 50); + onlineWidgetSelectPane = containsCache ? cachePanelMap.get(id) : new OnlineWidgetSelectPane(() -> ShareUtils.getPackageWidgets(widgetPackage), 50); downloadLabel.setVisible(!containsCache); showWidgetDetailPane(onlineWidgetSelectPane); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java b/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java index 96c2cc28c..69401c9c2 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java @@ -1,5 +1,7 @@ package com.fr.design.mainframe.share.util; +import com.fr.base.theme.FormTheme; +import com.fr.base.theme.TemplateTheme; import com.fr.design.DesignerEnvManager; import com.fr.design.extra.PluginConstants; import com.fr.form.share.base.CancelCheck; @@ -9,6 +11,11 @@ import com.fr.general.CloudCenter; import com.fr.log.FineLoggerFactory; import com.fr.stable.ProductConstants; import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLReaderHelper; +import com.fr.stable.xml.XMLableReader; +import com.fr.third.javax.xml.stream.XMLStreamException; import com.fr.third.org.apache.http.HttpEntity; import com.fr.third.org.apache.http.HttpException; import com.fr.third.org.apache.http.HttpStatus; @@ -23,8 +30,10 @@ import com.fr.third.org.apache.http.impl.client.HttpClients; import org.jetbrains.annotations.NotNull; import javax.crypto.Cipher; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; @@ -130,6 +139,32 @@ public class DownloadUtils { } } + public static FormTheme downloadThemeFile(String themePath) { + try { + CloseableHttpResponse fileRes = getHttpResponse(themePath); + if (fileRes.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) { + fileRes = getHttpResponse(fileRes.getHeaders("Location")[0].getValue()); + } + if (fileRes.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + HttpEntity entity = fileRes.getEntity(); + InputStream content = entity.getContent(); + XMLableReader reader = XMLReaderHelper.createXMLableReader(content, XMLPrintWriter.XML_ENCODER); + + FormTheme theme = new FormTheme(); + reader.readXMLObject(theme); + if (StringUtils.isNotEmpty(theme.getName())) { + return theme; + } + } else { + FineLoggerFactory.getLogger().info("download theme {} failed", themePath); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + return null; + } + private static CloseableHttpResponse getHttpResponse(String url, String id) throws Exception { //先登录一下。不然可能失败 CloseableHttpClient client = createClient(); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/util/InstallComponentHelper.java b/designer-form/src/main/java/com/fr/design/mainframe/share/util/InstallComponentHelper.java index 8c88de20b..437997e03 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/util/InstallComponentHelper.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/util/InstallComponentHelper.java @@ -21,7 +21,7 @@ import java.io.InputStream; public class InstallComponentHelper { private static final String PRE_INSTALL_PATH = "/com/fr/form/share/components"; - private static final String[] PRE_INSTALL_COMPONENTS = new String[]{ + public static final String[] PRE_INSTALL_COMPONENTS = new String[]{ "单行指标卡.f3df58b3-4302-4cab-ab77-caaf225de60a.reu", "分层雷达图-深色.49f8397c-e6a6-482a-acc7-46d8cec353a4.reu", "红绿灯表格-浅色.d0466992-328a-4ccf-ad67-6cbc844d669c.reu", @@ -45,6 +45,23 @@ public class InstallComponentHelper { } + public static String[] installPreComponent(int count) { + count = Math.max(Math.min(count, PRE_INSTALL_COMPONENTS.length), 0); + String[] installNames = new String[count]; + for (int index = 0; index < count; index ++) { + try { + String componentPath = PRE_INSTALL_COMPONENTS[index]; + InputStream inputStream = InstallComponentHelper.class.getResourceAsStream(StableUtils.pathJoin(PRE_INSTALL_PATH, componentPath)); + byte[] data = ResourceIOUtils.inputStream2Bytes(inputStream); + WorkContext.getWorkResource().write(StableUtils.pathJoin(ComponentPath.SHARE_PATH.path(), componentPath), data); + installNames[index] = componentPath; + } catch (Exception e) { + FineLoggerFactory.getLogger().error("install Component filed" + e.getMessage(), e); + } + } + return installNames; + } + private static boolean needPreInstallComponent() { try { //老用户或者组件库里已有组件,不预装组件 diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/NewFormPane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/NewFormPane.java index 2f0b446e3..7e5e40ef9 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/NewFormPane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/NewFormPane.java @@ -55,14 +55,10 @@ public class NewFormPane extends BasicPane { this.setLayout(FRGUIPaneFactory.createBorderLayout()); this.add(createModuleListPane(), BorderLayout.WEST); this.add(createTemplateManagePane(), BorderLayout.CENTER); + initWindow(); } - @Override - protected String title4PopupWindow() { - return Toolkit.i18nText("Fine-Design_New_Template"); - } - - public void showWindow() { + private void initWindow() { dialog = new UIDialog(DesignerContext.getDesignerFrame(), this) { @Override public void checkValid() throws Exception { @@ -73,9 +69,7 @@ public class NewFormPane extends BasicPane { dialog.addDialogActionListener(new DialogActionListener() { @Override public void doOk() { - if (selectedLayoutPane != null) { - NewFormPane.this.newForm(selectedLayoutPane.getTemplatePath()); - } + createLayoutForm(); } @Override @@ -87,6 +81,24 @@ public class NewFormPane extends BasicPane { GUICoreUtils.centerWindow(dialog); dialog.setTitle(this.title4PopupWindow()); dialog.setResizable(false); + } + + public void createLayoutForm() { + if (selectedLayoutPane != null) { + NewFormPane.this.newForm(selectedLayoutPane.getTemplatePath()); + } + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_New_Template"); + } + + public UIDialog getWindow() { + return dialog; + } + + public void showWindow() { dialog.setVisible(true); } diff --git a/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/5.frm b/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/5.frm index 5dde2178e..21c56152f 100644 --- a/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/5.frm +++ b/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/5.frm @@ -59,7 +59,7 @@ - + @@ -67,7 +67,7 @@ - + @@ -83,7 +83,7 @@ - + @@ -91,7 +91,7 @@ - + @@ -99,7 +99,7 @@ - + @@ -107,10 +107,18 @@ - + + + + + + + + + - + @@ -118,37 +126,38 @@ - + - + - + - + - + - - + + + diff --git a/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/6.frm b/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/6.frm index 3644ecff8..a76dbdb6b 100644 --- a/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/6.frm +++ b/designer-form/src/main/resources/com/fr/design/form/layouts/templates/multi/6.frm @@ -75,7 +75,7 @@ - + @@ -83,7 +83,7 @@ - + @@ -91,23 +91,23 @@ - + - + - + - + - + @@ -115,49 +115,67 @@ - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + - + + + + + - - - + diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/GuideIds.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/GuideIds.java new file mode 100644 index 000000000..efb9a7404 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/GuideIds.java @@ -0,0 +1,19 @@ +package com.fr.design.mainframe.guide; + +public class GuideIds { + public static class GuideVersion { + public static final String V11_0_0 = "11.0.0"; + } + + public static class GuideGroup { + public static final String F01 = "F01"; + public static final String F02 = "F02"; + } + + public static class Guide { + public static final String F001001 = "F001001"; + public static final String F001002 = "F001002"; + public static final String F002001 = "F002001"; + public static final String F002002 = "F002002"; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/GuideRegister.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/GuideRegister.java new file mode 100644 index 000000000..8ed6f3a30 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/GuideRegister.java @@ -0,0 +1,30 @@ +package com.fr.design.mainframe.guide; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.guide.base.GuideGroup; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.design.mainframe.guide.collect.GuideCollector; +import com.fr.design.mainframe.guide.creator.layout.ChangeLayoutComponentGuide; +import com.fr.design.mainframe.guide.creator.layout.UseLayoutAndComponentGuide; +import com.fr.design.mainframe.guide.creator.theme.DownloadComponentPackageGuide; +import com.fr.design.mainframe.guide.creator.theme.ThemeToggleGuide; + +public class GuideRegister { + public static void register() { + GuideCollector.getInstance().loadFromFile(); + registerGroup(); + registerGuide(); + } + + private static void registerGroup() { + GuideManager.getInstance().addGuideGroup(GuideIds.GuideVersion.V11_0_0, new GuideGroup(GuideIds.GuideGroup.F01, Toolkit.i18nText("Fine-Design_Guide_Group_F01_Name"))); + GuideManager.getInstance().addGuideGroup(GuideIds.GuideVersion.V11_0_0, new GuideGroup(GuideIds.GuideGroup.F02, Toolkit.i18nText("Fine-Design_Guide_Group_F02_Name"))); + } + + private static void registerGuide() { + GuideManager.getInstance().addGuide(GuideIds.GuideGroup.F01, UseLayoutAndComponentGuide.createGuide()); + GuideManager.getInstance().addGuide(GuideIds.GuideGroup.F01, ChangeLayoutComponentGuide.createGuide()); + GuideManager.getInstance().addGuide(GuideIds.GuideGroup.F02, ThemeToggleGuide.createGuide()); + GuideManager.getInstance().addGuide(GuideIds.GuideGroup.F02, DownloadComponentPackageGuide.createGuide()); + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java new file mode 100644 index 000000000..d19d20b8a --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java @@ -0,0 +1,121 @@ +package com.fr.design.mainframe.guide.creator; + +import com.fr.design.designer.beans.models.AddingModel; +import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XLayoutContainer; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.FormCreatorDropTarget; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.JForm; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.design.mainframe.guide.utils.ScreenImage; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; + +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.io.InputStream; +import java.util.UUID; + +public class GuideCreateUtils { + public static FormDesigner getFormDesigner() { + JForm jForm = (JForm) DesignerContext.getDesignerFrame().getSelectedJTemplate(); + FormDesigner designer = jForm.getFormDesign(); + return designer; + } + + public static Rectangle getXCreatorBoundsRelative2FormDesigner(XCreator xCreator) { + FormDesigner designer = getFormDesigner(); + Point point = SwingUtilities.convertPoint(xCreator, 0, 0, designer.getRootComponent()); + return new Rectangle(point.x + designer.getPaintX() - designer.getHorizontalScaleValue(), point.y + designer.getPaintY(), xCreator.getWidth(), xCreator.getHeight()); + } + + public static XCreator getXCreatorFormDesigner(String name) { + FormDesigner designer = getFormDesigner(); + XLayoutContainer rootComponent = designer.getRootComponent(); + return findXCreator(rootComponent, name); + + } + + public static XCreator findXCreator(XLayoutContainer container, String name) { + if (StringUtils.equals(container.toData().getWidgetName(), name)) { + return container; + } + for (Component component : container.getComponents()) { + if (component instanceof XLayoutContainer) { + XCreator xCreator = findXCreator((XLayoutContainer) component, name); + if (xCreator != null) { + return xCreator; + } + } else if (component instanceof XCreator) { + XCreator xCreator = (XCreator) component; + if (StringUtils.equals(xCreator.toData().getWidgetName(), name)) { + return xCreator; + } + } + } + return null; + } + + public static void addXCreatorToXLayoutContainer(XCreator xCreator, XLayoutContainer xLayoutContainer, boolean isDragComponent) { + if (xCreator == null) { + return; + } + FormDesigner designer = GuideCreateUtils.getFormDesigner(); + designer.getSelectionModel().selectACreator(xLayoutContainer); + + if (isDragComponent) { + designer.setAddingModel(new AddingModel(xCreator, 0,0)); + designer.setDropTarget(new FormCreatorDropTarget(designer)); + designer.repaint(); + } else { + designer.startDraggingBean(xCreator); + } + + FormCreatorDropTarget dropTarget = (FormCreatorDropTarget) designer.getDropTarget(); + dropTarget.adding(xLayoutContainer.getX(), xLayoutContainer.getY()); + + designer.getSelectionModel().selectACreator(xCreator); + } + + public static UILabel createModalTarget(JComponent component) { + ImageIcon ic = new ImageIcon(ScreenImage.createImageWithModal(component)); + return new UILabel(ic); + } + + public static Rectangle getPopupMenuBounds(JPopupMenu popupMenu, Component parent, int x, int y) { + Point point = SwingUtilities.convertPoint(parent,0,0, GuideManager.getInstance().getCurrentGuide().getGuideView().getRootPane()); + return new Rectangle(point.x + x, point.y + y, popupMenu.getWidth(), popupMenu.getHeight()); + } + + public static String openGuideFile(String sourcePath, String fileName, String suffix) { + String fileWorkPath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, UUID.randomUUID().toString() + suffix); + InputStream inputStream = GuideCreateUtils.class.getResourceAsStream(StableUtils.pathJoin(sourcePath, fileName + suffix)); + byte[] data = ResourceIOUtils.inputStream2Bytes(inputStream); + WorkContext.getWorkResource().write(fileWorkPath, data); + DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(fileWorkPath, false))); + return fileWorkPath; + } + + public static void deleteGuideFile(String filePath) { + WorkContext.getWorkResource().delete(filePath); + } + + public static void openDialogWithoutModal(JDialog dialog) { + dialog.setModal(false); + dialog.setVisible(true); + + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideSceneHelper.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideSceneHelper.java new file mode 100644 index 000000000..1571553cb --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideSceneHelper.java @@ -0,0 +1,89 @@ +package com.fr.design.mainframe.guide.creator; + +import com.fr.design.actions.file.WebPreviewUtils; +import com.fr.design.designer.creator.XCreator; +import com.fr.design.gui.ibutton.UIPreviewButton; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.CenterRegionContainerPane; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.design.mainframe.guide.scene.ClickScene; +import com.fr.design.mainframe.guide.scene.DisplayScene; +import com.fr.design.mainframe.guide.scene.GuideScene; +import com.fr.design.mainframe.guide.scene.GuideSceneLifecycleAdaptor; +import com.fr.design.mainframe.guide.tip.BubbleTip; +import com.fr.design.mainframe.guide.tip.GuideTip; +import com.fr.design.utils.ComponentUtils; + +import java.awt.Window; + +public class GuideSceneHelper { + public static GuideScene createWindowDisplayScene(Window window) { + DisplayScene scene = new DisplayScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addTarget(window); + return true; + } + }); + return scene; + } + + public static GuideScene createFormDesignerBodyDisplayScene() { + DisplayScene scene = new DisplayScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + FormDesigner formDesigner = GuideCreateUtils.getFormDesigner(); + scene.addTarget(formDesigner, GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(formDesigner.getRootComponent())); + return true; + } + }); + return scene; + } + + public static GuideScene createPreviewClickScene() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addClickTarget(ComponentUtils.findComponentByClass(CenterRegionContainerPane.getInstance(), UIPreviewButton.class), ClickScene.ClickType.LEFT); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_Base_Click_Preview"), null, GuideTip.Direction.BOTTOM, 0.5f, 0.2f); + return true; + } + + @Override + public void onComplete() { + GuideManager.getInstance().getCurrentGuide().getGuideView().dismissGuide(); + WebPreviewUtils.preview(DesignerContext.getDesignerFrame().getSelectedJTemplate()); + } + }); + return scene; + } + + public static GuideScene createSelectXCretorClickScene(String widgetName) { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + + XCreator xCreator = GuideCreateUtils.getXCreatorFormDesigner(widgetName); + scene.addClickTarget(GuideCreateUtils.getFormDesigner(), GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(xCreator), ClickScene.ClickType.LEFT); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_Base_Tip_Select_Widget"), BubbleTip.Direction.BOTTOM); + return super.prepared(); + } + + @Override + public void onComplete() { + super.onComplete(); + FormDesigner designer = GuideCreateUtils.getFormDesigner(); + XCreator xCreator = GuideCreateUtils.getXCreatorFormDesigner(widgetName); + designer.getSelectionModel().reset(); + designer.getSelectionModel().selectACreator(xCreator); + } + }); + return scene; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/ChangeLayoutComponentGuide.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/ChangeLayoutComponentGuide.java new file mode 100644 index 000000000..5703fd69f --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/ChangeLayoutComponentGuide.java @@ -0,0 +1,133 @@ +package com.fr.design.mainframe.guide.creator.layout; + +import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XLayoutContainer; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.CenterRegionContainerPane; +import com.fr.design.mainframe.FormArea; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.guide.GuideIds; +import com.fr.design.mainframe.guide.base.Guide; +import com.fr.design.mainframe.guide.base.GuideBuilder; +import com.fr.design.mainframe.guide.base.GuideLifecycleAdaptor; +import com.fr.design.mainframe.guide.creator.GuideCreateUtils; +import com.fr.design.mainframe.guide.creator.GuideSceneHelper; +import com.fr.design.mainframe.guide.scene.ClickScene; +import com.fr.design.mainframe.guide.scene.DisplayScene; +import com.fr.design.mainframe.guide.scene.DragScene; +import com.fr.design.mainframe.guide.scene.GuideScene; +import com.fr.design.mainframe.guide.scene.GuideSceneLifecycleAdaptor; +import com.fr.design.mainframe.guide.tip.GuideTip; +import com.fr.design.utils.ComponentUtils; +import java.awt.Rectangle; + +public class ChangeLayoutComponentGuide { + private static UIButton switchButton; + private static String filePath; + + public static Guide createGuide() { + GuideScene scene = createScene(); + scene.nextScene(createScene2()) + .nextScene(GuideSceneHelper.createFormDesignerBodyDisplayScene()) + .nextScene(createScene3()) + .nextScene(createScene4()) + .nextScene(GuideSceneHelper.createPreviewClickScene()); + + Guide guide = GuideBuilder.newInstance() + .setID(GuideIds.Guide.F001002) + .setName(Toolkit.i18nText("Fine-Design_Guide_Scene_F001002_Name")) + .setDescription(Toolkit.i18nText("Fine-Design_Guide_Scene_F001002_Description")) + .addScene(scene) + .registerLifecycle(new GuideLifecycleAdaptor() { + @Override + public boolean prepared() { + filePath = GuideCreateUtils.openGuideFile("/com/fr/report/guide/template", "layout_recommend", ".frm"); + return true; + } + + @Override + public void onEnd() { + GuideCreateUtils.deleteGuideFile(filePath); + } + }) + .getGuide(); + + return guide; + } + + private static GuideScene createScene() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + switchButton = (UIButton) ComponentUtils.findComponentByName(CenterRegionContainerPane.getInstance(), FormArea.FIX_LAYOUT_SWITCH_BUTTON); + scene.addClickTarget(switchButton, ClickScene.ClickType.LEFT, true); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001002_Tip_Click_No_Fix_Layout"), GuideTip.Direction.TOP); + return true; + } + }); + return scene; + } + + private static GuideScene createScene2() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addCustomTarget( + GuideCreateUtils.createModalTarget(switchButton.getComponentPopupMenu()), + GuideCreateUtils.getPopupMenuBounds(switchButton.getComponentPopupMenu(), switchButton,0, -switchButton.getComponentPopupMenu().getHeight()) + ); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001002_Tip_Select_Fix_layout"), null, GuideTip.Direction.RIGHT, 0.5f, 0.8f); + scene.addClickTarget(switchButton.getComponentPopupMenu().getComponent(1), ClickScene.ClickType.LEFT, true); + switchButton.getComponentPopupMenu().setVisible(false); + return true; + } + }); + return scene; + } + + private static GuideScene createScene3() { + DragScene scene = new DragScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addDragTarget(GuideCreateUtils.getFormDesigner(), GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(GuideCreateUtils.getXCreatorFormDesigner("absolute0")), DragScene.DragType.FROM); + scene.addDragTarget(GuideCreateUtils.getFormDesigner(), GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(GuideCreateUtils.getXCreatorFormDesigner("absolute1")), DragScene.DragType.TO); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001002_Tip_Drag"), GuideTip.Direction.TOP); + return super.prepared(); + } + + @Override + public void onComplete() { + FormDesigner formDesigner = GuideCreateUtils.getFormDesigner(); + + XCreator from = GuideCreateUtils.getXCreatorFormDesigner("absolute0"); + XLayoutContainer to = (XLayoutContainer) GuideCreateUtils.getXCreatorFormDesigner("absolute1"); + + formDesigner.getSelectionModel().removeCreator(from, from.getWidth(), from.getHeight()); + formDesigner.getSelectionModel().removeCreator(to, to.getWidth(),to.getHeight()); + + GuideCreateUtils.addXCreatorToXLayoutContainer(from, (XLayoutContainer) GuideCreateUtils.getXCreatorFormDesigner("box1"), true); + GuideCreateUtils.addXCreatorToXLayoutContainer(to, (XLayoutContainer) GuideCreateUtils.getXCreatorFormDesigner("box0"), true); + } + }); + return scene; + } + + private static GuideScene createScene4() { + DisplayScene scene = new DisplayScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + Rectangle rootBounds = GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(GuideCreateUtils.getFormDesigner().getRootComponent()); + Rectangle bound3 = GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(GuideCreateUtils.getXCreatorFormDesigner("absolute2")); + Rectangle targetBounds = new Rectangle(rootBounds.x, rootBounds.y, rootBounds.width, bound3.y - rootBounds.y); + scene.addTarget(GuideCreateUtils.getFormDesigner(), targetBounds); + return true; + } + }); + return scene; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java new file mode 100644 index 000000000..d38db10b5 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java @@ -0,0 +1,243 @@ +package com.fr.design.mainframe.guide.creator.layout; + +import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XOccupiedLayout; +import com.fr.design.dialog.UIDialog; +import com.fr.design.gui.imenu.UIHeadMenu; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.EastRegionContainerPane; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.FormWidgetDetailPane; +import com.fr.design.mainframe.NorthRegionContainerPane; +import com.fr.design.mainframe.guide.GuideIds; +import com.fr.design.mainframe.guide.base.Guide; +import com.fr.design.mainframe.guide.base.GuideBuilder; +import com.fr.design.mainframe.guide.base.GuideLifecycleAdaptor; +import com.fr.design.mainframe.guide.creator.GuideCreateUtils; +import com.fr.design.mainframe.guide.creator.GuideSceneHelper; +import com.fr.design.mainframe.guide.scene.ClickScene; +import com.fr.design.mainframe.guide.scene.DisplayScene; +import com.fr.design.mainframe.guide.scene.DragScene; +import com.fr.design.mainframe.guide.scene.GuideScene; +import com.fr.design.mainframe.guide.scene.GuideSceneLifecycleAdaptor; +import com.fr.design.mainframe.guide.tip.GuideTip; +import com.fr.design.mainframe.share.ui.block.LocalWidgetBlock; +import com.fr.design.mainframe.share.ui.local.LocalWidgetRepoPane; +import com.fr.design.mainframe.share.util.InstallComponentHelper; +import com.fr.design.utils.ComponentUtils; +import com.fr.design.widget.ui.designer.NewFormPane; +import com.fr.design.widget.ui.designer.PredefinedLayoutPane; +import com.fr.form.share.Group; +import com.fr.form.share.group.DefaultShareGroup; +import com.fr.form.share.group.DefaultShareGroupManager; +import java.awt.Component; +import java.util.ArrayList; +import java.util.List; + +public class UseLayoutAndComponentGuide { + private static UIHeadMenu fileHeadMenu; + private static NewFormPane newFormPane; + private static int autoInstallComponentCount; + private static String[] autoInstallComponentNames; + + public static Guide createGuide() { + GuideScene scene = createScene(); + scene.nextScene(createScene2()) + .nextScene(createScene3()) + .nextScene(createScene4()) + .nextScene(createScene5()) + .nextScene(createScene6("box0",0)) + .nextScene(createScene6("box1",1)) + .nextScene(createScene6("box2",2)) + .nextScene(GuideSceneHelper.createFormDesignerBodyDisplayScene()) + .nextScene(GuideSceneHelper.createPreviewClickScene()); + + + Guide guide = GuideBuilder.newInstance() + .setID(GuideIds.Guide.F001001) + .setName(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Name")) + .setDescription(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Description")) + .addScene(scene) + .registerLifecycle(new GuideLifecycleAdaptor() { + @Override + public boolean prepared() { + preloadShareComponent(); + Component component = ComponentUtils.findComponentByName(NorthRegionContainerPane.getInstance(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_File")); + fileHeadMenu = ((UIHeadMenu) component); + fileHeadMenu.setSelected(true); + fileHeadMenu.getPopupMenu().show(fileHeadMenu, 0, fileHeadMenu.getHeight()); + return true; + } + + @Override + public void onEnd() { + fileHeadMenu.setSelected(false); + fileHeadMenu.getPopupMenu().setVisible(false); + if (newFormPane != null) { + newFormPane.getWindow().dispose(); + } + removeAutoInstalledComponent(); + } + }) + .getGuide(); + + return guide; + } + + public static GuideScene createScene() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addClickTarget(fileHeadMenu.getMenuComponent(2), ClickScene.ClickType.LEFT); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Tip_New_Form"), GuideTip.Direction.BOTTOM); + scene.showScene(); + return true; + } + + @Override + public void onComplete() { + fileHeadMenu.setSelected(false); + fileHeadMenu.getPopupMenu().setVisible(false); + + newFormPane = new NewFormPane(); + newFormPane.getWindow().setModal(false); + newFormPane.showWindow(); + } + }); + return scene; + } + + public static GuideScene createScene2() { + DisplayScene scene = new DisplayScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addTarget(newFormPane.getWindow()); + return true; + } + }); + return scene; + } + + public static GuideScene createScene3() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + List componentList = ComponentUtils.findComponentsByClass(newFormPane.getWindow().getContentPane(), PredefinedLayoutPane.class); + if (componentList.get(1) != null) { + PredefinedLayoutPane layoutPane = (PredefinedLayoutPane) componentList.get(1); + scene.addClickTarget(layoutPane, ClickScene.ClickType.LEFT, true); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Tip_Select_Layout"), GuideTip.Direction.RIGHT); + } + + return super.prepared(); + } + }); + return scene; + } + + public static GuideScene createScene4() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + Component component = ComponentUtils.findComponentByName(newFormPane.getWindow().getContentPane(), UIDialog.OK_BUTTON); + if (component != null) { + scene.addClickTarget(component, ClickScene.ClickType.LEFT); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Tip_Click_Confirm"), GuideTip.Direction.TOP); + } + return super.prepared(); + } + + @Override + public void onComplete() { + newFormPane.createLayoutForm(); + newFormPane.getWindow().dispose(); + } + }); + return scene; + } + + public static GuideScene createScene5() { + DisplayScene scene = new DisplayScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + FormWidgetDetailPane.getInstance().switch2Local(); + EastRegionContainerPane.getInstance().switchTabTo(EastRegionContainerPane.KEY_WIDGET_LIB); + FormDesigner formDesigner = GuideCreateUtils.getFormDesigner(); + scene.addTarget(formDesigner, GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(formDesigner.getRootComponent())); + return true; + } + }); + return scene; + } + + public static GuideScene createScene6(String name, int blockIndex) { + DragScene scene = new DragScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addDragTarget(GuideCreateUtils.getFormDesigner(), GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(getXOccupiedLayout(name)), DragScene.DragType.TO); + scene.addDragTarget(getLocalWidgetBlock(blockIndex), DragScene.DragType.FROM); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Tip_Drag"), GuideTip.Direction.LEFT); + return super.prepared(); + } + + @Override + public void onComplete() { + LocalWidgetBlock block = getLocalWidgetBlock(blockIndex); + XCreator xCreator = block.transformXCreator(block); + XOccupiedLayout xOccupiedLayout = getXOccupiedLayout(name); + GuideCreateUtils.addXCreatorToXLayoutContainer(xCreator, xOccupiedLayout, false); + } + }); + return scene; + } + + private static XOccupiedLayout getXOccupiedLayout(String name) { + return (XOccupiedLayout) GuideCreateUtils.getXCreatorFormDesigner(name); + } + + private static LocalWidgetBlock getLocalWidgetBlock(int index) { + return (LocalWidgetBlock) ComponentUtils.findComponentsByClass(LocalWidgetRepoPane.getInstance(), LocalWidgetBlock.class).get(index); + } + + private static void preloadShareComponent() { + autoInstallComponentCount = 3; + try { + DefaultShareGroupManager.getInstance().refresh(); + Group shareGroup = DefaultShareGroupManager.getInstance().getGroup(DefaultShareGroup.GROUP_NAME); + if (shareGroup != null) { + DefaultShareGroup defaultShareGroup = (DefaultShareGroup) shareGroup; + int currentWidgetCount = defaultShareGroup.getAllBindInfoList().length; + autoInstallComponentCount = autoInstallComponentCount - (Math.min(autoInstallComponentCount, currentWidgetCount)); + } + if (autoInstallComponentCount > 0) { + autoInstallComponentNames = InstallComponentHelper.installPreComponent(autoInstallComponentCount); + DefaultShareGroupManager.getInstance().refresh(); + LocalWidgetRepoPane.getInstance().refreshAllGroupPane(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + static private void removeAutoInstalledComponent() { + Group shareGroup = DefaultShareGroupManager.getInstance().getGroup(DefaultShareGroup.GROUP_NAME); + if (shareGroup != null && autoInstallComponentNames != null) { + DefaultShareGroup defaultShareGroup = (DefaultShareGroup) shareGroup; + List installedList = new ArrayList<>(); + for (String componentName : autoInstallComponentNames) { + if (componentName != null) { + String uuid = componentName.split("\\.")[1]; + installedList.add(uuid); + } + } + defaultShareGroup.unInstallSelect(installedList); + LocalWidgetRepoPane.getInstance().refreshAllGroupPane(); + } + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/theme/DownloadComponentPackageGuide.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/theme/DownloadComponentPackageGuide.java new file mode 100644 index 000000000..8167c9a04 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/theme/DownloadComponentPackageGuide.java @@ -0,0 +1,22 @@ +package com.fr.design.mainframe.guide.creator.theme; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.guide.GuideIds; +import com.fr.design.mainframe.guide.base.Guide; +import com.fr.design.mainframe.guide.base.GuideBuilder; +import com.fr.design.mainframe.guide.base.GuideLifecycleAdaptor; + +public class DownloadComponentPackageGuide { + public static Guide createGuide() { + + Guide guide = GuideBuilder.newInstance() + .setID(GuideIds.Guide.F002002) + .setName(Toolkit.i18nText("Fine-Design_Guide_Scene_F002002_Name")) + .setDescription(Toolkit.i18nText("Fine-Design_Guide_Scene_F002002_Description")) + .registerLifecycle(new GuideLifecycleAdaptor() { + }) + .getGuide(); + + return guide; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/theme/ThemeToggleGuide.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/theme/ThemeToggleGuide.java new file mode 100644 index 000000000..67bee2d99 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/theme/ThemeToggleGuide.java @@ -0,0 +1,210 @@ +package com.fr.design.mainframe.guide.creator.theme; + +import com.fr.base.theme.FormTheme; +import com.fr.base.theme.FormThemeConfig; +import com.fr.base.theme.TemplateTheme; +import com.fr.design.designer.creator.XCreator; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.ibutton.UIButtonGroup; +import com.fr.design.gui.style.FollowingThemePane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.CenterRegionContainerPane; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.mainframe.EastRegionContainerPane; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.JForm; +import com.fr.design.mainframe.guide.GuideIds; +import com.fr.design.mainframe.guide.base.Guide; +import com.fr.design.mainframe.guide.base.GuideBuilder; +import com.fr.design.mainframe.guide.base.GuideLifecycleAdaptor; +import com.fr.design.mainframe.guide.base.GuideManager; +import com.fr.design.mainframe.guide.creator.GuideCreateUtils; +import com.fr.design.mainframe.guide.creator.GuideSceneHelper; +import com.fr.design.mainframe.guide.scene.ClickScene; +import com.fr.design.mainframe.guide.scene.DisplayScene; +import com.fr.design.mainframe.guide.scene.GuideScene; +import com.fr.design.mainframe.guide.scene.GuideSceneLifecycleAdaptor; +import com.fr.design.mainframe.guide.tip.BubbleTip; +import com.fr.design.mainframe.guide.tip.GuideTip; +import com.fr.design.mainframe.theme.TemplateThemeBlock; +import com.fr.design.mainframe.theme.dialog.TemplateThemeUsingDialog; +import com.fr.design.utils.ComponentUtils; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.stable.StableUtils; +import com.fr.stable.project.ProjectConstants; +import com.teamdev.jxbrowser.internal.ui.ToolkitKey; + +import javax.swing.SwingUtilities; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.Timer; +import java.util.TimerTask; + +public class ThemeToggleGuide { + private static TemplateThemeUsingDialog themeDialog; + private static String filePath; + + public static Guide createGuide() { + GuideScene scene1 = createScene1(); + + scene1.nextScene(createScene2()) + .nextScene(createScene3()) + .nextScene(createScene4()) + .nextScene(GuideSceneHelper.createFormDesignerBodyDisplayScene()) + .nextScene(GuideSceneHelper.createSelectXCretorClickScene("chart00")) + .nextScene(createScene5()) + .nextScene(GuideSceneHelper.createFormDesignerBodyDisplayScene()) + .nextScene(GuideSceneHelper.createPreviewClickScene()); + + Guide guide = GuideBuilder.newInstance() + .setID(GuideIds.Guide.F002001) + .setName(Toolkit.i18nText("Fine-Design_Guide_Scene_F002001_Name")) + .setDescription(Toolkit.i18nText("Fine-Design_Guide_Scene_F002001_Description")) + .addScene(scene1) + .registerLifecycle(new GuideLifecycleAdaptor() { + @Override + public boolean prepared() { + filePath = GuideCreateUtils.openGuideFile("/com/fr/report/guide/template", "toggle_theme", ".frm"); + return true; + } + + @Override + public void onEnd() { + GuideCreateUtils.deleteGuideFile(filePath); + } + }) + .getGuide(); + + return guide; + } + + private static GuideScene createScene1() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + TemplateTheme templateTheme = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getTemplateTheme(); + Component component = ComponentUtils.findComponentByName(CenterRegionContainerPane.getInstance(), templateTheme.getName()); + scene.addClickTarget(component, ClickScene.ClickType.LEFT); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F002001_Tip_Click_Template_Theme"), GuideTip.Direction.BOTTOM); + return true; + } + + @Override + public void onComplete() { + showTemplateThemeUsingDialog(); + } + }); + + return scene; + } + + private static GuideScene createScene2() { + DisplayScene scene = new DisplayScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + scene.addTarget(themeDialog); + scene.showScene(); + } + },100); + return true; + } + + @Override + public void onComplete() { + + } + }); + + return scene; + } + + private static GuideScene createScene3() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + String name = FormThemeConfig.getInstance().getThemeNames().get(4); + Component component = ComponentUtils.findComponentByName(themeDialog.getContentPane(), name); + if (component instanceof TemplateThemeBlock) { + scene.addClickTarget(component, ClickScene.ClickType.LEFT, true); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F002001_Tip_Toggle_Theme"), BubbleTip.Direction.TOP); + } + return true; + } + + @Override + public void onComplete() { + } + }); + return scene; + } + + private static GuideScene createScene4() { + ClickScene scene = new ClickScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + scene.addClickTarget(ComponentUtils.findComponentByName(themeDialog, TemplateThemeUsingDialog.COMPLETE_BUTTON), ClickScene.ClickType.LEFT, true); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F002001_Tip_Click_Confirm"), BubbleTip.Direction.TOP); + return true; + } + }); + return scene; + } + + private static GuideScene createScene5() { + ClickScene scene = new ClickScene(); + final UIButtonGroup[] uiButtonGroup = new UIButtonGroup[1]; + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + Component target2 = ComponentUtils.findComponentByClass(EastRegionContainerPane.getInstance(), FollowingThemePane.class); + target2 = ComponentUtils.findComponentByClass(target2, UIButtonGroup.class); + if (target2 != null) { + uiButtonGroup[0] = (UIButtonGroup) target2; + target2 = ((UIButtonGroup) target2).getButton(0); + scene.addClickTarget(target2, ClickScene.ClickType.LEFT); + scene.addBubbleTip( + Toolkit.i18nText("Fine-Design_Guide_Scene_F002001_Tip_Toggle_Follow_Theme"), + Toolkit.i18nText("Fine-Design_Guide_Scene_F002001_Tip_Toggle_Follow_Theme_Description"), + GuideTip.Direction.BOTTOM, + 0.5f, + 0.8f + ); + scene.showScene(); + } + } + },1000); + return false; + } + + @Override + public void onComplete() { + if (uiButtonGroup[0] != null) { + uiButtonGroup[0].setSelectedIndex(0); + } + } + }); + return scene; + } + + private static void showTemplateThemeUsingDialog() { + if (themeDialog == null) { + DesignerFrame designerFrame = DesignerContext.getDesignerFrame(); + themeDialog = new TemplateThemeUsingDialog<>(designerFrame, DesignerContext.getDesignerFrame().getSelectedJTemplate(), FormThemeConfig.getInstance()); + } + themeDialog.setModal(false); + themeDialog.setVisible(true); + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/entry/GuideEntryPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/entry/GuideEntryPane.java new file mode 100644 index 000000000..2058dc601 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/entry/GuideEntryPane.java @@ -0,0 +1,79 @@ +package com.fr.design.mainframe.guide.entry; + +import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.guide.collect.GuideCollector; +import com.fr.design.mainframe.guide.ui.BubbleHintDialog; +import com.fr.design.mainframe.guide.ui.GuideManageDialog; +import com.fr.general.IOUtils; + +import javax.swing.SwingUtilities; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class GuideEntryPane extends BasicPane { + private static GuideEntryPane guideEntryPane; + + private UIButton button; + + public static GuideEntryPane getGuideEntryPane() { + if (guideEntryPane == null) { + guideEntryPane = new GuideEntryPane(); + } + return guideEntryPane; + } + @Override + protected String title4PopupWindow() { + return null; + } + + private GuideEntryPane() { + setPreferredSize(new Dimension(24, 24)); + setLayout(new BorderLayout()); + button = new UIButton(); + button.setIcon(IOUtils.readIcon("/com/fr/design/mainframe/guide/guide.png")); + button.setToolTipText(Toolkit.i18nText(Toolkit.i18nText("Fine-Design_Guide_Entry_Name"))); + button.set4ToolbarButton(); + button.setRolloverEnabled(false); + this.add(button); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + GuideManageDialog.getInstance().showDialog(); + } + }); + this.setBackground(UIConstants.TEMPLATE_TAB_PANE_BACKGROUND); + this.addAncestorListener(new AncestorListener() { + @Override + public void ancestorAdded(AncestorEvent event) { + if (!GuideCollector.getInstance().isShowHint()) { + BubbleHintDialog dialog = new BubbleHintDialog(DesignerContext.getDesignerFrame()); + Point point = new Point(0,0); + SwingUtilities.convertPointToScreen(point, GuideEntryPane.this); + Dimension size = GuideEntryPane.this.getSize(); + dialog.setLocationRelativeTo(GuideEntryPane.this); + dialog.setLocation(point.x - 187,point.y + size.height); + dialog.setVisible(true); + } + } + + @Override + public void ancestorRemoved(AncestorEvent event) { + } + + @Override + public void ancestorMoved(AncestorEvent event) { + } + }); + + } + +} diff --git a/designer-realize/src/main/java/com/fr/start/MainDesigner.java b/designer-realize/src/main/java/com/fr/start/MainDesigner.java index 835658c9e..ce355076b 100644 --- a/designer-realize/src/main/java/com/fr/start/MainDesigner.java +++ b/designer-realize/src/main/java/com/fr/start/MainDesigner.java @@ -31,6 +31,7 @@ import com.fr.design.mainframe.JWorkBook; import com.fr.design.mainframe.alphafine.component.AlphaFinePane; import com.fr.design.mainframe.bbs.UserInfoLabel; import com.fr.design.mainframe.bbs.UserInfoPane; +import com.fr.design.mainframe.guide.entry.GuideEntryPane; import com.fr.design.module.ChartPreStyleAction; import com.fr.design.notification.SnapChatAllTypes; import com.fr.design.notification.ui.NotificationCenterPane; @@ -422,6 +423,10 @@ public class MainDesigner extends BaseDesigner { return AlphaFinePane.getAlphaFinePane(); } + public Component createGuideEntryPane() { + return GuideEntryPane.getGuideEntryPane(); + } + public Component createNotificationCenterPane(){ return NotificationCenterPane.getNotificationCenterPane(); } diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java b/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java index e2959552f..921d8efe7 100644 --- a/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java +++ b/designer-realize/src/main/java/com/fr/start/module/DesignerActivator.java @@ -61,6 +61,8 @@ import com.fr.design.mainframe.form.FormECCompositeProvider; import com.fr.design.mainframe.form.FormECDesignerProvider; import com.fr.design.mainframe.form.FormElementCaseDesigner; import com.fr.design.mainframe.form.FormReportComponentComposite; +import com.fr.design.mainframe.guide.GuideRegister; +import com.fr.design.mainframe.guide.collect.GuideCollector; import com.fr.design.mainframe.loghandler.DesignerLogAppender; import com.fr.design.mainframe.share.constants.ShareEntryKey; import com.fr.design.mainframe.socketio.DesignerSocketIO; @@ -225,6 +227,7 @@ public class DesignerActivator extends Activator implements Prepare { InformationCollector.getInstance().collectStartTime(); SharableManager.start(); + GuideRegister.register(); } private void createPluginListener() {