diff --git a/designer-base/src/main/java/com/fr/design/gui/icombobox/LazyComboBoxTest.java b/designer-base/src/main/java/com/fr/design/gui/icombobox/LazyComboBoxTest.java index 37e9db154..9906749b7 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icombobox/LazyComboBoxTest.java +++ b/designer-base/src/main/java/com/fr/design/gui/icombobox/LazyComboBoxTest.java @@ -3,10 +3,10 @@ */ package com.fr.design.gui.icombobox; +import com.fr.design.gui.UILookAndFeel; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.log.FineLoggerFactory; -import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; import javax.swing.JFrame; import javax.swing.JPanel; @@ -23,7 +23,7 @@ import java.awt.event.ItemListener; public class LazyComboBoxTest { public static void main(String[] args) { try { - UIManager.setLookAndFeel(new WindowsLookAndFeel()); + UIManager.setLookAndFeel(new UILookAndFeel()); } catch (UnsupportedLookAndFeelException e1) { FineLoggerFactory.getLogger().error(e1.getMessage(), e1); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java index bcac7f946..a9d9281e9 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java @@ -856,7 +856,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt BorderLayout.CENTER); - this.setSize(340, 180); + this.setSize(380, 180); this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Mkdir")); this.setResizable(false); this.setAlwaysOnTop(true); diff --git a/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java b/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java index e07daf93b..36b86cb89 100644 --- a/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java +++ b/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java @@ -62,6 +62,10 @@ public class FineEmbedServerActivator extends Activator { tomcat.setPort(DesignerEnvManager.getEnvManager().getEmbedServerPort()); // 设置解码uri使用的字符编码 tomcat.getConnector().setURIEncoding(EncodeConstants.ENCODING_UTF_8); + // 参考 https://jira.atlassian.com/browse/CONFSERVER-57582 + // https://tomcat.apache.org/tomcat-8.5-doc/config/http.html + // 8.5.x 请求参数带特殊字符被tomcat拒绝 []|{}^\`"<> + tomcat.getConnector().setProperty("relaxedQueryChars", "[]|{}^\`"<>"); setMaxPostSize(); String docBase = new File(WorkContext.getCurrent().getPath()).getParent(); diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java index ff89f059b..42db0d850 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java @@ -77,12 +77,13 @@ public class SelectionModel { * @param e 鼠标事件 */ public void selectACreatorAtMouseEvent(MouseEvent e) { + //单选因为要先从已选择的组件中筛选一遍,所以先选择再reset + XCreator comp = designer.getComponentAt(e); if (e.getButton() == MouseEvent.BUTTON3 || (!InputEventBaseOnOS.isControlDown(e) && !e.isShiftDown())) { // 如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件 selection.reset(); } else { //按下Ctrl或者shift键时鼠标可以进行多选,两次点击同一控件就取消选中 - XCreator comp = designer.getComponentAt(e); XLayoutContainer topLayout = XCreatorUtils.getHotspotContainer(comp).getTopLayout(); if (topLayout != null && !topLayout.isEditable()) { comp = topLayout; @@ -93,9 +94,9 @@ public class SelectionModel { selection.removeCreator(selected); } } + comp = designer.getComponentAt(e); } // 获取e所在的组件 - XCreator comp = designer.getComponentAt(e); selectACreator(comp); } @@ -309,6 +310,7 @@ public class SelectionModel { designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_DELETED); setSelectedCreator(isInPara ? designer.getParaComponent() : designer.getRootComponent()); + designer.getTopXCreators().refresh(); // 触发事件 diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XButton.java b/designer-form/src/main/java/com/fr/design/designer/creator/XButton.java index 44996df8c..9a627ab2c 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XButton.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XButton.java @@ -308,5 +308,4 @@ public class XButton extends XWidgetCreator { } } - } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java b/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java index b0f6e1158..f846f29bd 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java @@ -17,6 +17,8 @@ import com.fr.design.mainframe.CoverReportPane; import com.fr.design.mainframe.EditingMouseListener; import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.HelpDialogManager; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; +import com.fr.design.mainframe.widget.topxcreator.TopXCreator; import com.fr.design.mainframe.widget.editors.WLayoutBorderStyleEditor; import com.fr.design.module.DesignModuleFactory; import com.fr.form.ui.BaseChartEditor; @@ -258,6 +260,7 @@ public class XChartEditor extends XBorderStyleWidgetCreator { (e.getClickCount() == 2 || designer.getCursor().getType() == Cursor.HAND_CURSOR); displayCoverPane(!isEditing); selectionModel.selectACreatorAtMouseEvent(e); + editingMouseListener.refreshTopXCreator(isEditing); if (editingMouseListener.stopEditing()) { if (this != (XCreator) designer.getRootComponent()) { @@ -357,4 +360,35 @@ public class XChartEditor extends XBorderStyleWidgetCreator { public boolean supportMobileStyle() { return false; } + + @Override + public BasicTopXCreator getTopXCreator() { + return new TopXChart(this); + } + + private class TopXChart extends TopXCreator { + private final DesignerEditor designerEditor; + + public TopXChart(XCreator creator) { + super(creator); + designerEditor = creator.getDesignerEditor(); + Rectangle bounds = getBounds(); + designerEditor.getEditorTarget().setBounds(bounds.x + 1, bounds.y + 1, bounds.width - 2, bounds.height - 2); + } + + /** + * 更新designerEditor的大小 + */ + protected void resetSize(Rectangle bounds) { + super.resetSize(bounds); + designerEditor.getEditorTarget().setBounds(bounds.x + 1, bounds.y + 1, bounds.width - 2, bounds.height - 2); + } + + @Override + public void paint(Graphics g) { + designerEditor.paintEditor(g, this.getSize()); + super.paint(g); + } + } + } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java index dcb693883..20f278811 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java @@ -19,16 +19,22 @@ import com.fr.design.mainframe.CoverReportPane; import com.fr.design.mainframe.EditingMouseListener; import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.NoSupportAuthorityEdit; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; import com.fr.design.mainframe.WidgetPropertyPane; import com.fr.design.utils.gui.LayoutUtils; import com.fr.form.ui.Widget; import com.fr.form.ui.container.WTitleLayout; import com.fr.stable.Constants; +import com.fr.stable.CoreGraphHelper; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; +import com.fr.third.javax.annotation.Nullable; import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.ImageIcon; import javax.swing.JComponent; +import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.Border; import java.awt.BorderLayout; @@ -38,6 +44,7 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; import java.beans.IntrospectionException; import java.util.ArrayList; import java.util.List; @@ -539,6 +546,8 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo selectionModel.selectACreatorAtMouseEvent(e); } + editingMouseListener.refreshTopXCreator(); + if (editingMouseListener.stopEditing() && this != designer.getRootComponent()) { ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, this); editingMouseListener.startEditing(this, adapter.getDesignerEditor(), adapter); @@ -798,10 +807,37 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo /** * 是否支持共享-现只支持报表块、图表、tab块、绝对布局 - * @return */ public boolean isSupportShared() { return false; } + /** + * 获得该组件的顶层显示组件 + */ + @Nullable + public BasicTopXCreator getTopXCreator() { + return new BasicTopXCreator(this) { + @Override + protected void addComponent() { + Icon icon = new ImageIcon(getImage()); + JLabel jLabel = new JLabel(icon, JLabel.CENTER); + jLabel.setSize(getSize()); + this.add(jLabel); + } + }; + } + + /** + * 获得组件的图像 + */ + public BufferedImage getImage() { + BufferedImage image = CoreGraphHelper.createBufferedImage(getWidth(), getHeight()); + Graphics g = image.createGraphics(); + this.paint(g); + return image; + } + + + } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XElementCase.java b/designer-form/src/main/java/com/fr/design/designer/creator/XElementCase.java index ec06a1597..d84fd2e0c 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XElementCase.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XElementCase.java @@ -13,6 +13,8 @@ import com.fr.design.mainframe.widget.editors.ElementCaseToolBarEditor; import com.fr.design.mainframe.widget.editors.PaddingMarginEditor; import com.fr.design.mainframe.widget.editors.WLayoutBorderStyleEditor; import com.fr.design.mainframe.widget.propertypane.BrowserFitPropertyEditor; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; +import com.fr.design.mainframe.widget.topxcreator.TopXCreator; import com.fr.form.FormElementCaseContainerProvider; import com.fr.form.FormElementCaseProvider; import com.fr.form.FormProvider; @@ -319,6 +321,7 @@ public class XElementCase extends XBorderStyleWidgetCreator implements FormEleme public void respondClick(EditingMouseListener editingMouseListener,MouseEvent e){ HelpDialogManager.getInstance().setPane(coverPanel); super.respondClick(editingMouseListener, e); + editingMouseListener.refreshTopXCreator(); if (this.isHelpBtnOnFocus()) { coverPanel.setMsgDisplay(e); } else { @@ -370,4 +373,20 @@ public class XElementCase extends XBorderStyleWidgetCreator implements FormEleme public boolean isSupportShared() { return true; } + + @Override + public BasicTopXCreator getTopXCreator() { + return new TopXElementCase(this); + } + + private class TopXElementCase extends TopXCreator { + private UILabel imageLabel; + + public TopXElementCase(XCreator creator) { + super(creator); + imageLabel = initImageBackground(); + add(imageLabel); + } + } + } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteBodyLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteBodyLayout.java index 6190ffaeb..5db000e18 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteBodyLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteBodyLayout.java @@ -7,6 +7,7 @@ import com.fr.design.form.util.XCreatorConstants; import com.fr.design.fun.WidgetPropertyUIProvider; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.widget.editors.WLayoutBorderStyleEditor; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; import com.fr.form.ui.container.WAbsoluteBodyLayout; import com.fr.stable.core.PropertyChangeAdapter; @@ -130,4 +131,9 @@ public class XWAbsoluteBodyLayout extends XWAbsoluteLayout { public boolean isSupportShared() { return false; } + + @Override + public BasicTopXCreator getTopXCreator() { + return null; + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteLayout.java index b98c2a952..98143a7ea 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XWAbsoluteLayout.java @@ -25,6 +25,8 @@ import com.fr.design.mainframe.FormArea; import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.WidgetHelpDialog; import com.fr.design.mainframe.WidgetPropertyPane; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; +import com.fr.design.mainframe.widget.topxcreator.TopXCreator; import com.fr.form.ui.Connector; import com.fr.form.ui.Widget; import com.fr.form.ui.container.WAbsoluteLayout; @@ -542,6 +544,7 @@ public class XWAbsoluteLayout extends XLayoutContainer { selectionModel.selectACreatorAtMouseEvent(e); designer.repaint(); + editingMouseListener.refreshTopXCreator(isEditing); if (editingMouseListener.stopEditing()) { if (this != designer.getRootComponent()) { @@ -606,4 +609,9 @@ public class XWAbsoluteLayout extends XLayoutContainer { return super.getWidgetPropertyUIProviders(); } } + + @Override + public BasicTopXCreator getTopXCreator() { + return new TopXCreator(this); + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XWParameterLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/XWParameterLayout.java index cb288c98c..384ee07b6 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XWParameterLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XWParameterLayout.java @@ -15,6 +15,7 @@ import com.fr.design.mainframe.widget.editors.BooleanEditor; import com.fr.design.mainframe.widget.editors.WidgetDisplayPosition; import com.fr.design.mainframe.widget.renderer.BackgroundRenderer; import com.fr.design.mainframe.widget.renderer.WidgetDisplayPositionRender; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; import com.fr.form.ui.container.WBorderLayout; import com.fr.form.ui.container.WFitLayout; import com.fr.form.ui.container.WParameterLayout; @@ -251,4 +252,10 @@ public class XWParameterLayout extends XWAbsoluteLayout { return false; } + @Override + public BasicTopXCreator getTopXCreator() { + return null; + } + + } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XWTitleLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/XWTitleLayout.java index 2cc56ee9b..b8fe8f004 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XWTitleLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XWTitleLayout.java @@ -7,6 +7,7 @@ import com.fr.design.designer.beans.LayoutAdapter; import com.fr.design.designer.beans.adapters.layout.FRTitleLayoutAdapter; import com.fr.design.form.layout.FRTitleLayout; import com.fr.design.fun.WidgetPropertyUIProvider; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; import com.fr.form.ui.Label; import com.fr.form.ui.Widget; import com.fr.form.ui.WidgetTitle; @@ -189,4 +190,9 @@ public class XWTitleLayout extends DedicateLayoutContainer { XCreator creator = getPropertyDescriptorCreator(); return creator.getWidgetPropertyUIProviders(); } + + @Override + public BasicTopXCreator getTopXCreator() { + return getEditingChildCreator().getTopXCreator(); + } } \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardMainBorderLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardMainBorderLayout.java index 25da3e775..3ad1463b9 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardMainBorderLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardMainBorderLayout.java @@ -16,16 +16,15 @@ import com.fr.design.designer.creator.XCreatorUtils; import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.creator.XWBorderLayout; import com.fr.design.designer.creator.XWidgetCreator; -import com.fr.design.designer.properties.mobile.MobileBooKMarkUsePropertyUI; -import com.fr.design.form.util.FormDesignerUtils; import com.fr.design.form.util.XCreatorConstants; -import com.fr.design.fun.WidgetPropertyUIProvider; import com.fr.design.icon.IconPathConstants; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.EditingMouseListener; import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.WidgetHelpDialog; import com.fr.design.mainframe.WidgetPropertyPane; +import com.fr.design.mainframe.widget.topxcreator.BasicTopXCreator; +import com.fr.design.mainframe.widget.topxcreator.TopXCreator; import com.fr.form.event.Listener; import com.fr.form.ui.CardSwitchButton; import com.fr.form.ui.LayoutBorderStyle; @@ -438,6 +437,7 @@ public class XWCardMainBorderLayout extends XWBorderLayout { setEditable(isEditing); selectionModel.selectACreatorAtMouseEvent(e); + editingMouseListener.refreshTopXCreator(isEditing); designer.repaint(); if (editingMouseListener.stopEditing()) { @@ -514,4 +514,9 @@ public class XWCardMainBorderLayout extends XWBorderLayout { public boolean isSupportShared() { return true; } + + @Override + public BasicTopXCreator getTopXCreator() { + return new TopXCreator(this); + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java index 49f246256..010a38217 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java @@ -248,6 +248,7 @@ public class XWCardTagLayout extends XWHorizontalBoxLayout { if (e.getClickCount() <= 1) { selectionModel.selectACreatorAtMouseEvent(e); } + editingMouseListener.refreshTopXCreator(); if (editingMouseListener.stopEditing()) { if (this != designer.getRootComponent()) { ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, this); diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTitleLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTitleLayout.java index babc54b31..f6f6b2b41 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTitleLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTitleLayout.java @@ -204,6 +204,7 @@ public class XWCardTitleLayout extends XWBorderLayout { if (e.getClickCount() <= 1) { selectionModel.selectACreatorAtMouseEvent(e); } + editingMouseListener.refreshTopXCreator(); if (editingMouseListener.stopEditing()) { if (this != designer.getRootComponent()) { diff --git a/designer-form/src/main/java/com/fr/design/designer/treeview/ComponentTreeCellRenderer.java b/designer-form/src/main/java/com/fr/design/designer/treeview/ComponentTreeCellRenderer.java index 16ec4405d..78b606a7f 100644 --- a/designer-form/src/main/java/com/fr/design/designer/treeview/ComponentTreeCellRenderer.java +++ b/designer-form/src/main/java/com/fr/design/designer/treeview/ComponentTreeCellRenderer.java @@ -4,6 +4,7 @@ import com.fr.design.constants.UIConstants; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XCreatorUtils; import com.fr.design.gui.ilable.UILabel; +import com.fr.log.FineLoggerFactory; import javax.swing.Icon; import javax.swing.JTree; @@ -23,7 +24,12 @@ public class ComponentTreeCellRenderer extends DefaultTreeCellRenderer { if (value instanceof XCreator) { String name = ((XCreator) value).toData().getWidgetName(); setText(name); - Icon icon = XCreatorUtils.getCreatorIcon((XCreator) value); + Icon icon = null; + try { + icon = XCreatorUtils.getCreatorIcon((XCreator) value); + } catch (Exception e) { + FineLoggerFactory.getLogger().info("{} has not icon or has been deleted", name); + } if (icon != null) { setIcon(icon); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java b/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java index a2f295f87..2fdd1f8f1 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java @@ -2,6 +2,7 @@ package com.fr.design.mainframe; import com.fr.design.constants.UIConstants; import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XCreatorUtils; import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.treeview.ComponentTreeCellRenderer; import com.fr.design.designer.treeview.ComponentTreeModel; @@ -15,7 +16,9 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTree; import javax.swing.SwingUtilities; +import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import java.awt.BorderLayout; @@ -30,6 +33,9 @@ import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; public class ComponentTree extends JTree { @@ -81,6 +87,7 @@ public class ComponentTree extends JTree { public void setSelectionPath(TreePath path) { // 不管点击哪一项,都要先退出编辑状态(图表、报表块、绝对布局、tab块) designer.stopEditing(path); + designer.getTopXCreators().refresh(); super.setSelectionPath(path); } @@ -129,6 +136,7 @@ public class ComponentTree extends JTree { setSelectionPaths(treepath); if (treepath.length > 0) { scrollPathToVisible(treepath[0]); + //expandPath(treepath[0]); } } @@ -228,6 +236,39 @@ public class ComponentTree extends JTree { repaint(); } + /** + * 获得树的展开路径 + * */ + public void getExpandNodes(List searchList) { + getExpandNodes((XLayoutContainer)designer.getTopContainer(),searchList); + } + + public void getExpandNodes(XLayoutContainer container, List searchList) { + for (int i = 0, size = container.getXCreatorCount(); i < size; i++) { + XCreator creator = container.getXCreator(i); + TreePath treePath=buildTreePath(creator); + if(isExpanded(treePath)) searchList.add(treePath); + if (creator instanceof XLayoutContainer) { + getExpandNodes((XLayoutContainer) creator, searchList); + } + } + } + + /** + * 将树按照展开路径进行展开 + * */ + public void expandNodes(List list){ + for(TreePath treePath:list) { + if (treePath.getLastPathComponent() instanceof XLayoutContainer) { + XLayoutContainer creator= (XLayoutContainer) treePath.getLastPathComponent(); + if (XCreatorUtils.getParentXLayoutContainer(creator) == null) { + continue; + } + expandPath(treePath); + } + } + } + private TreePath buildTreePath(Component comp) { ArrayList path = new ArrayList(); Component parent = comp; diff --git a/designer-form/src/main/java/com/fr/design/mainframe/CoverPane.java b/designer-form/src/main/java/com/fr/design/mainframe/CoverPane.java index d692eaa5e..a4c401440 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/CoverPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/CoverPane.java @@ -8,7 +8,7 @@ import com.fr.general.IOUtils; import com.fr.stable.Constants; -import javax.swing.JPanel; +import javax.swing.JComponent; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; @@ -28,7 +28,7 @@ import java.awt.Rectangle; * Date: 14-7-24 * Time: 上午9:09 */ -public class CoverPane extends JPanel { +public class CoverPane extends JComponent { private UIButton editButton; private AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java index 183c0b08c..6dcf7f34b 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java @@ -210,6 +210,7 @@ public class EditingMouseListener extends MouseInputAdapter { */ public void mouseReleased(MouseEvent e) { MouseEvent transEvent = new MouseEvent(e.getComponent(), MouseEvent.MOUSE_CLICKED, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton()); + MouseEvent clickEvent = new MouseEvent(e.getComponent(), MouseEvent.MOUSE_CLICKED, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton()); int oldX = e.getX(); int oldY = e.getY(); offsetEventPoint(e); @@ -234,14 +235,21 @@ public class EditingMouseListener extends MouseInputAdapter { lastPressEvent = null; lastXCreator = null; e.translatePoint(oldX - e.getX(), oldY - e.getY()); - if (pressX != oldX || pressY != oldY) { + if (isAutoFire(transEvent, clickEvent)) { // click只有在mouseReleased和mousePressed前后x/y坐标相等时才会被触发在mouseReleased之后 // 但是当使用者来回点击切换时 存在mouseReleased和mousePressed前后x/y坐标不相等的情况 即鼠标按下去的位置和鼠标释放的位置不相等 存在偏移 // 当这种偏移很小时 看起来就好像是点击了 实际上是手抖了或者鼠标轻微滑动了 所以这里对这种情况要有容错处理 - mouseClicked(transEvent); + mouseClicked(clickEvent); } } + private boolean isAutoFire(MouseEvent transEvent, MouseEvent clickEvent ) { + offsetEventPoint(transEvent); + XCreator xCreator = designer.getComponentAt(transEvent); + return (pressX != clickEvent.getX() || pressY != clickEvent.getY()) + && xCreator != null && xCreator.acceptType(XCardSwitchButton.class); + } + private void mouseDraggingRelease(MouseEvent e) { // 当前鼠标所在的组件 XCreator hoveredComponent = designer.getComponentAt(e.getX(), e.getY()); @@ -308,6 +316,7 @@ public class EditingMouseListener extends MouseInputAdapter { XCreator component = designer.getComponentAt(e); setCoverPaneNotDisplay(component, e, false); + designer.getTopXCreators().displayCoverPane(e); if (processTopLayoutMouseMove(component, e)) { return; @@ -692,6 +701,7 @@ public class EditingMouseListener extends MouseInputAdapter { currentXCreator.stopEditing(); currentXCreator = null; currentEditor = null; + refreshTopXCreator(); return true; } return true; @@ -719,4 +729,19 @@ public class EditingMouseListener extends MouseInputAdapter { } currentEditor.getEditorTarget().setBounds(bounds); } + + /** + * 刷新顶层组件 + * */ + public void refreshTopXCreator(boolean isEditing){ + designer.refreshTopXCreator(isEditing); + } + + /** + * 刷新顶层组件 + * */ + public void refreshTopXCreator(){ + refreshTopXCreator(false); + } + } 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 e5ce0f726..5cb0157f9 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 @@ -35,7 +35,9 @@ import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.creator.XWAbsoluteBodyLayout; import com.fr.design.designer.creator.XWAbsoluteLayout; import com.fr.design.designer.creator.XWBorderLayout; +import com.fr.design.designer.creator.XWFitLayout; import com.fr.design.designer.creator.XWParameterLayout; +import com.fr.design.designer.creator.XWTitleLayout; import com.fr.design.designer.properties.FormWidgetAuthorityEditPane; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.event.DesignerOpenedListener; @@ -43,6 +45,7 @@ import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.form.util.XCreatorConstants; import com.fr.design.fun.RightSelectionHandlerProvider; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; +import com.fr.design.mainframe.widget.topxcreator.TopXCreators; import com.fr.design.menu.MenuDef; import com.fr.design.menu.ShortCut; import com.fr.design.menu.ToolBarDef; @@ -121,6 +124,7 @@ public class FormDesigner extends TargetComponent
implements TreeSelection private FormArea formArea; private ConnectorHelper connectorHelper; private boolean isReportBlockEditing = false; + private TopXCreators topXCreators; //组件重叠 private boolean isWidgetsIntersect = false; @@ -184,6 +188,8 @@ public class FormDesigner extends TargetComponent implements TreeSelection new FormDesignerDropTarget(this);// 添加Drag and Drop. this.switchAction = switchAction; + topXCreators=new TopXCreators(this); + add(topXCreators); // 必须刷新"参数/控件树"面板,否则,若最近一次打开模版为 cpt,重启设计器,打开 frm,控件树消失 populateParameterPropertyPane(); @@ -825,6 +831,40 @@ public class FormDesigner extends TargetComponent implements TreeSelection return null; } + /** + * 从已选择的组件中找x,y所在的组件 + */ + private XCreator xCreatorAt(int x, int y, XCreator[] xCreators) { + for (XCreator creator : xCreators) { + if (creator == null || !creator.isVisible()) { + continue; + } + if (creator instanceof XWAbsoluteBodyLayout || creator instanceof XWFitLayout || creator instanceof XWParameterLayout) { + continue; + } + x -= creator.getX(); + y -= creator.getY(); + Rectangle rect = ComponentUtils.computeVisibleRect(creator); + // 判断是否处于交叉区域 + if (!isIntersectArea(x, y, rect)) { + continue; + } + if (creator instanceof XWTitleLayout) { + return creator.getEditingChildCreator(); + } + return creator; + } + return null; + } + + /** + * 刷新顶层组件 + * */ + public void refreshTopXCreator(boolean isEditing){ + topXCreators.refresh(); + topXCreators.setVisible(!isEditing); + } + private boolean isIntersectArea(int x, int y, Rectangle rect) { return x >= rect.getX() && (x <= (rect.getX() + rect.getWidth())) && (y >= rect.getY()) && (y <= (rect.getY() + rect.getHeight())); @@ -984,6 +1024,10 @@ public class FormDesigner extends TargetComponent implements TreeSelection invalidateLayout(); } + public TopXCreators getTopXCreators() { + return topXCreators; + } + public StateModel getStateModel() { return stateModel; } @@ -1001,9 +1045,19 @@ public class FormDesigner extends TargetComponent implements TreeSelection return getComponentAt(p.x, p.y); } + /** + * 先从已选择则的组件中去找,再遍历root去找 + * */ @Override public XCreator getComponentAt(int x, int y) { - return getComponentAt(x, y, null); + XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() ? paraComponent : rootComponent; + if (container == null) { + container = rootComponent; + } + int relativeX = x + (int) (formArea.getHorizontalValue() / scale) - container.getX(); + int relativeY = y + (int) (formArea.getVerticalValue() / scale) - container.getY(); + XCreator result = xCreatorAt(relativeX, relativeY, selectionModel.getSelection().getSelectedCreators()); + return result == null ? getComponentAt(x, y, null) : result; } @Nullable @@ -1311,6 +1365,10 @@ public class FormDesigner extends TargetComponent implements TreeSelection } } + public void paintTopCreators(Graphics clipg){ + topXCreators.paint(clipg); + } + /** * 重置组件边界 */ diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java index 26547229b..2a8e255e8 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java @@ -84,6 +84,7 @@ public class FormDesignerUI extends ComponentUI { // 设计参数面板 repaintPara(g, paraComponent, c); } + repaintTopXCreators(g); if (designer.isDrawLineMode() && designer.getDrawLineHelper().drawLining()) { designer.getDrawLineHelper().drawAuxiliaryLine(g); @@ -445,4 +446,8 @@ public class FormDesignerUI extends ComponentUI { ComponentUtils.resetBuffer(dbcomponents); } + private void repaintTopXCreators(Graphics g){ + designer.paintTopCreators(g); + } + } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormHierarchyTreePane.java b/designer-form/src/main/java/com/fr/design/mainframe/FormHierarchyTreePane.java index 6822422b2..f94475a76 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormHierarchyTreePane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormHierarchyTreePane.java @@ -24,12 +24,14 @@ import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import javax.swing.tree.TreePath; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.util.ArrayList; +import java.util.List; /** @@ -89,10 +91,13 @@ public class FormHierarchyTreePane extends FormDockView implements HierarchyTree /** * 刷新 */ + //TODO 太乱了,需要重写,监听器里加了监听器是什么意思,每次调用该方法都会添加一个新的监听器 public void refreshDockingView() { FormDesigner formDesigner = this.getEditingFormDesigner(); + List list = new ArrayList<>(); removeAll(); if (this.componentTree != null) { + componentTree.getExpandNodes(list); this.componentTree.removeAll(); } if (formDesigner == null) { @@ -100,6 +105,8 @@ public class FormHierarchyTreePane extends FormDockView implements HierarchyTree return; } componentTree = new ComponentTree(formDesigner); + //保证删除组件后组件树不收起 + componentTree.expandNodes(list); formDesigner.addDesignerEditListener(new DesignerEditListener() { @Override public void fireCreatorModified(DesignerEvent evt) { diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/BasicTopXCreator.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/BasicTopXCreator.java new file mode 100644 index 000000000..e49aaf6e8 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/BasicTopXCreator.java @@ -0,0 +1,70 @@ +package com.fr.design.mainframe.widget.topxcreator; + +import com.fr.design.designer.creator.XCreator; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.WidgetPropertyPane; +import com.fr.design.utils.ComponentUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; + +/** + * @Author: Yuan.Wang + * @Date: 2020/8/31 + */ +public class BasicTopXCreator extends JComponent { + private FormDesigner designer; + private XCreator creator; + + public BasicTopXCreator(XCreator creator) { + this.designer = WidgetPropertyPane.getInstance().getEditingFormDesigner(); + this.creator = creator; + init(); + } + + private void init() { + setOpaque(false); + setBackground(null); + setLayout(null); + setBounds(calculateBounds()); + addComponent(); + } + + + //子类可能会重写该方法 + protected void resetSize(Rectangle bounds) { + //do nothing + } + + protected void addComponent() { + + } + + /** + * 重新设置组件大小 + * */ + public void resizeTopXCreator() { + Rectangle bounds=calculateBounds(); + setBounds(bounds); + resetSize(bounds); + } + + public void displayCoverPane(MouseEvent e, boolean visible) {} + + /** + * 计算显示大小 + * */ + private Rectangle calculateBounds() { + Rectangle rect = ComponentUtils.getRelativeBounds(creator); + Rectangle bounds = new Rectangle(0, 0, creator.getWidth(), creator.getHeight()); + bounds.x += (rect.x - designer.getHorizontalScaleValue()); + bounds.y += (rect.y - designer.getVerticalScaleValue()); + return bounds; + } + + @Override + public void paint(Graphics g) { + super.paint(g); + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/TopXCreator.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/TopXCreator.java new file mode 100644 index 000000000..42371a44f --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/TopXCreator.java @@ -0,0 +1,49 @@ +package com.fr.design.mainframe.widget.topxcreator; + +import com.fr.design.designer.creator.XCreator; +import com.fr.design.mainframe.CoverReportPane; + +import java.awt.*; +import java.awt.event.MouseEvent; + +/** + * @Author: Yuan.Wang + * @Date: 2020/8/26 + */ +public class TopXCreator extends BasicTopXCreator { + + private final CoverReportPane coverPanel; + + public TopXCreator(XCreator creator) { + super(creator); + coverPanel = new CoverReportPane(); + init(); + } + + private void init() { + coverPanel.setSize(getSize()); + coverPanel.setVisible(false); + add(coverPanel); + } + + + protected void resetSize(Rectangle bounds) { + coverPanel.setSize(getSize()); + } + + /** + * 设置是否显示蒙层 + * */ + public void displayCoverPane(boolean visible) { + coverPanel.setVisible(visible); + } + + /** + * 依据鼠标事件和visible设置是否显示蒙层 + * */ + public void displayCoverPane(MouseEvent event, boolean visible) { + boolean isVisible = visible && getBounds().contains(event.getX(), event.getY()); + coverPanel.setVisible(isVisible); + } + +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/TopXCreators.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/TopXCreators.java new file mode 100644 index 000000000..f271c3cc1 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/topxcreator/TopXCreators.java @@ -0,0 +1,101 @@ +package com.fr.design.mainframe.widget.topxcreator; + +import com.fr.design.designer.beans.events.DesignerEvent; +import com.fr.design.designer.beans.models.SelectionModel; +import com.fr.design.designer.creator.XCreator; +import com.fr.design.mainframe.FormDesigner; + +import java.awt.event.MouseEvent; + +import javax.swing.*; +import java.awt.*; + + +/** + * 需要显示顶层的组件层 + * + * @Author: Yuan.Wang + * @Date: 2020/8/25 + */ +public class TopXCreators extends JComponent { + final private FormDesigner designer; + + public TopXCreators(FormDesigner designer) { + this.designer = designer; + init(); + } + + private void init() { + setLayout(null); + setVisible(false); + setBackground(null); + setOpaque(false); + designer.addDesignerEditListener(e -> { + if (e.getCreatorEventID() == DesignerEvent.CREATOR_EDITED) { + refresh(); + } + }); + } + + /** + * 选中的组件有变化时刷新 + */ + public void refresh() { + removeAll(); + addXCreators(); + } + + @Override + public void paint(Graphics g) { + setSize(designer.getSize()); + resizeTopXCreators(); + super.paint(g); + } + + @Override + public void setVisible(boolean aFlag) { + super.setVisible(aFlag); + for (int i = 0, count = getComponentCount(); i < count; i++) { + if (getComponent(i) instanceof TopXCreator) { + TopXCreator xCreator = (TopXCreator) getComponent(i); + xCreator.displayCoverPane(aFlag); + } + } + repaint(); + } + + /** + * 依据MouseEvent坐标来设置是否显示蒙层 + */ + public void displayCoverPane(MouseEvent e) { + for (int i = 0, count = getComponentCount(); i < count; i++) { + BasicTopXCreator xCreator = (BasicTopXCreator) getComponent(i); + xCreator.displayCoverPane(e, isVisible()); + } + } + + /** + * 加入被选择的组件 + */ + private void addXCreators() { + SelectionModel selectionModel = designer.getSelectionModel(); + XCreator[] xCreators = selectionModel.getSelection().getSelectedCreators(); + for (XCreator creator : xCreators) { + BasicTopXCreator topXCreator = creator.getTopXCreator(); + if (topXCreator != null) { + add(topXCreator); + } + } + } + + /** + * 更新顶层组件的位置和大小 + */ + private void resizeTopXCreators() { + for (int i = 0, count = getComponentCount(); i < count; i++) { + BasicTopXCreator topXCreator = (BasicTopXCreator) getComponent(i); + topXCreator.resizeTopXCreator(); + } + repaint(); + } +} diff --git a/designer-realize/src/main/java/com/fr/start/fx/FastGifImage.java b/designer-realize/src/main/java/com/fr/start/fx/FastGifImage.java deleted file mode 100644 index 9eb3ecef2..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/FastGifImage.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.fr.start.fx; - -import com.sun.imageio.plugins.gif.GIFImageReader; -import com.sun.imageio.plugins.gif.GIFImageReaderSpi; -import com.sun.javafx.tk.ImageLoader; -import com.sun.javafx.tk.PlatformImage; -import javafx.animation.KeyFrame; -import javafx.animation.Timeline; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.scene.image.WritableImage; -import javafx.util.Duration; - -import javax.imageio.stream.FileImageInputStream; -import java.io.File; -import java.lang.ref.WeakReference; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.util.regex.Pattern; - -/** - * 边加载边播放的gif加载器 - * - * @author daniel - */ -public class FastGifImage extends WritableImage { - private String url; - private int gifCount; - - public FastGifImage(String url, int w, int h) { - super(w, h); - this.url = validateUrl(url); - seekCount(); - initialize(); - } - - /** - * 给出gif帧数,加快加载速度 - * - * @param url gif url - * @param gifCount gif帧数 - * @param w 宽 - * @param h 高 - */ - public FastGifImage(String url, int gifCount, int w, int h) { - super(w, h); - this.url = validateUrl(url); - this.gifCount = gifCount; - initialize(); - } - - private void seekCount() { - try { - GIFImageReaderSpi spi = new GIFImageReaderSpi(); - GIFImageReader gifReader = (GIFImageReader) spi.createReaderInstance(); - gifReader.setInput(new FileImageInputStream(new File(new URI(url)))); - gifCount = gifReader.getNumImages(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static final Pattern URL_QUICKMATCH = Pattern.compile("^\\p{Alpha}[\\p{Alnum}+.-]*:.*$"); - - private static String validateUrl(final String url) { - if (url == null) { - throw new NullPointerException("URL must not be null"); - } - - if (url.trim().isEmpty()) { - throw new IllegalArgumentException("URL must not be empty"); - } - - try { - if (!URL_QUICKMATCH.matcher(url).matches()) { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - URL resource; - if (url.charAt(0) == '/') { - resource = contextClassLoader.getResource(url.substring(1)); - } else { - resource = contextClassLoader.getResource(url); - } - if (resource == null) { - throw new IllegalArgumentException("Invalid URL or resource not found"); - } - return resource.toString(); - } - // Use URL constructor for validation - return new URL(url).toString(); - } catch (final IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid URL" + e.getMessage()); - } catch (final MalformedURLException e) { - throw new IllegalArgumentException("Invalid URL" + e.getMessage()); - } - } - - private void finishImage(ImageLoader loader) { - initializeAnimatedImage(loader); - } - - // Generates the animation Timeline for multiframe images. - private void initializeAnimatedImage(ImageLoader loader) { - - animation = new Animation(this, loader); - animation.start(); - } - - // Support for animated images. - private Animation animation; - - private static final class Animation { - final WeakReference imageRef; - final Timeline timeline; - private ImageLoader loader; - - public Animation(final FastGifImage image, final ImageLoader loader) { - this.loader = loader; - imageRef = new WeakReference(image); - timeline = new Timeline(); - timeline.setCycleCount(Timeline.INDEFINITE); - - final int frameCount = loader.getFrameCount(); - int duration = 0; - - for (int i = 0; i < frameCount; ++i) { - addKeyFrame(i, duration); - duration = duration + loader.getFrameDelay(i); - } - - // Note: we need one extra frame in the timeline to define how long - // the last frame is shown, the wrap around is "instantaneous" - addKeyFrame(0, duration); - } - - public void start() { - timeline.play(); - } - - public void stop() { - timeline.stop(); - loader = null; - } - - private void updateImage(final int frameIndex) { - final FastGifImage image = imageRef.get(); - if (image != null) { - image.setPlatformImagePropertyImpl( - loader.getFrame(frameIndex)); - } else { - timeline.stop(); - } - } - - private void addKeyFrame(final int index, final double duration) { - timeline.getKeyFrames().add( - new KeyFrame(Duration.millis(duration), - new EventHandler() { - @Override - public void handle(Event event) { - updateImage(index); - } - } - )); - } - } - - private static Method method; - - static { - try { - method = FastGifImage.class.getSuperclass().getSuperclass().getDeclaredMethod("platformImagePropertyImpl"); - method.setAccessible(true); - } catch (Exception e) { - - } - } - - private void setPlatformImagePropertyImpl(PlatformImage image) { - try { - Object o = method.invoke(this); - Method method = o.getClass().getDeclaredMethod("set", Object.class); - method.setAccessible(true); - method.invoke(o, image); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - } - - - private void initialize() { - finishImage(new PrismImageLoader2(url, gifCount, (int) getRequestedWidth(), (int) getRequestedHeight(), isPreserveRatio(), isSmooth())); - } - - /** - * 销毁gif动画 - */ - public void destroy() { - animation.stop(); - } - -} diff --git a/designer-realize/src/main/java/com/fr/start/fx/PrismImageLoader2.java b/designer-realize/src/main/java/com/fr/start/fx/PrismImageLoader2.java deleted file mode 100644 index 4529465c7..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/PrismImageLoader2.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.fr.start.fx; - -import com.fr.concurrent.NamedThreadFactory; -import com.fr.log.FineLoggerFactory; -import com.sun.javafx.iio.ImageFrame; -import com.sun.javafx.iio.ImageLoadListener; -import com.sun.javafx.iio.ImageLoader; -import com.sun.javafx.iio.ImageMetadata; -import com.sun.javafx.iio.ImageStorageException; -import com.sun.javafx.iio.common.ImageTools; -import com.sun.javafx.iio.gif.GIFImageLoaderFactory; -import com.sun.javafx.tk.PlatformImage; -import com.sun.prism.Image; -import com.sun.prism.impl.PrismSettings; - - -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * 边加载边播放的gif加载器 - * - * @author daniel - */ -class PrismImageLoader2 implements com.sun.javafx.tk.ImageLoader { - - private Image[] images; - private int[] delayTimes; - private int width; - private int height; - private int gifCount = 1; - private Exception exception; - - public PrismImageLoader2(final String url, int gifCount, final int width, final int height, - final boolean preserveRatio, final boolean smooth) { - this.gifCount = gifCount; - images = new Image[gifCount]; - delayTimes = new int[gifCount]; - this.width = width; - this.height = height; - ExecutorService es = Executors.newSingleThreadExecutor(new NamedThreadFactory("PrismImageLoader2")); - es.execute(new Runnable() { - @Override - public void run() { - InputStream inputStream = null; - try { - inputStream = ImageTools.createInputStream(url); - loadAll(inputStream, width, height, preserveRatio, smooth); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - }); - es.shutdown(); - } - - @Override - public int getWidth() { - return width; - } - - @Override - public int getHeight() { - return height; - } - - @Override - public int getFrameCount() { - return gifCount; - } - - @Override - @SuppressWarnings("squid:S2142") - public PlatformImage getFrame(int index) { - while (images[index] == null) { - synchronized (this) { - if (images[index] == null) { - try { - this.wait(); - } catch (InterruptedException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - } - } - } - return images[index]; - } - - - @Override - public int getFrameDelay(int index) { -// while (images[0] == null) { -// synchronized (this) { -// if(images[0] == null) { -// try { -// this.wait(); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// } -// } -// return 0; -// } -// return delayTimes[0]; - // 直接使用第一帧的时间 - return 40; - } - - @Override - public int getLoopCount() { - return 0; - } - - @Override - public Exception getException() { - return exception; - } - - - @SuppressWarnings("squid:S244") - private void loadAll(InputStream stream, int w, int h, - boolean preserveRatio, boolean smooth) { - ImageLoadListener listener = new PrismLoadListener(); - - try { - ImageLoader loader = null; - loader = GIFImageLoaderFactory.getInstance().createImageLoader(stream); - loader.addListener(listener); - - for (int i = 0; i < gifCount; i++) { - ImageFrame imageFrame = loader.load(i, w, h, preserveRatio, smooth); - images[i] = convert(imageFrame); - synchronized (this) { - notifyAll(); - } - } - } catch (ImageStorageException e) { - handleException(e); - } catch (Exception e) { - handleException(e); - } - } - - private void handleException(final ImageStorageException isException) { - // unwrap ImageStorageException if possible - final Throwable exceptionCause = isException.getCause(); - if (exceptionCause instanceof Exception) { - handleException((Exception) exceptionCause); - } else { - handleException((Exception) isException); - } - } - - private void handleException(final Exception exception) { - if (PrismSettings.verbose) { - exception.printStackTrace(System.err); - } - this.exception = exception; - } - - private Image convert(ImageFrame imgFrames) { - ImageFrame frame = imgFrames; - Image image = Image.convertImageFrame(frame); - ImageMetadata metadata = frame.getMetadata(); - if (metadata != null) { - Integer delay = metadata.delayTime; - if (delay != null) { - delayTimes[0] = delay.intValue(); - } - } - return image; - } - - - private class PrismLoadListener implements ImageLoadListener { - @Override - public void imageLoadWarning(ImageLoader loader, String message) { - - } - - @Override - public void imageLoadProgress(ImageLoader loader, - float percentageComplete) { - // progress only matters when backgroundLoading=true, but - // currently we are relying on AbstractRemoteResource for tracking - // progress of the InputStream, so there's no need to implement - // this for now; eventually though we might want to consider - // moving away from AbstractRemoteResource and instead use - // the built-in support for progress in the javafx-iio library... - } - - @Override - public void imageLoadMetaData(ImageLoader loader, ImageMetadata metadata) { - // We currently have no need to listen for ImageMetadata ready. - } - } - -} diff --git a/designer-realize/src/main/java/com/fr/start/fx/SplashFx.java b/designer-realize/src/main/java/com/fr/start/fx/SplashFx.java deleted file mode 100644 index f5c64bf79..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/SplashFx.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.fr.start.fx; - -import com.fr.concurrent.NamedThreadFactory; -import com.fr.design.mainframe.DesignerContext; -import com.fr.start.SplashFxActionListener; -import com.fr.start.SplashStrategy; -import javafx.application.Application; -import javafx.application.Platform; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * JavaFx方式启动启动动画。这种方式在mac下与 - * swing一起启动会会出现线程死锁,jvm等问题, - * 所以这个方式仅用于windows上。 - * - * @author vito - * @date 2018/6/4 - * @see com.fr.start.jni.SplashMac - */ -public class SplashFx implements SplashStrategy { - - private SplashFxWindow fxWindow; - private static final ExecutorService SERVICE = Executors.newSingleThreadExecutor(new NamedThreadFactory("SplashFx")); - - @Override - public void show() { - Platform.setImplicitExit(false); - SERVICE.execute(new Runnable() { - @Override - public void run() { - Application.launch(SplashFxWindow.class); - } - }); - fxWindow = SplashFxWindow.waitForStartUpTest(); - fxWindow.addSplashActionListener(new SplashFxActionListener() { - @Override - public void splashClose() { - DesignerContext.getDesignerFrame().setVisible(true); - } - }); - } - - @Override - public void hide() { - fxWindow.close(); - } - - @Override - public void updateModuleLog(final String text) { - fxWindow.updateModuleInfo(text); - } - - @Override - public void updateThanksLog(final String text) { - fxWindow.updateThanks(text); - } -} diff --git a/designer-realize/src/main/java/com/fr/start/fx/SplashFxWindow.java b/designer-realize/src/main/java/com/fr/start/fx/SplashFxWindow.java deleted file mode 100644 index 00ad51293..000000000 --- a/designer-realize/src/main/java/com/fr/start/fx/SplashFxWindow.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.fr.start.fx; - -import com.fr.log.FineLoggerFactory; -import com.fr.stable.OperatingSystem; -import com.fr.start.SplashContext; -import com.fr.start.SplashFxActionListener; -import javafx.application.Application; -import javafx.application.Platform; -import javafx.geometry.Rectangle2D; -import javafx.scene.Scene; -import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; -import javafx.scene.paint.Color; -import javafx.scene.text.Font; -import javafx.scene.text.Text; -import javafx.stage.Screen; -import javafx.stage.Stage; -import javafx.stage.StageStyle; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; - - -/** - * JavaFx启动动画窗口 - * - * @author vito - */ -public class SplashFxWindow extends Application { - - private static final String ARIAL_FONT_NAME = "Arial"; - private static final String PF_FONT_NAME = "PingFang"; - private static final String YAHEI_FONT_NAME = "Microsoft YaHei"; - private static final int MODULE_INFO_LEFT_MARGIN = 36; - private static final int MODULE_INFO_BOTTOM_MARGIN = 28; - private static final int THINKS_BOTTOM_RIGHT = 35; - private static final int THINKS_BOTTOM_MARGIN = 27; - private static final int WINDOW_WIDTH = 640; - private static final int WINDOW_HEIGHT = 360; - private static final int FONT = 12; - private static final int FRAME_COUNT = 315; - private static final String THINKS_COLOR = "#82b1ce"; - - private static final CountDownLatch LATCH = new CountDownLatch(1); - private static SplashFxWindow app = null; - - private Text moduleInfo; - private Text thanks; - private FastGifImage image; - private List listeners = new ArrayList(); - - /** - * 获取当前运行实例。黑科技 - * - * @return 运行实例 - */ - @SuppressWarnings("squid:S2142") - public static SplashFxWindow waitForStartUpTest() { - try { - LATCH.await(); - } catch (InterruptedException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return app; - } - - private static void setApp(SplashFxWindow window) { - app = window; - LATCH.countDown(); - } - - public SplashFxWindow() { - setApp(this); - } - - @Override - public void start(Stage primaryStage) { - AnchorPane root = new AnchorPane(); - primaryStage.initStyle(StageStyle.TRANSPARENT); - image = new FastGifImage(SplashContext.SPLASH_PATH, FRAME_COUNT, WINDOW_WIDTH, WINDOW_HEIGHT); - - ImageView gif = new ImageView(image); - - AnchorPane.setBottomAnchor(gif, 0d); - AnchorPane.setTopAnchor(gif, 0d); - AnchorPane.setLeftAnchor(gif, 0d); - AnchorPane.setRightAnchor(gif, 0d); - Font font; - if (OperatingSystem.isWindows()) { - font = new Font(YAHEI_FONT_NAME, FONT); - } else if (OperatingSystem.isMacOS()) { - font = new Font(PF_FONT_NAME, FONT); - } else { - font = new Font(ARIAL_FONT_NAME, FONT); - } - - moduleInfo = new Text(); - moduleInfo.setFont(font); - moduleInfo.setFill(Color.WHITE); - AnchorPane.setLeftAnchor(moduleInfo,(double) MODULE_INFO_LEFT_MARGIN); - AnchorPane.setBottomAnchor(moduleInfo,(double) MODULE_INFO_BOTTOM_MARGIN); - thanks = new Text(); - thanks.setFont(font); - thanks.setFill(Color.valueOf(THINKS_COLOR)); - AnchorPane.setRightAnchor(thanks, (double) THINKS_BOTTOM_RIGHT); - AnchorPane.setBottomAnchor(thanks, (double) THINKS_BOTTOM_MARGIN); - - root.getChildren().add(gif); - root.getChildren().add(moduleInfo); - root.getChildren().add(thanks); - - primaryStage.setWidth(WINDOW_WIDTH); - primaryStage.setHeight(WINDOW_HEIGHT); - primaryStage.setScene(new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT, null)); - setWindowCenter(primaryStage); - primaryStage.show(); - } - - public void close() { - Platform.runLater(new Runnable() { - @Override - public void run() { - try { - ((Stage) moduleInfo.getScene().getWindow()).close(); - image.destroy(); - fireSplashClose(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - } - }); - } - - /** - * 设置窗口居中 - * - * @param stage 窗口 - */ - private void setWindowCenter(Stage stage) { - Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds(); - stage.setX(primaryScreenBounds.getMinX() + (primaryScreenBounds.getWidth() - stage.getWidth()) / 2.0); - stage.setY(primaryScreenBounds.getMinY() + (primaryScreenBounds.getHeight() - stage.getHeight()) / 2.0); - } - - /** - * 更新模块信息 - * - * @param s 文字 - */ - public void updateModuleInfo(final String s) { - Platform.runLater(new Runnable() { - @Override - public void run() { - if (moduleInfo != null) { - moduleInfo.setText(s); - } - } - }); - - } - - /** - * 更新欢迎信息 - * - * @param s 文字 - */ - public void updateThanks(final String s) { - Platform.runLater(new Runnable() { - @Override - public void run() { - if (thanks != null) { - thanks.setText(s); - } - } - }); - - } - - /** - * 添加一个动画状态监听 - * - * @param listener - */ - public void addSplashActionListener(SplashFxActionListener listener) { - listeners.add(listener); - } - - public void fireSplashClose() { - for (SplashFxActionListener listener : listeners) { - listener.splashClose(); - } - } -} diff --git a/designer-realize/src/main/java/com/fr/start/jni/SplashJNI.java b/designer-realize/src/main/java/com/fr/start/jni/SplashJNI.java deleted file mode 100644 index e71a44ca2..000000000 --- a/designer-realize/src/main/java/com/fr/start/jni/SplashJNI.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.fr.start.jni; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; - -/** - * Splash JNI调用。jni类改名或者移包之后 - * 必须重新编译动态库 - * - * @author vito - * @date 2018/6/4 - */ -public class SplashJNI { - - static { - try { - System.setProperty("java.library.path", "."); - System.loadLibrary("splash"); - } catch (UnsatisfiedLinkError e) { - loadLibraryFromJar("/com/fr/start/jni/splash.dylib"); - } - } - - /** - * 显示启动动画窗口 - */ - public native void show(String path); - - /** - * 隐藏启动动画窗口 - */ - public native void hide(); - - /** - * 设置模块加载信息 - */ - public native void updateModuleLog(String text); - - /** - * 设置感谢文字 - */ - public native void updateThanksLog(String text); - - /** - * 从jar中加载动态库 - * - * @param path 路径,如/com/a/b - * @throws UnsatisfiedLinkError 没有找到合适的动态库 - */ - private static void loadLibraryFromJar(String path) throws UnsatisfiedLinkError { - try (InputStream inputStream = SplashJNI.class.getResourceAsStream(path)) { - File tempLib = File.createTempFile(path, ""); - - byte[] buffer = new byte[1024]; - int read = -1; - - try (FileOutputStream fileOutputStream = new FileOutputStream(tempLib)) { - while ((read = inputStream.read(buffer)) != -1) { - fileOutputStream.write(buffer, 0, read); - } - } - - System.load(tempLib.getAbsolutePath()); - } catch (Exception e) { - throw new UnsatisfiedLinkError("Unable to open " + path + " from jar file."); - } - } -} diff --git a/designer-realize/src/main/java/com/fr/start/jni/SplashMac.java b/designer-realize/src/main/java/com/fr/start/jni/SplashMac.java deleted file mode 100644 index 6d2a47a2e..000000000 --- a/designer-realize/src/main/java/com/fr/start/jni/SplashMac.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.fr.start.jni; - -import com.fr.log.FineLoggerFactory; -import com.fr.stable.ProductConstants; -import com.fr.stable.StableUtils; -import com.fr.stable.StringUtils; -import com.fr.start.SplashContext; -import com.fr.start.SplashStrategy; - -import javax.swing.JFrame; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * mac上使用jni方式绘制gif。不使用javafx有两个原因: - * 1.mac上javafx和swing同时启动会导致卡死; - * 2.platform.exit会导致设计器崩溃 - * - * @author vito - * @see com.fr.start.fx.SplashFx - */ -public class SplashMac implements SplashStrategy { - - - private SplashJNI jni; - private static final int EXILE = 10000; - - public SplashMac() { - jni = new SplashJNI(); - } - - /** - * 将jar中的资源拷贝到缓存文件夹 - * - * @return 路径 - */ - private static String loadResFromJar() { - File tempLib = null; - try (InputStream inputStream = SplashContext.class.getResourceAsStream(SplashContext.SPLASH_PATH)) { - if (inputStream == null) { - FineLoggerFactory.getLogger().error("Unable to copy " + SplashContext.SPLASH_PATH + " from jar file."); - return StringUtils.EMPTY; - } - tempLib = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), SplashContext.SPLASH_CACHE_NAME)); - byte[] buffer = new byte[1024]; - int read = -1; - try (FileOutputStream fileOutputStream = new FileOutputStream(tempLib)) { - while ((read = inputStream.read(buffer)) != -1) { - fileOutputStream.write(buffer, 0, read); - } - } - return tempLib.getAbsolutePath(); - } catch (IOException e) { - if (tempLib != null) { - tempLib.deleteOnExit(); - } - // 直接抛异常 - throw new RuntimeException("Unable to copy " + SplashContext.SPLASH_PATH + " from jar file."); - } - } - - @Override - public void show() { - if (jni != null) { - // mac下安装版模糊的hack - JFrame jFrame = new JFrame(); - jFrame.setLocation(EXILE, EXILE); - jFrame.setVisible(true); - jFrame.setVisible(false); - File splash = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), SplashContext.SPLASH_CACHE_NAME)); - String path = splash.exists() ? splash.getAbsolutePath() : loadResFromJar(); - jni.show(path); - } - } - - @Override - public void hide() { - if (jni != null) { - jni.hide(); - jni = null; - } - } - - @Override - public void updateModuleLog(String text) { - if (jni != null) { - jni.updateModuleLog(text); - } - - } - - @Override - public void updateThanksLog(String text) { - if (jni != null) { - jni.updateThanksLog(text); - } - } -} diff --git a/designer-realize/src/main/resources/com/fr/start/jni/splash.dylib b/designer-realize/src/main/resources/com/fr/start/jni/splash.dylib deleted file mode 100755 index 6ae677da3..000000000 Binary files a/designer-realize/src/main/resources/com/fr/start/jni/splash.dylib and /dev/null differ