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 50fc31566..c348b49e7 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 @@ -1439,6 +1439,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..003f22908 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java @@ -0,0 +1,160 @@ +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.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() { + 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(); + end(); + GuideCompleteDialog.getInstance().showDialog(getName()); + } + + public void terminate() { + if (lifecycle != null) { + lifecycle.onTerminate(); + } + end(); + } + + public void end() { + GuideManager.getInstance().setCurrentGuide(null); + guideView.dismissGuide(); + if (lifecycle != null) { + lifecycle.onEnd(); + } + } + + 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..d9c2ac061 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideManager.java @@ -0,0 +1,88 @@ +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 Guide currentGuide; + private List guideGroupList; + private static GuideManager guideManager; + + public static GuideManager getInstance() { + if (guideManager == null) { + guideManager = new GuideManager(); + } + return guideManager; + } + + public GuideManager() { + guideGroupList = new ArrayList<>(); + } + + public Guide getCurrentGuide() { + return currentGuide; + } + + public void setCurrentGuide(Guide currentGuide) { + this.currentGuide = currentGuide; + } + + public void addGuideGroup(GuideGroup guideGroup) { + this.guideGroupList.add(guideGroup); + } + + public void addGuide(String groupId, Guide guide) { + for (GuideGroup group : guideGroupList) { + if (StringUtils.equals(groupId, group.getID())) { + group.addGuide(guide); + } + } + } + + public List getGuideGroupList() { + return guideGroupList; + } + + public List getAllGuide() { + List guideList = new ArrayList<>(); + for (GuideGroup group : getGuideGroupList()) { + for (Guide guide : group.getGuideList()) { + guideList.add(guide); + } + } + return guideList; + } + + public GuideGroup getGuideGroup(String groupId) { + for (GuideGroup group : getGuideGroupList()) { + if (StringUtils.equals(groupId, group.getID())) { + return group; + } + } + return null; + } + + public Guide getGuide(String guideId) { + for (GuideGroup group : getGuideGroupList()) { + for (Guide guide : group.getGuideList()) { + if (StringUtils.equals(guideId, guide.getID())) { + return guide; + } + } + } + + return null; + } + + public void completeAll() { + for (GuideGroup group : 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/GuideView.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java new file mode 100644 index 000000000..eb72c7ebd --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java @@ -0,0 +1,132 @@ +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.JWindow; +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.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; + +public class GuideView extends JWindow{ + 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.window = window; + this.modalColor = Color.BLACK; + this.modalOpacity = 0.6f; + this.setPreferredSize(window.getSize()); + this.setSize(window.getSize()); + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + setBg(); + window.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + setLocationRelativeTo(window); + } + + @Override + public void componentMoved(ComponentEvent e) { + setLocation(window.getLocation()); + } + }); + window.addWindowFocusListener(new WindowFocusListener() { + @Override + public void windowGainedFocus(WindowEvent e) { + requestFocus(); + setLocationRelativeTo(window); + } + + @Override + public void windowLostFocus(WindowEvent e) { + + } + }); + this.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (scene == null) { + invoker.terminate(); + } + if (scene instanceof AbstractGuideScene && invoker != null) { + if (((AbstractGuideScene) scene).getHighlightList().size() == 0) { + invoker.terminate(); + } + } + } + }); + + } + + public GuideView(Window window, Guide guide) { + this(DesignerContext.getDesignerFrame()); + 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() { + 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() { + this.getLayeredPane().removeAll(); + revalidate(); + repaint(); + this.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..4247f2ca2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java @@ -0,0 +1,386 @@ +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.Color; +import java.awt.Component; +import java.awt.Dimension; +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 GuideScene nextScene; + private SceneFilter sceneFilter; + private GuideSceneLifecycle lifecycle; + private GuideView container; + private List targetList; + private List highlightList; + private Component nextButton; + + public AbstractGuideScene() { + this.setLayout(null); + this.setOpaque(false); + targetList = new ArrayList<>(); + highlightList = 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 if (component instanceof Window){ + Window window = (Window) component; + window.toFront(); + window.requestFocus(); + image = ScreenImage.createImage(component); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + container.toFront(); + container.requestFocus(); + } + }); + } else { + image = captureImage(component); + } + targetList.add(component); + highlightList.add(getTargetComponentWithImage(image, rectangle)); + return true; + } catch (AWTException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据设计器上选定区域获取高亮视图,采用截屏的方式 + * @param rectangle 选定区域,相对屏幕 + * @return + */ + public boolean addTarget(Rectangle rectangle) { + try { + targetList.add(null); + container.setVisible(false); + BufferedImage image = captureImage(rectangle); + highlightList.add(getTargetComponentWithImage(image, rectangle)); + return true; + } catch (AWTException e) { + e.printStackTrace(); + 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()); + 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(); + 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 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(); + 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(); + + if (lifecycle != null) { + lifecycle.onComplete(); + } + if (sceneFilter != null) { + nextScene = sceneFilter.getFilterScene(); + } + if (nextScene != null) { + if (nextScene instanceof AbstractGuideScene) { + ((AbstractGuideScene) nextScene).setContainer(container); + } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + 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(); + } +} 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..6b0f4b0d5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java @@ -0,0 +1,90 @@ +package com.fr.design.mainframe.guide.scene; + +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())); + } +} 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..7d954150f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java @@ -0,0 +1,83 @@ +package com.fr.design.mainframe.guide.tip; + +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 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) { + 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..8d529f33b --- /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); + 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(); + GuideManageDialog.getInstance().showDialog(); + } + }); + + 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..3f25d1308 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java @@ -0,0 +1,226 @@ +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.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); + 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 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(); + JPanel expandContent = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 5); + for (GuideGroup guideGroup : GuideManager.getInstance().getGuideGroupList()) { + JPanel guideGroupCard = createGuideGroupCard(guideGroup); + expandContent.add(guideGroupCard); + } + ExpandPane expandPane = new ExpandPane(Toolkit.i18nText("Fine-Design_Guide_Manager_Dialog_Version_Title", "11.0.0"), expandContent); + scrollContent.add(expandPane); + 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..7c722d7de --- /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.5f)); + 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/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/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..3bfbf494d 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); // 获取该组件所在的焦点容器 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/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/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..a1869ed79 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 { @@ -87,6 +83,18 @@ public class NewFormPane extends BasicPane { GUICoreUtils.centerWindow(dialog); dialog.setTitle(this.title4PopupWindow()); dialog.setResizable(false); + } + + @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-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..29210c5dd --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/GuideIds.java @@ -0,0 +1,15 @@ +package com.fr.design.mainframe.guide; + +public class GuideIds { + 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..deafa66fa --- /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(new GuideGroup(GuideIds.GuideGroup.F01, Toolkit.i18nText("Fine-Design_Guide_Group_F01_Name"))); + GuideManager.getInstance().addGuideGroup(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..29653c9b8 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java @@ -0,0 +1,118 @@ +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.designer.creator.XOccupiedLayout; +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 sun.java2d.xr.XcbRequestCounter; + +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +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(), 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); + } +} 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..c27663e4f --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideSceneHelper.java @@ -0,0 +1,63 @@ +package com.fr.design.mainframe.guide.creator; + +import com.fr.design.actions.file.WebPreviewUtils; +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.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; + } +} 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..f39683b71 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java @@ -0,0 +1,242 @@ +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, true); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Tip_Click_Confirm"), GuideTip.Direction.TOP); + } + return super.prepared(); + } + + @Override + public void onComplete() { + 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..a0b72ec5c --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/theme/ThemeToggleGuide.java @@ -0,0 +1,237 @@ +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(createScene5()) + .nextScene(createScene6()) + .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; + } + + public void onShow() { + GuideManager.getInstance().getCurrentGuide().getGuideView().toFront(); // brings to front without needing to setAlwaysOnTop + GuideManager.getInstance().getCurrentGuide().getGuideView().requestFocus(); + } + + @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() { + DisplayScene scene = new DisplayScene(); + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + JForm jForm = (JForm) DesignerContext.getDesignerFrame().getSelectedJTemplate(); + scene.addTarget(jForm.getFormDesign()); + return true; + } + + @Override + public void onShow() { + JForm jForm = (JForm) DesignerContext.getDesignerFrame().getSelectedJTemplate(); + FormDesigner designer = jForm.getFormDesign(); + XCreator xCreator = (XCreator) designer.getRootComponent().getComponent(0); + jForm.getFormDesign().getSelectionModel().reset(); + jForm.getFormDesign().getSelectionModel().selectACreator(xCreator); + } + }); + return scene; + } + + private static GuideScene createScene6() { + ClickScene scene = new ClickScene(); + final UIButtonGroup[] uiButtonGroup = new UIButtonGroup[1]; + scene.registerLifecycle(new GuideSceneLifecycleAdaptor() { + @Override + public boolean prepared() { + JForm jForm = (JForm) DesignerContext.getDesignerFrame().getSelectedJTemplate(); + FormDesigner designer = jForm.getFormDesign(); + XCreator xCreator = (XCreator) designer.getRootComponent().getComponent(0); + scene.addTarget(designer, GuideCreateUtils.getXCreatorBoundsRelative2FormDesigner(xCreator)); + + 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 + ); + } + return true; + } + + @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); + } + if (!themeDialog.isVisible()) { + themeDialog.setVisible(true); + } + themeDialog.requestFocus(); + } +} 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() {