From 597eed5d8a89967bf7b3fb2201c76b704d34e942 Mon Sep 17 00:00:00 2001 From: kerry Date: Thu, 30 Dec 2021 17:58:18 +0800 Subject: [PATCH 01/19] =?UTF-8?q?REPORT-65107=20=E5=86=B3=E7=AD=96?= =?UTF-8?q?=E6=8A=A5=E8=A1=A8-11frm=EF=BC=8C=E6=97=A0=E6=B3=95=E5=90=91tab?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E4=B8=8A=E6=96=B9=E6=8B=96=E5=85=A5=E6=94=BE?= =?UTF-8?q?=E7=BD=AE=E7=BB=84=E4=BB=B6=EF=BC=8C10=E4=B8=8A=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E8=BF=98=E6=AF=94=E8=BE=83=E9=A1=BA=E7=95=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fr/design/mainframe/FormCreatorDropTarget.java | 3 --- 1 file changed, 3 deletions(-) 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 5eb354c6c..102c5c863 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 @@ -90,9 +90,6 @@ public class FormCreatorDropTarget extends DropTarget { XLayoutContainer container = XCreatorUtils.getHotspotContainer(hoveredComponent); boolean success = false; if (container != null) { - //XWCardTagLayout 切换添加状态到普通状态 - container.stopAddingState(designer); - // 如果是容器,则调用其acceptComponent接受组件 AddingModel model = designer.getAddingModel(); From d357ff42c747d5b7a651ad7c46f33708c90598f2 Mon Sep 17 00:00:00 2001 From: hades Date: Fri, 31 Dec 2021 15:12:13 +0800 Subject: [PATCH 02/19] =?UTF-8?q?REPORT-64009=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8=E5=86=85=E5=AF=B9macOS12=E7=9A=84=E5=A4=84=E7=90=86?= =?UTF-8?q?=20fix=E9=97=A8=E6=A7=9B=E7=94=A8=E4=BE=8B=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/fr/design/web/CustomIconPane.java | 9 ++++----- .../main/java/com/fr/start/module/DesignerActivator.java | 4 ++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java index 9e03dcc9d..93e65a7ea 100644 --- a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java +++ b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java @@ -4,14 +4,14 @@ import com.fr.base.BaseUtils; import com.fr.base.GraphHelper; import com.fr.base.Icon; import com.fr.base.IconManager; -import com.fr.design.designer.IntervalConstants; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ifilechooser.FileChooserArgs; +import com.fr.design.gui.ifilechooser.FileChooserFactory; import com.fr.design.gui.ifilechooser.FileChooserProvider; -import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.design.gui.itextarea.DescriptionTextArea; @@ -451,9 +451,8 @@ public class CustomIconPane extends BasicPane { private void onBrowseButtonClicked() { // carl:不知道是否只要png格式,反正导出时全部都转成png了 - FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder(). - filter("Icon Image File", "*.jpg", "*.jpeg", "*.png", "*.gif"). - build(); + FileChooserProvider fileChooserProvider = FileChooserFactory.createFileChooser(FileChooserArgs.newBuilder(). + setFilter("Icon Image File", "*.jpg", "*.jpeg", "*.png", "*.gif").build()); if (JFileChooser.APPROVE_OPTION == fileChooserProvider.showDialog(DesignerContext.getDesignerFrame())) { String path = fileChooserProvider.getSelectedFile().getAbsolutePath(); // 图片存储有最大值48*48限制,没有超过最大值时,按原图大小存储,超过最大值后,压缩至最大值存储 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 3c9b4dc9d..8ea078cd4 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 @@ -8,6 +8,7 @@ import com.fr.base.passport.FinePassportManager; import com.fr.base.process.ProcessOperator; import com.fr.chart.chartattr.ChartCollection; import com.fr.config.MarketConfig; +import com.fr.config.ServerPreferenceConfig; import com.fr.decision.update.backup.RecoverManager; import com.fr.design.DesignerEnvManager; import com.fr.design.ExtraDesignClassManager; @@ -177,6 +178,9 @@ public class DesignerActivator extends Activator implements Prepare { //生成BasicChartQuickEditor对象,需要用到ChartDesignerActivator的注册信息(DesignModuleFactory.registerChartPropertyPaneClass(ChartPropertyPane.class);) //所以不能在registerCellEditor函数中进行注册 ActionFactory.registerCellEditor(ChartCollection.class, new BasicChartQuickEditor()); + if (DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter() && WorkContext.getCurrent().isLocal()) { + ServerPreferenceConfig.getInstance().setUseOptimizedUPM(DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter()); + } } private void loadLogAppender() { From 40e5ba10a1e43a649d189dfcfbe69a34e217b7ab Mon Sep 17 00:00:00 2001 From: hades Date: Fri, 31 Dec 2021 15:18:53 +0800 Subject: [PATCH 03/19] =?UTF-8?q?REPORT-64009=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8=E5=86=85=E5=AF=B9macOS12=E7=9A=84=E5=A4=84=E7=90=86?= =?UTF-8?q?=20fix=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fr/design/web/CustomIconPane.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java index 93e65a7ea..96b584020 100644 --- a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java +++ b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java @@ -30,23 +30,34 @@ import com.fr.stable.ListMap; import com.fr.stable.StringUtils; import com.fr.transaction.Configurations; import com.fr.transaction.WorkerFacade; -import javafx.stage.FileChooser; -import javax.swing.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.plaf.basic.BasicButtonUI; -import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; /** * carl:自定义Icon编辑 From 0a3552adae241de1054855699a0a027d865b2b59 Mon Sep 17 00:00:00 2001 From: kerry Date: Tue, 4 Jan 2022 09:17:32 +0800 Subject: [PATCH 04/19] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design/designer/creator/XLayoutContainer.java | 8 -------- .../creator/cardlayout/XWCardMainBorderLayout.java | 12 ------------ .../creator/cardlayout/XWCardTagLayout.java | 9 --------- .../creator/cardlayout/XWCardTitleLayout.java | 13 +------------ 4 files changed, 1 insertion(+), 41 deletions(-) diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XLayoutContainer.java b/designer-form/src/main/java/com/fr/design/designer/creator/XLayoutContainer.java index 01d09fe4c..3d0b24847 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XLayoutContainer.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XLayoutContainer.java @@ -474,14 +474,6 @@ public abstract class XLayoutContainer extends XBorderStyleWidgetCreator impleme return 0; } - /** - * 切换到非添加状态 - * - * @param designer 表单设计器 - */ - public void stopAddingState(FormDesigner designer) { - } - /** * 寻找最近的为自适应布局的父容器 * 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 fdc01be1e..e09b31fb0 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 @@ -179,18 +179,6 @@ public class XWCardMainBorderLayout extends XWBorderLayout { } } - /** - * 切换到非添加状态 - * - * @return designer 表单设计器 - */ - @Override - public void stopAddingState(FormDesigner designer){ - designer.stopAddingState(); - return; - } - - /** * 添加card区域 * 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 ceb334028..850378af2 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 @@ -187,15 +187,6 @@ public class XWCardTagLayout extends XWHorizontalBoxLayout { return DEFAULT_NAME; } - /** - * 切换到非添加状态 - * - * @return designer 表单设计器 - */ - @Override - public void stopAddingState(FormDesigner designer) { - designer.stopAddingState(); - } //新增时去tabFitLayout名字中最大的Index+1,防止重名 private int getTabNameIndex() { 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 7cdca0a0b..9695eee18 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 @@ -166,18 +166,7 @@ public class XWCardTitleLayout extends XWBorderLayout { XWCardTagLayout xwCardTagLayout = (XWCardTagLayout) this.getComponent(0); this.addTagPart(xwCardTagLayout); } - - /** - * 切换到非添加状态 - * - * @return designer 表单设计器 - */ - @Override - public void stopAddingState(FormDesigner designer){ - designer.stopAddingState(); - return; - } - + /** * 该布局隐藏,无需对边框进行操作 * @param border 边框 From 2ffdfa366cc7f47efba7069b4031d80d82710d48 Mon Sep 17 00:00:00 2001 From: hades Date: Tue, 4 Jan 2022 10:13:30 +0800 Subject: [PATCH 05/19] =?UTF-8?q?REPORT-65307=20=E4=BA=8C=E8=BD=AE?= =?UTF-8?q?=E5=86=92=E7=83=9F=E6=B5=8B=E8=AF=95-=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E9=94=81=E5=AE=9A=E4=BC=98=E5=8C=96-?= =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96=E9=97=AE=E9=A2=98-=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E6=98=BE=E7=A4=BA=E4=B8=8D=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/fr/design/lock/LockInfoDialog.java | 3 ++- .../src/main/java/com/fr/design/mainframe/ForbiddenPane.java | 3 ++- .../main/resources/com/fr/design/i18n/dimension_en.properties | 4 +++- .../resources/com/fr/design/i18n/dimension_ja_JP.properties | 4 +++- .../resources/com/fr/design/i18n/dimension_ko_KR.properties | 4 +++- .../main/resources/com/fr/design/i18n/dimension_zh.properties | 4 +++- .../resources/com/fr/design/i18n/dimension_zh_TW.properties | 4 +++- 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java b/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java index 71c954924..a0fd544d5 100644 --- a/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java +++ b/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java @@ -3,6 +3,7 @@ package com.fr.design.lock; import com.fr.design.file.TemplateTreePane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.DesignSizeI18nManager; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; @@ -44,7 +45,7 @@ public class LockInfoDialog extends JDialog { panel.add(createControlPane(), BorderLayout.SOUTH); this.getContentPane().add(panel); this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Title_Hint")); - this.setSize(400, 160); + this.setSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.lock.LockInfoDialog")); this.setResizable(false); this.setModal(true); GUICoreUtils.centerWindow(this); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/ForbiddenPane.java b/designer-base/src/main/java/com/fr/design/mainframe/ForbiddenPane.java index f90391211..9c33534c7 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/ForbiddenPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/ForbiddenPane.java @@ -2,6 +2,7 @@ package com.fr.design.mainframe; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.DesignSizeI18nManager; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.guide.base.GuideView; import com.fr.design.utils.gui.GUICoreUtils; @@ -105,7 +106,7 @@ public class ForbiddenPane extends JPanel { super.paintComponent(g2d); } }; - refreshButton.setPreferredSize(new Dimension(68, 24)); + refreshButton.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.mainframe.ForbiddenPane.refreshButton")); refreshButton.setForeground(Color.WHITE); refreshButton.setBorderPainted(false); refreshButton.setContentAreaFilled(false); diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties index 786fe2ad0..aa4a83f3e 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties @@ -12,4 +12,6 @@ com.fr.design.web.pane.text.field=450*20 com.fr.design.actions.server.dialog=800*630 com.fr.design.report.fit.templatePane.dialog=800*400 com.fr.design.report.fit.firstColumn=120*20 -com.fr.design.report.fit.column=160*20 \ No newline at end of file +com.fr.design.report.fit.column=160*20 +com.fr.design.lock.LockInfoDialog=500*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=75*24 \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties index 0956fa79d..96558262f 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties @@ -11,4 +11,6 @@ com.fr.design.web.pane.text.field=400*20 com.fr.design.actions.server.dialog=700*630 com.fr.design.report.fit.templatePane.dialog=600*400 com.fr.design.report.fit.firstColumn=170*20 -com.fr.design.report.fit.column=100*20 \ No newline at end of file +com.fr.design.report.fit.column=100*20 +com.fr.design.lock.LockInfoDialog=500*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties index 17031793f..05e20c7aa 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties @@ -11,4 +11,6 @@ com.fr.design.web.pane.text.field=450*20 com.fr.design.actions.server.dialog=700*630 com.fr.design.report.fit.templatePane.dialog=600*400 com.fr.design.report.fit.firstColumn=130*20 -com.fr.design.report.fit.column=100*20 \ No newline at end of file +com.fr.design.report.fit.column=100*20 +com.fr.design.lock.LockInfoDialog=500*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=80*24 \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties index 931b79b44..a4b2993e6 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties @@ -12,4 +12,6 @@ com.fr.design.web.pane.text.field=450*20 com.fr.design.actions.server.dialog=700*630 com.fr.design.report.fit.templatePane.dialog=600*400 com.fr.design.report.fit.firstColumn=80*20 -com.fr.design.report.fit.column=100*20 \ No newline at end of file +com.fr.design.report.fit.column=100*20 +com.fr.design.lock.LockInfoDialog=400*160 +com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties index 8ea7fd7c2..5813cd96c 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties @@ -11,4 +11,6 @@ com.fr.design.web.pane.text.field=450*20 com.fr.design.actions.server.dialog=700*630 com.fr.design.report.fit.templatePane.dialog=600*400 com.fr.design.report.fit.firstColumn=80*20 -com.fr.design.report.fit.column=100*20 \ No newline at end of file +com.fr.design.report.fit.column=100*20 +com.fr.design.lock.LockInfoDialog=400*160 +com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 \ No newline at end of file From e47c0f56723a88fbc81bcac7f5392d24beb6a73e Mon Sep 17 00:00:00 2001 From: Starryi Date: Tue, 4 Jan 2022 12:43:44 +0800 Subject: [PATCH 06/19] =?UTF-8?q?REPORT-65358=20=E3=80=90=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E8=BE=B9=E6=A1=86=E3=80=91=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E5=8F=8C=E7=BA=BF=E6=98=BE=E7=A4=BA=E6=9C=89?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 各边框绘制时的偏移距离要单独计算 【改动思路】 同上 --- .../fr/design/cell/CellStylePreviewPane.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/cell/CellStylePreviewPane.java b/designer-base/src/main/java/com/fr/design/cell/CellStylePreviewPane.java index b4b382af5..eb3c2cd7b 100644 --- a/designer-base/src/main/java/com/fr/design/cell/CellStylePreviewPane.java +++ b/designer-base/src/main/java/com/fr/design/cell/CellStylePreviewPane.java @@ -19,9 +19,7 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Rectangle; import java.awt.RenderingHints; -import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.util.List; @@ -154,16 +152,16 @@ public class CellStylePreviewPane extends JPanel { float adjustRight = 0; float adjustBottom = 0; if (column == 0) { - adjustLeft = GraphHelper.getLineStyleSize(style.getBorderLeft()) / 2.0F + computeOffset4DoubleStyleBorder(style); + adjustLeft = computeHalfSize4StyledBorder(style.getBorderLeft()); } if (row == 0) { - adjustTop = GraphHelper.getLineStyleSize(style.getBorderTop()) / 2.0F + computeOffset4DoubleStyleBorder(style); + adjustTop = computeHalfSize4StyledBorder(style.getBorderTop()); } if (column == columnSpan - 1) { - adjustRight = -GraphHelper.getLineStyleSize(style.getBorderRight()) / 2.0F - computeOffset4DoubleStyleBorder(style); + adjustRight = -computeHalfSize4StyledBorder(style.getBorderRight()); } if (row == rowSpan - 1) { - adjustBottom = -GraphHelper.getLineStyleSize(style.getBorderBottom()) / 2.0F - computeOffset4DoubleStyleBorder(style); + adjustBottom = -computeHalfSize4StyledBorder(style.getBorderBottom()); } g2d.translate(adjustLeft, adjustTop); @@ -171,15 +169,16 @@ public class CellStylePreviewPane extends JPanel { g2d.translate(-adjustLeft, -adjustTop); } - private float computeOffset4DoubleStyleBorder(Style style) { - float offset = 0F; - if (style.getBorderLeft() == Constants.LINE_DOUBLE) { - offset += GraphHelper.getLineStyleSize(Constants.LINE_THIN) / 2.0F; - } else if (style.getBorderLeft() == Constants.LINE_DOUBLE_DOT) { - offset += GraphHelper.getLineStyleSize(Constants.LINE_DOT) / 2.0F; + private float computeHalfSize4StyledBorder(int border) { + float size = GraphHelper.getLineStyleSize(border) / 2.0F; + + if (border == Constants.LINE_DOUBLE) { + size += GraphHelper.getLineStyleSize(Constants.LINE_THIN) / 2.0F; + } else if (border == Constants.LINE_DOUBLE_DOT) { + size += GraphHelper.getLineStyleSize(Constants.LINE_DOT) / 2.0F; } - return offset; + return size; } @Override From 9c5a1e72f5d3a95d03917d3bba4c4545604e93c3 Mon Sep 17 00:00:00 2001 From: Starryi Date: Tue, 4 Jan 2022 12:44:38 +0800 Subject: [PATCH 07/19] =?UTF-8?q?REPORT-65365=20=E3=80=90=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E8=BE=B9=E6=A1=86=E3=80=91=E5=A4=9A=E6=AC=A1=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=8D=95=E5=85=83=E6=A0=BC=E6=A0=B7=E5=BC=8F=E5=90=8E?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E8=87=AA=E5=AE=9A=E4=B9=89=EF=BC=8C=E8=BE=B9?= =?UTF-8?q?=E6=A1=86=E7=BA=BF=E6=9C=89=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 根据数据模型填充面板时,需要先重置面板清理掉旧的数据 【改动思路】 同上 --- .../java/com/fr/design/gui/style/BorderPane.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java b/designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java index dcead1c87..3c917ea45 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java @@ -4,7 +4,6 @@ package com.fr.design.gui.style; * Copyright(c) 2001-2010, FineReport Inc, All Rights Reserved. */ -import com.fr.base.BaseUtils; import com.fr.base.CellBorderStyle; import com.fr.base.Style; import com.fr.design.constants.LayoutConstants; @@ -17,8 +16,8 @@ import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.style.color.NewColorSelectBox; -import com.fr.general.IOUtils; import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils; +import com.fr.general.IOUtils; import com.fr.stable.Constants; import com.fr.stable.CoreConstants; @@ -206,6 +205,8 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse } public void populateLineStyleAndColor(CellBorderStyle cellBorderStyle, boolean onlyInspectTop) { + resetLineStyleAndColorSetting(); + if (cellBorderStyle.getTopStyle() != Constants.LINE_NONE) { this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getTopStyle()); this.currentLineColorPane.setSelectObject(cellBorderStyle.getTopColor()); @@ -225,9 +226,6 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse } else if (cellBorderStyle.getHorizontalStyle() != Constants.LINE_NONE) { this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getHorizontalStyle()); this.currentLineColorPane.setSelectObject(cellBorderStyle.getHorizontalColor()); - } else { - this.currentLineCombo.setSelectedLineStyle(Constants.LINE_NONE); - this.currentLineColorPane.setSelectObject(Color.BLACK); } } @@ -236,6 +234,11 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse } } + private void resetLineStyleAndColorSetting() { + this.currentLineCombo.setSelectedLineStyle(Constants.LINE_NONE); + this.currentLineColorPane.setSelectObject(null); + } + @Override public Style update(Style style) { From 0862c0aecf4e66872d9984b40fef097110dc789b Mon Sep 17 00:00:00 2001 From: hades Date: Tue, 4 Jan 2022 13:54:35 +0800 Subject: [PATCH 08/19] =?UTF-8?q?REPORT-65343=20FR11-=E6=96=B0=E8=87=AA?= =?UTF-8?q?=E9=80=82=E5=BA=94=E5=BC=80=E5=8F=91=E8=80=85=E8=B0=83=E8=AF=95?= =?UTF-8?q?-=E6=96=B0=E5=BB=BA=E6=A8=A1=E6=9D=BF=EF=BC=8C=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E7=82=B9=E5=87=BB=E5=BC=80=E5=8F=91=E8=80=85=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E8=BF=9B=E8=A1=8C=E6=A8=A1=E6=9D=BF=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E5=92=8C=E9=A2=84=E8=A7=88=EF=BC=8C=E6=AD=A4=E6=97=B6=E8=99=BD?= =?UTF-8?q?=E7=84=B6=E5=BC=B9=E5=87=BA=E4=BF=9D=E5=AD=98=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=EF=BC=8C=E4=BD=86=E5=AF=B9=E8=AF=9D=E6=A1=86?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E8=BF=98=E6=B2=A1=E6=9C=89=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E7=9A=84=E6=97=B6=E5=80=99=E6=A8=A1=E6=9D=BFweb=E5=B0=B1?= =?UTF-8?q?=E6=89=93=E5=BC=80=E4=BA=86=E4=B8=94=E6=8A=A5=E9=94=99=EF=BC=8C?= =?UTF-8?q?=E5=9B=A0=E4=B8=BA=E6=A8=A1=E6=9D=BF=E6=B2=A1=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E6=88=90=E5=8A=9F=EF=BC=9B=E8=AE=BE=E8=AE=A1=E5=99=A8=E7=AB=AF?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E7=9C=8B=E5=88=B0=E6=A8=A1=E6=9D=BF=E8=A2=AB?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../worker/save/CallbackSaveWorker.java | 9 +++++++++ .../fr/design/preview/DeveloperPreview.java | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java b/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java index f8a0f5d4f..ed2597f1d 100644 --- a/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java +++ b/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java @@ -63,6 +63,15 @@ public class CallbackSaveWorker extends SaveWorker { } } + public void addSuccessCallbackBeforeLast(Runnable successRunnable) { + if (successRunnableList == null) { + successRunnableList = new LinkedList<>(); + } + if (successRunnable != null) { + successRunnableList.add(successRunnableList.size() - 1, successRunnable); + } + } + public void addFailCallback(Runnable failRunnable) { if (failRunnableList == null) { failRunnableList = new LinkedList<>(); diff --git a/designer-form/src/main/java/com/fr/design/preview/DeveloperPreview.java b/designer-form/src/main/java/com/fr/design/preview/DeveloperPreview.java index 782538f63..69e514b40 100644 --- a/designer-form/src/main/java/com/fr/design/preview/DeveloperPreview.java +++ b/designer-form/src/main/java/com/fr/design/preview/DeveloperPreview.java @@ -6,10 +6,13 @@ import com.fr.design.fun.impl.AbstractPreviewProvider; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.JForm; import com.fr.design.mainframe.JTemplate; +import com.fr.design.worker.WorkerManager; +import com.fr.design.worker.save.CallbackSaveWorker; import com.fr.general.web.ParameterConstants; import java.util.HashMap; import java.util.Map; +import javax.swing.SwingWorker; /** * Created by kerry on 2020-04-23 @@ -44,6 +47,22 @@ public class DeveloperPreview extends AbstractPreviewProvider { @Override public void onClick(JTemplate jt) { super.onClick(jt); + SwingWorker worker = WorkerManager.getInstance().getWorker(jt.getRuntimeId()); + if (worker instanceof CallbackSaveWorker) { + CallbackSaveWorker callbackSaveWorker = (CallbackSaveWorker) worker; + callbackSaveWorker.addSuccessCallbackBeforeLast(new Runnable() { + @Override + public void run() { + onPreview(jt); + } + }); + } else if (jt.getEditingFILE().isEnvFile()) { + // 已经保存在当前工作目录了 + onPreview(jt); + } + } + + private void onPreview(JTemplate jt) { MutilTempalteTabPane.getInstance().closeCurrentTpl(); jt.generateForBiddenTemplate(); } From c262e42d2359c9cf4bb46f9e43845182e967f94c Mon Sep 17 00:00:00 2001 From: Starryi Date: Tue, 4 Jan 2022 15:34:43 +0800 Subject: [PATCH 09/19] =?UTF-8?q?REPORT-65371=20=E3=80=90=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E8=BE=B9=E6=A1=86=E3=80=91=E9=99=84=E4=BB=B6=E6=88=AA?= =?UTF-8?q?=E5=9B=BE=EF=BC=8C=E6=BB=9A=E5=8A=A8=E6=9D=A1=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=9C=89=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 右侧留点边距给滚动条,否则滚动条会遮挡住内容 【改动思路】 同上 --- .../fr/design/mainframe/theme/edit/cell/CellStyleEditPane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/cell/CellStyleEditPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/cell/CellStyleEditPane.java index 8efbb1eee..d8a4096ce 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/cell/CellStyleEditPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/cell/CellStyleEditPane.java @@ -198,7 +198,7 @@ public class CellStyleEditPane extends MultiTabPane { @Override protected void layoutContentPane() { super.layoutContentPane(); - leftcontentPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + leftcontentPane.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 5, original)); } } } From 5132d43d76d4912e9ade46a730359dbef59542e4 Mon Sep 17 00:00:00 2001 From: hades Date: Tue, 4 Jan 2022 15:56:06 +0800 Subject: [PATCH 10/19] =?UTF-8?q?REPORT-65381=20linux=5Farm=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=99=A8-=E7=82=B9=E5=87=BB=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=A0=8F=E6=96=87=E4=BB=B6-=E9=80=89=E9=A1=B9=EF=BC=8C?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E5=BC=B9=E7=AA=97=E5=90=8E=E5=86=8D=E7=82=B9?= =?UTF-8?q?=E5=87=BB=20=E7=A1=AE=E5=AE=9A=E6=8C=89=E9=92=AE=EF=BC=8C?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E4=B8=8D=E6=B6=88=E5=A4=B1=EF=BC=8C=E6=97=A0?= =?UTF-8?q?=E4=BB=BB=E4=BD=95=E5=8F=8D=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/fr/design/actions/file/PreferencePane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java index e3dd02e95..db94ace66 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java @@ -788,7 +788,7 @@ public class PreferencePane extends BasicPane { designerEnvManager.setJoinProductImprove(this.joinProductImproveCheckBox.isSelected()); designerEnvManager.setEmbedServerLazyStartup(this.embedServerLazyStartupCheckBox.isSelected()); designerEnvManager.setImageCompress(this.imageCompressPanelCheckBox.isSelected()); - designerEnvManager.setUseOptimizedUPM4Adapter(this.useOptimizedUPMCheckbox.isSelected()); + designerEnvManager.setUseOptimizedUPM4Adapter(this.useOptimizedUPMCheckbox != null && this.useOptimizedUPMCheckbox.isSelected()); VcsConfigManager vcsConfigManager = designerEnvManager.getVcsConfigManager(); vcsConfigManager.setSaveInterval(this.saveIntervalEditor.getValue()); vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected()); From d1321ea0815c4b4a4c4b672b38ac363728852cf6 Mon Sep 17 00:00:00 2001 From: hades Date: Tue, 4 Jan 2022 15:56:57 +0800 Subject: [PATCH 11/19] =?UTF-8?q?REPORT-65369=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8=E5=86=85=E5=AF=B9macOS12=E7=9A=84=E5=A4=84=E7=90=86-?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E5=9B=BE=E6=A0=87=E8=AE=BE=E7=BD=AE-?= =?UTF-8?q?=E5=9C=A8=E7=82=B9=E5=87=BB=20=E9=80=89=E6=8B=A9=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=97=B6=E5=9B=9E=E5=88=B0=E4=BA=86=E7=88=B6=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E7=95=8C=E9=9D=A2=EF=BC=8C=E6=B2=A1=E6=9C=89=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E6=98=BE=E7=A4=BA=E5=87=BA=E6=9D=A5=EF=BC=8C=E8=80=8C?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E5=86=8D=E6=AC=A1=E5=8D=95=E6=9C=BA=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=99=A8=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/fr/design/web/CustomIconPane.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java index 96b584020..564b09d46 100644 --- a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java +++ b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java @@ -40,6 +40,7 @@ import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.Window; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JComponent; @@ -425,7 +426,7 @@ public class CustomIconPane extends BasicPane { browseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - onBrowseButtonClicked(); + onBrowseButtonClicked(SwingUtilities.getWindowAncestor(EditIconDialog.this)); } }); @@ -460,11 +461,11 @@ public class CustomIconPane extends BasicPane { this.add(centerPane, BorderLayout.CENTER); } - private void onBrowseButtonClicked() { + private void onBrowseButtonClicked(Window parent) { // carl:不知道是否只要png格式,反正导出时全部都转成png了 FileChooserProvider fileChooserProvider = FileChooserFactory.createFileChooser(FileChooserArgs.newBuilder(). setFilter("Icon Image File", "*.jpg", "*.jpeg", "*.png", "*.gif").build()); - if (JFileChooser.APPROVE_OPTION == fileChooserProvider.showDialog(DesignerContext.getDesignerFrame())) { + if (JFileChooser.APPROVE_OPTION == fileChooserProvider.showDialog(parent)) { String path = fileChooserProvider.getSelectedFile().getAbsolutePath(); // 图片存储有最大值48*48限制,没有超过最大值时,按原图大小存储,超过最大值后,压缩至最大值存储 Image image = BaseUtils.readImage(path); From b74f5d3bd323a8a78d7ada1bd022e41ba53d7e44 Mon Sep 17 00:00:00 2001 From: Hoky <303455184@qq.com> Date: Tue, 4 Jan 2022 16:25:24 +0800 Subject: [PATCH 12/19] =?UTF-8?q?REPORT-65290=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8-=E6=B0=B4=E5=8D=B0=EF=BC=8C=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E6=94=B9=E5=8F=98=E6=B0=B4=E5=8D=B0=E5=BC=80=E5=85=B3=EF=BC=8C?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=B0=B4=E5=8D=B0=E5=8F=98=E6=88=90=E4=BA=86?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E5=8D=95=E7=8B=AC=E8=AE=BE=E7=BD=AE=201.?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B0=B4=E5=8D=B0=E7=9A=84isvalid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fr/design/report/WatermarkSettingPane.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java b/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java index 0cc211c5f..e79bfcf6b 100644 --- a/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java +++ b/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java @@ -1,5 +1,6 @@ package com.fr.design.report; +import com.fr.base.iofile.attr.WaterMarkProvideConstant; import com.fr.base.iofile.attr.WatermarkAttr; import com.fr.design.dialog.AbstractTemplateServerSettingPane; import com.fr.report.core.ReportUtils; @@ -42,13 +43,13 @@ public class WatermarkSettingPane extends AbstractTemplateServerSettingPane { } public void populate(WatermarkAttr watermark) { - if (!watermark.isValid()) { + if (watermark.getWaterMarkProvider().equals(WaterMarkProvideConstant.TEMPLATE)) { + chooseComboBox.setSelectedIndex(SINGLE_SET); + watermarkPane.populate(watermark); + } else { chooseComboBox.setSelectedIndex(SERVER_SET); populateServerSettings(); - return; } - chooseComboBox.setSelectedIndex(SINGLE_SET); - watermarkPane.populate(watermark); } From 354400bec3cc6a452d291af16e8097d393115dd7 Mon Sep 17 00:00:00 2001 From: Starryi Date: Wed, 5 Jan 2022 11:36:54 +0800 Subject: [PATCH 13/19] =?UTF-8?q?REPORT-64811=2010.0=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8=E4=B8=8B=E8=BD=BD=E7=9A=84=E7=BB=84=E4=BB=B6=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=97=A0=E6=B3=95=E8=A7=A3=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 10.0设计器无法通过配置文件使用测试服务器的下载接口,导致文件 下载失败. 【改动思路】 和11.0一样优先使用配置文件中的地址 --- .../com/fr/design/mainframe/share/util/DownloadUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java b/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java index b6375b1d6..6c6e156b0 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java @@ -38,8 +38,8 @@ import java.util.Set; * created by Harrison on 2020/05/27 **/ public class DownloadUtils { - private static final String REUSES_URL = CloudCenter.getInstance().acquireUrlByKind("af.reuseInfo") + "file/download"; - private static final String PACKAGE_REUSES_URL = CloudCenter.getInstance().acquireUrlByKind("af.reuseInfo") + "package/download/"; + private static final String REUSES_URL = ShareComponentConstants.REU_INFO_PATH + "file/download"; + private static final String PACKAGE_REUSES_URL = ShareComponentConstants.REU_INFO_PATH + "package/download/"; private static final String CERTIFICATE_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtsz62CPSWXZE/IYZRiAuTSZkw\n" + "1WOwer8+JFktK0uKLAUuQoBr+UjAMFtRA8W7JgKMDwZy/2liEAiXEOSPU/hrdV8D\n" + "tT541LnGi1X/hXiRwuttPWYN3L2GYm/d5blU+FBNwghBIrdAxXTzYBc6P4KL/oYX\n" + From da9398eead40e011cfabfd388fe1d157e92c626e Mon Sep 17 00:00:00 2001 From: Starryi Date: Wed, 5 Jan 2022 17:04:09 +0800 Subject: [PATCH 14/19] =?UTF-8?q?REPORT-65449=20=E5=9C=A8=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=8C=85=E8=AF=A6=E6=83=85=E9=A1=B5=E6=8B=96=E6=8B=BD?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=B9=B6=E4=BF=AE=E6=94=B9=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E5=86=8D=E7=82=B9=E5=88=B0=E5=9C=A8=E7=BA=BF=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=EF=BC=8C=E6=A0=87=E7=AD=BE=E5=92=8C=E5=86=85=E5=AE=B9=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=B8=8D=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 在线组件库页面刷新为所有在线组件列表时,Tab标题没有作出对应改变,出现了Tab投显示组件包,而列表页 显示所有在线组件的情况 【改动思路】 刷新时修改标题头"组件" --- .../mainframe/share/ui/online/OnlineWidgetTabPane.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java index b48b74e67..52ea26bc2 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java @@ -24,6 +24,7 @@ public class OnlineWidgetTabPane extends JPanel { private static final String COMPONENT = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share"); private static final String COMPONENT_PACKAGE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share_Package"); private static final String COMPONENT_EMBED = "COMPONENT_EMBED"; + private UITabGroup headGroup; private CardLayout cardLayout; private JPanel centerPane; private boolean packagePaneCreated = false; @@ -43,7 +44,7 @@ public class OnlineWidgetTabPane extends JPanel { this.centerPane.add(new OnlineWidgetShowPane(sharableWidgets), COMPONENT); this.centerPane.add( embedFilterShowPane = new OnlineEmbedFilterShowPane(new OnlineWidgetShowPane(sharableWidgets, OnlineWidgetSortType.SALES)), COMPONENT_EMBED); //延迟组件包面板的初始化,防止组件面板里组件的缩略图和组件包面板里组件的缩略图一起加载 - UITabGroup headGroup = new UITabGroup(new String[]{COMPONENT, COMPONENT_PACKAGE}) { + this.headGroup = new UITabGroup(new String[]{COMPONENT, COMPONENT_PACKAGE}) { public void tabChanged(int newSelectedIndex) { for (TabChangeListener changeListener : tabChangeListeners) { changeListener.tabChange(newSelectedIndex); @@ -63,7 +64,7 @@ public class OnlineWidgetTabPane extends JPanel { } }; - headGroup.setSelectedIndex(0); + this.headGroup.setSelectedIndex(0); this.centerPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); jPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); @@ -84,6 +85,7 @@ public class OnlineWidgetTabPane extends JPanel { } } public void refreshPane() { + this.headGroup.setSelectedIndex(0); this.cardLayout.show(centerPane, ComponentShareUtil.needShowEmbedFilterPane() ? COMPONENT_EMBED : COMPONENT); } From 914aa241de62f41ef830b013e1b7726ef089f7cf Mon Sep 17 00:00:00 2001 From: Hoky <303455184@qq.com> Date: Wed, 5 Jan 2022 20:07:14 +0800 Subject: [PATCH 15/19] =?UTF-8?q?REPORT-65474=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=99=A8-=E6=B0=B4=E5=8D=B0=EF=BC=8C=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E6=94=B9=E5=8F=98=E6=B0=B4=E5=8D=B0=E5=BC=80=E5=85=B3=EF=BC=8C?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=B0=B4=E5=8D=B0=E5=8F=98=E6=88=90=E4=BA=86?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E5=8D=95=E7=8B=AC=E8=AE=BE=E7=BD=AE=201.?= =?UTF-8?q?=E6=96=B0=E5=BB=BA=E6=B0=B4=E5=8D=B0=E9=BB=98=E8=AE=A4=E4=B8=8D?= =?UTF-8?q?=E6=98=AF=E6=A8=A1=E6=9D=BF=E6=B0=B4=E5=8D=B0=EF=BC=8C=E5=BD=93?= =?UTF-8?q?=E6=96=B0=E5=BB=BA=E6=A8=A1=E6=9D=BF=E6=B0=B4=E5=8D=B0=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E5=80=99=EF=BC=8C=E8=BF=9B=E8=A1=8C=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8D=B3=E5=8F=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fr/design/report/WatermarkSettingPane.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java b/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java index e79bfcf6b..f3de6eef9 100644 --- a/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java +++ b/designer-base/src/main/java/com/fr/design/report/WatermarkSettingPane.java @@ -34,6 +34,7 @@ public class WatermarkSettingPane extends AbstractTemplateServerSettingPane { @Override protected void populateServerSettings() { WatermarkAttr watermarkAttr = ReportUtils.getWatermarkAttrFromServerConfig(); + watermarkAttr.setValid(true); watermarkPane.populate(watermarkAttr); } @@ -55,8 +56,9 @@ public class WatermarkSettingPane extends AbstractTemplateServerSettingPane { public WatermarkAttr update() { WatermarkAttr watermark = watermarkPane.update(); - if (isUsingServerSettings()) { - watermark.setValid(false); + if (!isUsingServerSettings()) { + watermark.setValid(true); + watermark.setWaterMarkProvider(WaterMarkProvideConstant.TEMPLATE); } return watermark; } From b4c6bd77b9b4d7e5a45e0a331e204c185a74da8d Mon Sep 17 00:00:00 2001 From: pengda Date: Thu, 6 Jan 2022 14:50:39 +0800 Subject: [PATCH 16/19] =?UTF-8?q?REPORT-58833=20js=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fr/design/formula/FormulaPane.java | 10 +- .../AutoCompleteExtraRefreshComponent.java | 5 + ...toCompleteWithExtraRefreshPopupWindow.java | 982 +++++++++++++ .../AutoCompletionWithExtraRefresh.java | 1260 +++++++++++++++++ .../FormulaAutoCompletePopupWindow.java | 976 +------------ .../FormulaPaneAutoCompletion.java | 1241 +--------------- .../JSAutoCompletePopupWindow.java | 16 + .../JSImplPaneAutoCompletion.java | 31 + .../fr/design/javascript/JSContentPane.java | 167 ++- .../JSContentWithDescriptionPane.java | 858 +++++++++++ .../design/javascript/JavaScriptImplPane.java | 95 +- .../javascript/NewJavaScriptImplPane.java | 23 + .../jsapi/CategoryTreeNodesUserObject.java | 21 + .../javascript/jsapi/JSAPITreeHelper.java | 155 ++ .../javascript/jsapi/JSAPIUserObject.java | 9 + .../jsapi/JSImplPopulateAction.java | 7 + .../javascript/jsapi/JSImplUpdateAction.java | 7 + .../fr/design/javascript/jsapi/category.json | 47 + .../com/fr/design/javascript/jsapi/jsapi.json | 33 + .../design/javascript/ListenerEditPane.java | 2 +- 20 files changed, 3676 insertions(+), 2269 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteExtraRefreshComponent.java create mode 100644 designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteWithExtraRefreshPopupWindow.java create mode 100644 designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompletionWithExtraRefresh.java create mode 100644 designer-base/src/main/java/com/fr/design/gui/autocomplete/JSAutoCompletePopupWindow.java create mode 100644 designer-base/src/main/java/com/fr/design/gui/autocomplete/JSImplPaneAutoCompletion.java create mode 100644 designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java create mode 100644 designer-base/src/main/java/com/fr/design/javascript/NewJavaScriptImplPane.java create mode 100644 designer-base/src/main/java/com/fr/design/javascript/jsapi/CategoryTreeNodesUserObject.java create mode 100644 designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPITreeHelper.java create mode 100644 designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPIUserObject.java create mode 100644 designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplPopulateAction.java create mode 100644 designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplUpdateAction.java create mode 100644 designer-base/src/main/resources/com/fr/design/javascript/jsapi/category.json create mode 100644 designer-base/src/main/resources/com/fr/design/javascript/jsapi/jsapi.json diff --git a/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java b/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java index 904cdf00b..da61fab15 100644 --- a/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java +++ b/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java @@ -16,6 +16,7 @@ import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.autocomplete.AutoCompleteExtraRefreshComponent; import com.fr.design.gui.autocomplete.CompletionCellRenderer; import com.fr.design.gui.autocomplete.CompletionProvider; import com.fr.design.gui.autocomplete.DefaultCompletionProvider; @@ -416,7 +417,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { autoCompletion = new FormulaPaneAutoCompletion(provider); autoCompletion.setListCellRenderer(new CompletionCellRenderer()); autoCompletion.install(formulaTextArea); - autoCompletion.installVariableTree(variableTreeAndDescriptionArea); + autoCompletion.installExtraRefreshComponent(variableTreeAndDescriptionArea); } @@ -1036,7 +1037,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { } } - public class VariableTreeAndDescriptionArea extends JPanel { + public class VariableTreeAndDescriptionArea extends JPanel implements AutoCompleteExtraRefreshComponent { private JTree variablesTree; private UITextArea descriptionTextArea; @@ -1277,6 +1278,11 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { functionTypeList.setSelectedIndex(0); } + @Override + public void refresh(String replacementText) { + refreshText(replacementText); + } + /* * 查看函数的详细信息 */ diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteExtraRefreshComponent.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteExtraRefreshComponent.java new file mode 100644 index 000000000..ff6b7faef --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteExtraRefreshComponent.java @@ -0,0 +1,5 @@ +package com.fr.design.gui.autocomplete; + +public interface AutoCompleteExtraRefreshComponent { + void refresh(String replacementText); +} diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteWithExtraRefreshPopupWindow.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteWithExtraRefreshPopupWindow.java new file mode 100644 index 000000000..3f4f19177 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompleteWithExtraRefreshPopupWindow.java @@ -0,0 +1,982 @@ +package com.fr.design.gui.autocomplete; + +import com.fr.design.gui.syntax.ui.rsyntaxtextarea.PopupWindowDecorator; +import com.fr.log.FineLoggerFactory; +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JWindow; +import javax.swing.KeyStroke; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.plaf.ListUI; +import javax.swing.text.Caret; +import javax.swing.text.JTextComponent; + +public abstract class AutoCompleteWithExtraRefreshPopupWindow extends JWindow implements CaretListener, + ListSelectionListener, MouseListener { + private final static int DIS = 5; + /** + * The parent AutoCompletion instance. + */ + private AutoCompletion ac; + + /** + * The list of completion choices. + */ + private JList list; + + /** + * The contents of {@link #list()}. + */ + private CompletionListModel model; + + /** + * A hack to work around the fact that we clear our completion model (and + * our selection) when hiding the completion window. This allows us to + * still know what the user selected after the popup is hidden. + */ + private Completion lastSelection; + + /** + * Optional popup window containing a description of the currently + * selected completion. + */ + private AutoCompleteDescWindow descWindow; + + /** + * The preferred size of the optional description window. This field + * only exists because the user may (and usually will) set the size of + * the description window before it exists (it must be parented to a + * Window). + */ + private Dimension preferredDescWindowSize; + + + + /** + * Whether the completion window and the optional description window + * should be displayed above the current caret position (as opposed to + * underneath it, which is preferred unless there is not enough space). + */ + private boolean aboveCaret; + + private int lastLine; + + private KeyActionPair escapeKap; + private KeyActionPair upKap; + private KeyActionPair downKap; + private KeyActionPair leftKap; + private KeyActionPair rightKap; + private KeyActionPair enterKap; + private KeyActionPair tabKap; + private KeyActionPair homeKap; + private KeyActionPair endKap; + private KeyActionPair pageUpKap; + private KeyActionPair pageDownKap; + private KeyActionPair ctrlCKap; + + private KeyActionPair oldEscape, oldUp, oldDown, oldLeft, oldRight, + oldEnter, oldTab, oldHome, oldEnd, oldPageUp, oldPageDown, + oldCtrlC; + + /** + * The space between the caret and the completion popup. + */ + private static final int VERTICAL_SPACE = 1; + + /** + * The class name of the Substance List UI. + */ + private static final String SUBSTANCE_LIST_UI = + "org.pushingpixels.substance.internal.ui.SubstanceListUI"; + + + protected AutoCompleteExtraRefreshComponent component; + + + /** + * Constructor. + * + * @param parent The parent window (hosting the text component). + * @param ac The auto-completion instance. + */ + public AutoCompleteWithExtraRefreshPopupWindow(Window parent, final AutoCompletion ac) { + + super(parent); + ComponentOrientation o = ac.getTextComponentOrientation(); + + this.ac = ac; + model = new CompletionListModel(); + list = new PopupList(model); + + list.setCellRenderer(new DelegatingCellRenderer()); + list.addListSelectionListener(this); + list.addMouseListener(this); + + JPanel contentPane = new JPanel(new BorderLayout()); + JScrollPane sp = new JScrollPane(list, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + // In 1.4, JScrollPane.setCorner() has a bug where it won't accept + // JScrollPane.LOWER_TRAILING_CORNER, even though that constant is + // defined. So we have to put the logic added in 1.5 to handle it + // here. + JPanel corner = new SizeGrip(); + //sp.setCorner(JScrollPane.LOWER_TRAILING_CORNER, corner); + boolean isLeftToRight = o.isLeftToRight(); + String str = isLeftToRight ? JScrollPane.LOWER_RIGHT_CORNER : + JScrollPane.LOWER_LEFT_CORNER; + sp.setCorner(str, corner); + + contentPane.add(sp); + setContentPane(contentPane); + applyComponentOrientation(o); + + // Give apps a chance to decorate us with drop shadows, etc. + if (Util.getShouldAllowDecoratingMainAutoCompleteWindows()) { + PopupWindowDecorator decorator = PopupWindowDecorator.get(); + if (decorator != null) { + decorator.decorate(this); + } + } + + pack(); + + setFocusableWindowState(false); + + lastLine = -1; + + } + + + public void caretUpdate(CaretEvent e) { + if (isVisible()) { // Should always be true + int line = ac.getLineOfCaret(); + if (line != lastLine) { + lastLine = -1; + setVisible(false); + } else { + doAutocomplete(); + } + } else if (AutoCompletion.isDebug()) { + Thread.dumpStack(); + } + } + + + /** + * Creates the description window. + * + * @return The description window. + */ + private AutoCompleteDescWindow createDescriptionWindow() { + AutoCompleteDescWindow dw = new AutoCompleteDescWindow(this, ac); + dw.applyComponentOrientation(ac.getTextComponentOrientation()); + Dimension size = preferredDescWindowSize; + if (size == null) { + size = getSize(); + } + dw.setSize(size); + return dw; + } + + + /** + * Creates the mappings from keys to Actions we'll be putting into the + * text component's ActionMap and InputMap. + */ + private void createKeyActionPairs() { + + // Actions we'll install. + EnterAction enterAction = new EnterAction(); + escapeKap = new KeyActionPair("Escape", new EscapeAction()); + upKap = new KeyActionPair("Up", new UpAction()); + downKap = new KeyActionPair("Down", new DownAction()); + leftKap = new KeyActionPair("Left", new LeftAction()); + rightKap = new KeyActionPair("Right", new RightAction()); + enterKap = new KeyActionPair("Enter", enterAction); + tabKap = new KeyActionPair("Tab", enterAction); + homeKap = new KeyActionPair("Home", new HomeAction()); + endKap = new KeyActionPair("End", new EndAction()); + pageUpKap = new KeyActionPair("PageUp", new PageUpAction()); + pageDownKap = new KeyActionPair("PageDown", new PageDownAction()); + ctrlCKap = new KeyActionPair("CtrlC", new CopyAction()); + + // Buffers for the actions we replace. + oldEscape = new KeyActionPair(); + oldUp = new KeyActionPair(); + oldDown = new KeyActionPair(); + oldLeft = new KeyActionPair(); + oldRight = new KeyActionPair(); + oldEnter = new KeyActionPair(); + oldTab = new KeyActionPair(); + oldHome = new KeyActionPair(); + oldEnd = new KeyActionPair(); + oldPageUp = new KeyActionPair(); + oldPageDown = new KeyActionPair(); + oldCtrlC = new KeyActionPair(); + + } + + + protected void doAutocomplete() { + lastLine = ac.refreshPopupWindow(); + } + + + /** + * Returns the copy keystroke to use for this platform. + * + * @return The copy keystroke. + */ + private static final KeyStroke getCopyKeyStroke() { + int key = KeyEvent.VK_C; + int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + return KeyStroke.getKeyStroke(key, mask); + } + + + /** + * Returns the default list cell renderer used when a completion provider + * does not supply its own. + * + * @return The default list cell renderer. + * @see #setListCellRenderer(ListCellRenderer) + */ + public ListCellRenderer getListCellRenderer() { + DelegatingCellRenderer dcr = (DelegatingCellRenderer) list. + getCellRenderer(); + return dcr.getFallbackCellRenderer(); + } + + + /** + * Returns the selected value, or null if nothing is selected. + * + * @return The selected value. + */ + public Completion getSelection() { + return isShowing() ? (Completion) list.getSelectedValue() : lastSelection; + } + + + /** + * Inserts the currently selected completion. + * + * @see #getSelection() + */ + private void insertSelectedCompletion() { + Completion comp = getSelection(); + ac.insertCompletion(comp); + } + + public void installComp(AutoCompleteExtraRefreshComponent component){ + this.component = component; + } + + public void refreshInstallComp() { + component.refresh(getSelection().getReplacementText()); + } + + /** + * Registers keyboard actions to listen for in the text component and + * intercept. + * + * @see #uninstallKeyBindings() + */ + private void installKeyBindings() { + + if (AutoCompletion.isDebug()) { + FineLoggerFactory.getLogger().debug("PopupWindow: Installing keybindings"); + } + + if (escapeKap == null) { // Lazily create actions. + createKeyActionPairs(); + } + + JTextComponent comp = ac.getTextComponent(); + InputMap im = comp.getInputMap(); + ActionMap am = comp.getActionMap(); + + replaceAction(im, am, KeyEvent.VK_ESCAPE, escapeKap, oldEscape); + if (AutoCompletion.isDebug() && oldEscape.action == escapeKap.action) { + Thread.dumpStack(); + } + replaceAction(im, am, KeyEvent.VK_UP, upKap, oldUp); + replaceAction(im, am, KeyEvent.VK_LEFT, leftKap, oldLeft); + replaceAction(im, am, KeyEvent.VK_DOWN, downKap, oldDown); + replaceAction(im, am, KeyEvent.VK_RIGHT, rightKap, oldRight); + replaceAction(im, am, KeyEvent.VK_ENTER, enterKap, oldEnter); + replaceAction(im, am, KeyEvent.VK_TAB, tabKap, oldTab); + replaceAction(im, am, KeyEvent.VK_HOME, homeKap, oldHome); + replaceAction(im, am, KeyEvent.VK_END, endKap, oldEnd); + replaceAction(im, am, KeyEvent.VK_PAGE_UP, pageUpKap, oldPageUp); + replaceAction(im, am, KeyEvent.VK_PAGE_DOWN, pageDownKap, oldPageDown); + + // Make Ctrl+C copy from description window. This isn't done + // automagically because the desc. window is not focusable, and copying + // from text components can only be done from focused components. + KeyStroke ks = getCopyKeyStroke(); + oldCtrlC.key = im.get(ks); + im.put(ks, ctrlCKap.key); + oldCtrlC.action = am.get(ctrlCKap.key); + am.put(ctrlCKap.key, ctrlCKap.action); + + comp.addCaretListener(this); + + } + + + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2 && e.getButton() == 1) { + insertSelectedCompletion(); + } + } + + + public void mouseEntered(MouseEvent e) { + } + + + public void mouseExited(MouseEvent e) { + } + + + public void mousePressed(MouseEvent e) { + refreshInstallComp(); + } + + + public void mouseReleased(MouseEvent e) { + } + + + /** + * Positions the description window relative to the completion choices + * window. We assume there is room on one side of the other for this + * entire window to fit. + */ + private void positionDescWindow() { + + boolean showDescWindow = descWindow != null && ac.isShowDescWindow(); + if (!showDescWindow) { + return; + } + + // Don't use getLocationOnScreen() as this throws an exception if + // window isn't visible yet, but getLocation() doesn't, and is in + // screen coordinates! + Point p = getLocation(); + Rectangle screenBounds = Util.getScreenBoundsForPoint(p.x, p.y); + //Dimension screenSize = getToolkit().getScreenSize(); + //int totalH = Math.max(getHeight(), descWindow.getHeight()); + + // Try to position to the right first (LTR) + int x; + if (ac.getTextComponentOrientation().isLeftToRight()) { + x = getX() + getWidth() + DIS; + if (x + descWindow.getWidth() > screenBounds.x + screenBounds.width) { // doesn't fit + x = getX() - DIS - descWindow.getWidth(); + } + } else { // RTL + x = getX() - DIS - descWindow.getWidth(); + if (x < screenBounds.x) { // Doesn't fit + x = getX() + getWidth() + DIS; + } + } + + int y = getY(); + if (aboveCaret) { + y = y + getHeight() - descWindow.getHeight(); + } + + if (x != descWindow.getX() || y != descWindow.getY()) { + descWindow.setLocation(x, y); + } + + } + + + /** + * "Puts back" the original key/Action pair for a keystroke. This is used + * when this popup is hidden. + * + * @param im The input map. + * @param am The action map. + * @param key The keystroke whose key/Action pair to change. + * @param kap The (original) key/Action pair. + * @see #replaceAction(InputMap, ActionMap, int, KeyActionPair, KeyActionPair) + */ + private void putBackAction(InputMap im, ActionMap am, int key, + KeyActionPair kap) { + KeyStroke ks = KeyStroke.getKeyStroke(key, 0); + am.put(im.get(ks), kap.action); // Original action for the "new" key + im.put(ks, kap.key); // Original key for the keystroke. + } + + + /** + * Replaces a key/Action pair in an InputMap and ActionMap with a new + * pair. + * + * @param im The input map. + * @param am The action map. + * @param key The keystroke whose information to replace. + * @param kap The new key/Action pair for key. + * @param old A buffer in which to place the old key/Action pair. + * @see #putBackAction(InputMap, ActionMap, int, KeyActionPair) + */ + private void replaceAction(InputMap im, ActionMap am, int key, + KeyActionPair kap, KeyActionPair old) { + KeyStroke ks = KeyStroke.getKeyStroke(key, 0); + old.key = im.get(ks); + im.put(ks, kap.key); + old.action = am.get(kap.key); + am.put(kap.key, kap.action); + } + + + /** + * Selects the first item in the completion list. + * + * @see #selectLastItem() + */ + private void selectFirstItem() { + if (model.getSize() > 0) { + list.setSelectedIndex(0); + list.ensureIndexIsVisible(0); + } + } + + + /** + * Selects the last item in the completion list. + * + * @see #selectFirstItem() + */ + private void selectLastItem() { + int index = model.getSize() - 1; + if (index > -1) { + list.setSelectedIndex(index); + list.ensureIndexIsVisible(index); + } + } + + + /** + * Selects the next item in the completion list. + * + * @see #selectPreviousItem() + */ + private void selectNextItem() { + int index = list.getSelectedIndex(); + if (index > -1) { + index = (index + 1) % model.getSize(); + list.setSelectedIndex(index); + list.ensureIndexIsVisible(index); + } + } + + + /** + * Selects the completion item one "page down" from the currently selected + * one. + * + * @see #selectPageUpItem() + */ + private void selectPageDownItem() { + int visibleRowCount = list.getVisibleRowCount(); + int i = Math.min(list.getModel().getSize() - 1, + list.getSelectedIndex() + visibleRowCount); + list.setSelectedIndex(i); + list.ensureIndexIsVisible(i); + } + + + /** + * Selects the completion item one "page up" from the currently selected + * one. + * + * @see #selectPageDownItem() + */ + private void selectPageUpItem() { + int visibleRowCount = list.getVisibleRowCount(); + int i = Math.max(0, list.getSelectedIndex() - visibleRowCount); + list.setSelectedIndex(i); + list.ensureIndexIsVisible(i); + } + + + /** + * Selects the previous item in the completion list. + * + * @see #selectNextItem() + */ + private void selectPreviousItem() { + int index = list.getSelectedIndex(); + switch (index) { + case 0: + index = list.getModel().getSize() - 1; + break; + case -1: // Check for an empty list (would be an error) + index = list.getModel().getSize() - 1; + if (index == -1) { + return; + } + break; + default: + index = index - 1; + break; + } + list.setSelectedIndex(index); + list.ensureIndexIsVisible(index); + } + + + /** + * Sets the completions to display in the choices list. The first + * completion is selected. + * + * @param completions The completions to display. + */ + public void setCompletions(List completions) { + model.setContents(completions); + selectFirstItem(); + } + + + /** + * Sets the size of the description window. + * + * @param size The new size. This cannot be null. + */ + public void setDescriptionWindowSize(Dimension size) { + if (descWindow != null) { + descWindow.setSize(size); + } else { + preferredDescWindowSize = size; + } + } + + + /** + * Sets the default list cell renderer to use when a completion provider + * does not supply its own. + * + * @param renderer The renderer to use. If this is null, + * a default renderer is used. + * @see #getListCellRenderer() + */ + public void setListCellRenderer(ListCellRenderer renderer) { + DelegatingCellRenderer dcr = (DelegatingCellRenderer) list. + getCellRenderer(); + dcr.setFallbackCellRenderer(renderer); + } + + + /** + * Sets the location of this window to be "good" relative to the specified + * rectangle. That rectangle should be the location of the text + * component's caret, in screen coordinates. + * + * @param r The text component's caret position, in screen coordinates. + */ + public void setLocationRelativeTo(Rectangle r) { + + // Multi-monitor support - make sure the completion window (and + // description window, if applicable) both fit in the same window in + // a multi-monitor environment. To do this, we decide which monitor + // the rectangle "r" is in, and use that one (just pick top-left corner + // as the defining point). + Rectangle screenBounds = Util.getScreenBoundsForPoint(r.x, r.y); + //Dimension screenSize = getToolkit().getScreenSize(); + + boolean showDescWindow = descWindow != null && ac.isShowDescWindow(); + int totalH = getHeight(); + if (showDescWindow) { + totalH = Math.max(totalH, descWindow.getHeight()); + } + + // Try putting our stuff "below" the caret first. We assume that the + // entire height of our stuff fits on the screen one way or the other. + aboveCaret = false; + int y = r.y + r.height + VERTICAL_SPACE; + if (y + totalH > screenBounds.height) { + y = r.y - VERTICAL_SPACE - getHeight(); + aboveCaret = true; + } + + // Get x-coordinate of completions. Try to align left edge with the + // caret first. + int x = r.x; + if (!ac.getTextComponentOrientation().isLeftToRight()) { + x -= getWidth(); // RTL => align right edge + } + if (x < screenBounds.x) { + x = screenBounds.x; + } else if (x + getWidth() > screenBounds.x + screenBounds.width) { // completions don't fit + x = screenBounds.x + screenBounds.width - getWidth(); + } + + setLocation(x, y); + + // Position the description window, if necessary. + if (showDescWindow) { + positionDescWindow(); + } + + } + + + /** + * Toggles the visibility of this popup window. + * + * @param visible Whether this window should be visible. + */ + @Override + public void setVisible(boolean visible) { + + if (visible != isVisible()) { + + if (visible) { + installKeyBindings(); + lastLine = ac.getLineOfCaret(); + selectFirstItem(); + if (descWindow == null && ac.isShowDescWindow()) { + descWindow = createDescriptionWindow(); + positionDescWindow(); + } + // descWindow needs a kick-start the first time it's displayed. + // Also, the newly-selected item in the choices list is + // probably different from the previous one anyway. + if (descWindow != null) { + Completion c = (Completion) list.getSelectedValue(); + if (c != null) { + descWindow.setDescriptionFor(c); + } + } + } else { + uninstallKeyBindings(); + } + + super.setVisible(visible); + + // Some languages, such as Java, can use quite a lot of memory + // when displaying hundreds of completion choices. We pro-actively + // clear our list model here to make them available for GC. + // Otherwise, they stick around, and consider the following: a + // user starts code-completion for Java 5 SDK classes, then hides + // the dialog, then changes the "class path" to use a Java 6 SDK + // instead. On pressing Ctrl+space, a new array of Completions is + // created. If this window holds on to the previous Completions, + // you're getting roughly 2x the necessary Completions in memory + // until the Completions are actually passed to this window. + if (!visible) { // Do after super.setVisible(false) + lastSelection = (Completion) list.getSelectedValue(); + model.clear(); + } + + // Must set descWindow's visibility one way or the other each time, + // because of the way child JWindows' visibility is handled - in + // some ways it's dependent on the parent, in other ways it's not. + if (descWindow != null) { + descWindow.setVisible(visible && ac.isShowDescWindow()); + } + + } + + } + + + /** + * Stops intercepting certain keystrokes from the text component. + * + * @see #installKeyBindings() + */ + private void uninstallKeyBindings() { + + if (AutoCompletion.isDebug()) { + FineLoggerFactory.getLogger().debug("PopupWindow: Removing keybindings"); + } + + JTextComponent comp = ac.getTextComponent(); + InputMap im = comp.getInputMap(); + ActionMap am = comp.getActionMap(); + + putBackAction(im, am, KeyEvent.VK_ESCAPE, oldEscape); + putBackAction(im, am, KeyEvent.VK_UP, oldUp); + putBackAction(im, am, KeyEvent.VK_DOWN, oldDown); + putBackAction(im, am, KeyEvent.VK_LEFT, oldLeft); + putBackAction(im, am, KeyEvent.VK_RIGHT, oldRight); + putBackAction(im, am, KeyEvent.VK_ENTER, oldEnter); + putBackAction(im, am, KeyEvent.VK_TAB, oldTab); + putBackAction(im, am, KeyEvent.VK_HOME, oldHome); + putBackAction(im, am, KeyEvent.VK_END, oldEnd); + putBackAction(im, am, KeyEvent.VK_PAGE_UP, oldPageUp); + putBackAction(im, am, KeyEvent.VK_PAGE_DOWN, oldPageDown); + + // Ctrl+C + KeyStroke ks = getCopyKeyStroke(); + am.put(im.get(ks), oldCtrlC.action); // Original action + im.put(ks, oldCtrlC.key); // Original key + + comp.removeCaretListener(this); + + } + + + /** + * Updates the LookAndFeel of this window and the description + * window. + */ + public void updateUI() { + SwingUtilities.updateComponentTreeUI(this); + if (descWindow != null) { + descWindow.updateUI(); + } + } + + + /** + * Called when a new item is selected in the popup list. + * + * @param e The event. + */ + public void valueChanged(ListSelectionEvent e) { + if (!e.getValueIsAdjusting()) { + Object value = list.getSelectedValue(); + if (value != null && descWindow != null) { + descWindow.setDescriptionFor((Completion) value); + positionDescWindow(); + } + } + } + + + class CopyAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + boolean doNormalCopy = false; + if (descWindow != null && descWindow.isVisible()) { + doNormalCopy = !descWindow.copy(); + } + if (doNormalCopy) { + ac.getTextComponent().copy(); + } + } + + } + + + class DownAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + selectNextItem(); + refreshInstallComp(); + } + } + + } + + + class EndAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + selectLastItem(); + } + } + + } + + + class EnterAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + insertSelectedCompletion(); + refreshInstallComp(); + } + } + + } + + + class EscapeAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + setVisible(false); + } + } + + } + + + class HomeAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + selectFirstItem(); + } + } + + } + + + /** + * A mapping from a key (an Object) to an Action. + */ + private static class KeyActionPair { + + public Object key; + public Action action; + + public KeyActionPair() { + } + + public KeyActionPair(Object key, Action a) { + this.key = key; + this.action = a; + } + + } + + + class LeftAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + JTextComponent comp = ac.getTextComponent(); + Caret c = comp.getCaret(); + int dot = c.getDot(); + if (dot > 0) { + c.setDot(--dot); + // Ensure moving left hasn't moved us up a line, thus + // hiding the popup window. + if (comp.isVisible()) { + if (lastLine != -1) { + doAutocomplete(); + } + } + } + } + } + + } + + + class PageDownAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + selectPageDownItem(); + } + } + + } + + + class PageUpAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + selectPageUpItem(); + } + } + + } + + + /** + * The actual list of completion choices in this popup window. + */ + private class PopupList extends JList { + + public PopupList(CompletionListModel model) { + super(model); + } + + @Override + public void setUI(ListUI ui) { + if (Util.getUseSubstanceRenderers() && + SUBSTANCE_LIST_UI.equals(ui.getClass().getName())) { + // Substance requires its special ListUI be installed for + // its renderers to actually render (!), but long completion + // lists (e.g. PHPCompletionProvider in RSTALanguageSupport) + // will simply populate too slowly on initial display (when + // calculating preferred size of all items), so in this case + // we give a prototype cell value. + CompletionProvider p = ac.getCompletionProvider(); + BasicCompletion bc = new BasicCompletion(p, "Hello world"); + setPrototypeCellValue(bc); + } else { + // Our custom UI that is faster for long HTML completion lists. + ui = new FastListUI(); + setPrototypeCellValue(null); + } + super.setUI(ui); + } + + } + + + class RightAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + JTextComponent comp = ac.getTextComponent(); + Caret c = comp.getCaret(); + int dot = c.getDot(); + if (dot < comp.getDocument().getLength()) { + c.setDot(++dot); + // Ensure moving right hasn't moved us up a line, thus + // hiding the popup window. + if (comp.isVisible()) { + if (lastLine != -1) { + doAutocomplete(); + } + } + } + } + } + + } + + + class UpAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isVisible()) { + selectPreviousItem(); + refreshInstallComp(); + } + } + + } + +} diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompletionWithExtraRefresh.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompletionWithExtraRefresh.java new file mode 100644 index 000000000..4def5370d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AutoCompletionWithExtraRefresh.java @@ -0,0 +1,1260 @@ +package com.fr.design.gui.autocomplete; + +import com.fr.design.formula.FormulaPane; +import java.awt.ComponentOrientation; +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.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.KeyStroke; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIManager; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.JTextComponent; + + +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + +public abstract class AutoCompletionWithExtraRefresh extends AutoCompletion{ + private AutoCompleteExtraRefreshComponent area; + + /** + * The text component we're providing completion for. + */ + private JTextComponent textComponent; + + /** + * The parent window of {@link #textComponent}. + */ + private Window parentWindow; + + /** + * The popup window containing completion choices. + */ + private AutoCompleteWithExtraRefreshPopupWindow popupWindow; + + /** + * The preferred size of the completion choices window. This field exists + * because the user will likely set the preferred size of the window + * before it is actually created. + */ + private Dimension preferredChoicesWindowSize; + + /** + * The preferred size of the optional description window. This field + * only exists because the user may (and usually will) set the size of + * the description window before it exists (it must be parented to a + * Window). + */ + private Dimension preferredDescWindowSize; + + /** + * Manages any parameterized completions that are inserted. + */ + private ParameterizedCompletionContext pcc; + + /** + * Provides the completion options relevant to the current caret position. + */ + private CompletionProvider provider; + + /** + * The renderer to use for the completion choices. If this is + * null, then a default renderer is used. + */ + private ListCellRenderer renderer; + + /** + * The handler to use when an external URL is clicked in the help + * documentation. + */ + private ExternalURLHandler externalURLHandler; + + /** + * An optional redirector that converts URL's to some other location before + * being handed over to externalURLHandler. + */ + private static LinkRedirector linkRedirector; + + /** + * Whether the description window should be displayed along with the + * completion choice window. + */ + private boolean showDescWindow; + + /** + * Whether auto-complete is enabled. + */ + private boolean autoCompleteEnabled; + + /** + * Whether the auto-activation of auto-complete (after a delay, after the + * user types an appropriate character) is enabled. + */ + private boolean autoActivationEnabled; + + /** + * Whether or not, when there is only a single auto-complete option + * that matches the text at the current text position, that text should + * be auto-inserted, instead of the completion window displaying. + */ + private boolean autoCompleteSingleChoices; + + /** + * Whether parameter assistance is enabled. + */ + private boolean parameterAssistanceEnabled; + + /** + * A renderer used for {@link Completion}s in the optional parameter + * choices popup window (displayed when a {@link ParameterizedCompletion} + * is code-completed). If this isn't set, a default renderer is used. + */ + private ListCellRenderer paramChoicesRenderer; + + /** + * The keystroke that triggers the completion window. + */ + private KeyStroke trigger; + + /** + * The previous key in the text component's InputMap for the + * trigger key. + */ + private Object oldTriggerKey; + + /** + * The action previously assigned to {@link #trigger}, so we can reset it + * if the user disables auto-completion. + */ + private Action oldTriggerAction; + + /** + * The previous key in the text component's InputMap for the + * parameter completion trigger key. + */ + private Object oldParenKey; + + /** + * The action previously assigned to the parameter completion key, so we + * can reset it when we uninstall. + */ + private Action oldParenAction; + + /** + * Listens for events in the parent window that affect the visibility of + * the popup windows. + */ + private ParentWindowListener parentWindowListener; + + /** + * Listens for events from the text component that affect the visibility + * of the popup windows. + */ + private TextComponentListener textComponentListener; + + /** + * Listens for events in the text component that cause the popup windows + * to automatically activate. + */ + private AutoActivationListener autoActivationListener; + + /** + * Listens for LAF changes so the auto-complete windows automatically + * update themselves accordingly. + */ + private LookAndFeelChangeListener lafListener; + + /** + * The key used in the input map for the AutoComplete action. + */ + private static final String PARAM_TRIGGER_KEY = "AutoComplete"; + + /** + * Key used in the input map for the parameter completion action. + */ + private static final String PARAM_COMPLETE_KEY = "AutoCompletion.FunctionStart"; + + /** + * Stores how to render auto-completion-specific highlights in text + * components. + */ + private static final AutoCompletionStyleContext STYLE_CONTEXT = + new AutoCompletionStyleContext(); + + /** + * Whether debug messages should be printed to stdout as AutoCompletion + * runs. + */ + private static final boolean DEBUG = initDebug(); + + Window getParentWindow(){ + return parentWindow; + } + + ListCellRenderer getCellRender(){ + return renderer; + } + + Dimension getPreferredChoicesWindowSize(){ + return preferredChoicesWindowSize; + } + + Dimension getPreferredDescWindowSize(){ + return preferredDescWindowSize; + } + /** + * Constructor. + * + * @param provider The completion provider. This cannot be + * null. + */ + public AutoCompletionWithExtraRefresh(CompletionProvider provider) { + super(provider); + setChoicesWindowSize(350, 200); + setDescriptionWindowSize(350, 250); + + setCompletionProvider(provider); + setTriggerKey(getDefaultTriggerKey()); + setAutoCompleteEnabled(true); + setAutoCompleteSingleChoices(true); + setAutoActivationEnabled(false); + setShowDescWindow(false); + parentWindowListener = new ParentWindowListener(); + textComponentListener = new TextComponentListener(); + autoActivationListener = new AutoActivationListener(); + lafListener = new LookAndFeelChangeListener(); + } + + + /** + * Displays the popup window. Hosting applications can call this method + * to programmatically begin an auto-completion operation. + */ + public void doCompletion() { + refreshPopupWindow(); + } + + + /** + * Returns the delay between when the user types a character and when the + * code completion popup should automatically appear (if applicable). + * + * @return The delay, in milliseconds. + * @see #setAutoActivationDelay(int) + */ + public int getAutoActivationDelay() { + return autoActivationListener.timer.getDelay(); + } + + + /** + * Returns whether, if a single auto-complete choice is available, it + * should be automatically inserted, without displaying the popup menu. + * + * @return Whether to auto-complete single choices. + * @see #setAutoCompleteSingleChoices(boolean) + */ + public boolean isAutoCompleteSingleChoices() { + return autoCompleteSingleChoices; + } + + + /** + * Returns the completion provider. + * + * @return The completion provider. + */ + public CompletionProvider getCompletionProvider() { + return provider; + } + + + /** + * Returns whether debug is enabled for AutoCompletion. + * + * @return Whether debug is enabled. + */ + static boolean isDebug() { + return DEBUG; + } + + + /** + * Returns the default auto-complete "trigger key" for this OS. For + * Windows, for example, it is Ctrl+Space. + * + * @return The default auto-complete trigger key. + */ + public static KeyStroke getDefaultTriggerKey() { + // Default to CTRL, even on Mac, since Ctrl+Space activates Spotlight + return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, DEFAULT_MODIFIER); + } + + + /** + * Returns the handler to use when an external URL is clicked in the + * description window. + * + * @return The handler. + * @see #setExternalURLHandler(ExternalURLHandler) + * @see #getLinkRedirector() + */ + public ExternalURLHandler getExternalURLHandler() { + return externalURLHandler; + } + + + int getLineOfCaret() { + Document doc = textComponent.getDocument(); + Element root = doc.getDefaultRootElement(); + return root.getElementIndex(textComponent.getCaretPosition()); + } + + + /** + * Returns the link redirector, if any. + * + * @return The link redirector, or null if none. + * @see #setLinkRedirector(LinkRedirector) + */ + public static LinkRedirector getLinkRedirector() { + return linkRedirector; + } + + + /** + * Returns the default list cell renderer used when a completion provider + * does not supply its own. + * + * @return The default list cell renderer. + * @see #setListCellRenderer(ListCellRenderer) + */ + public ListCellRenderer getListCellRenderer() { + return renderer; + } + + + /** + * Returns the renderer to use for {@link Completion}s in the optional + * parameter choices popup window (displayed when a + * {@link ParameterizedCompletion} is code-completed). If this returns + * null, a default renderer is used. + * + * @return The renderer to use. + * @see #setParamChoicesRenderer(ListCellRenderer) + * @see #isParameterAssistanceEnabled() + */ + public ListCellRenderer getParamChoicesRenderer() { + return paramChoicesRenderer; + } + + + /** + * Returns the text to replace with in the document. This is a + * "last-chance" hook for subclasses to make special modifications to the + * completion text inserted. The default implementation simply returns + * c.getReplacementText(). You usually will not need to modify + * this method. + * + * @param c The completion being inserted. + * @param doc The document being modified. + * @param start The start of the text being replaced. + * @param len The length of the text being replaced. + * @return The text to replace with. + */ + protected String getReplacementText(Completion c, Document doc, int start, + int len) { + return c.getReplacementText(); + } + + + /** + * Returns whether the "description window" should be shown alongside + * the completion window. + * + * @return Whether the description window should be shown. + * @see #setShowDescWindow(boolean) + */ + public boolean isShowDescWindow() { + return showDescWindow; + } + + + /** + * Returns the style context describing how auto-completion related + * highlights in the editor are rendered. + * + * @return The style context. + */ + public static AutoCompletionStyleContext getStyleContext() { + return STYLE_CONTEXT; + } + + + /** + * Returns the text component for which auto-completion is enabled. + * + * @return The text component, or null if this + * {@link AutoCompletion} is not installed on any text component. + * @see #install(JTextComponent) + */ + public JTextComponent getTextComponent() { + return textComponent; + } + + + /** + * Returns the orientation of the text component we're installed to. + * + * @return The orientation of the text component, or null if + * we are not installed on one. + */ + ComponentOrientation getTextComponentOrientation() { + return textComponent == null ? null : + textComponent.getComponentOrientation(); + } + + + /** + * Returns the "trigger key" used for auto-complete. + * + * @return The trigger key. + * @see #setTriggerKey(KeyStroke) + */ + public KeyStroke getTriggerKey() { + return trigger; + } + + + /** + * Hides any child windows being displayed by the auto-completion system. + * + * @return Whether any windows were visible. + */ + public boolean hideChildWindows() { + //return hidePopupWindow() || hideToolTipWindow(); + boolean res = hidePopupWindow(); + res |= hideParameterCompletionPopups(); + return res; + } + + + /** + * Hides and disposes of any parameter completion-related popups. + * + * @return Whether any such windows were visible (and thus hidden). + */ + private boolean hideParameterCompletionPopups() { + if (pcc != null) { + pcc.deactivate(); + pcc = null; + return true; + } + return false; + } + + + /** + * Hides the popup window, if it is visible. + * + * @return Whether the popup window was visible. + */ + protected boolean hidePopupWindow() { + if (popupWindow != null) { + if (popupWindow.isVisible()) { + popupWindow.setVisible(false); + return true; + } + } + return false; + } + + + /** + * Determines whether debug should be enabled for the AutoCompletion + * library. This method checks a system property, but takes care of + * {@link SecurityException}s in case we're in an applet or WebStart. + * + * @return Whether debug should be enabled. + */ + private static boolean initDebug() { + boolean debug = false; + try { + debug = Boolean.getBoolean("AutoCompletion.debug"); + } catch (SecurityException se) { // We're in an applet or WebStart. + debug = false; + } + return debug; + } + + + /** + * Installs this auto-completion on a text component. If this + * {@link AutoCompletion} is already installed on another text component, + * it is uninstalled first. + * + * @param c The text component. + * @see #uninstall() + */ + public void install(JTextComponent c) { + + if (textComponent != null) { + uninstall(); + } + + this.textComponent = c; + installTriggerKey(getTriggerKey()); + + // Install the function completion key, if there is one. + // NOTE: We cannot do this if the start char is ' ' (e.g. just a space + // between the function name and parameters) because it overrides + // RSTA's special space action. It seems KeyStorke.getKeyStroke(' ') + // hoses ctrl+space, shift+space, etc., even though I think it + // shouldn't... + char start = provider.getParameterListStart(); + if (start != 0 && start != ' ') { + InputMap im = c.getInputMap(); + ActionMap am = c.getActionMap(); + KeyStroke ks = KeyStroke.getKeyStroke(start); + oldParenKey = im.get(ks); + im.put(ks, PARAM_COMPLETE_KEY); + oldParenAction = am.get(PARAM_COMPLETE_KEY); + am.put(PARAM_COMPLETE_KEY, + new ParameterizedCompletionStartAction(start)); + } + + textComponentListener.addTo(this.textComponent); + // In case textComponent is already in a window... + textComponentListener.hierarchyChanged(null); + + if (isAutoActivationEnabled()) { + autoActivationListener.addTo(this.textComponent); + } + + UIManager.addPropertyChangeListener(lafListener); + updateUI(); // In case there have been changes since we uninstalled + + } + + + /** + * Installs a "trigger key" action onto the current text component. + * + * @param ks The keystroke that should trigger the action. + */ + private void installTriggerKey(KeyStroke ks) { + InputMap im = textComponent.getInputMap(); + oldTriggerKey = im.get(ks); + im.put(ks, PARAM_TRIGGER_KEY); + ActionMap am = textComponent.getActionMap(); + oldTriggerAction = am.get(PARAM_TRIGGER_KEY); + am.put(PARAM_TRIGGER_KEY, new AutoCompleteAction()); + } + + + /** + * Returns whether auto-activation is enabled (that is, whether the + * completion popup will automatically appear after a delay when the user + * types an appropriate character). Note that this parameter will be + * ignored if auto-completion is disabled. + * + * @return Whether auto-activation is enabled. + * @see #setAutoActivationEnabled(boolean) + * @see #getAutoActivationDelay() + * @see #isAutoCompleteEnabled() + */ + public boolean isAutoActivationEnabled() { + return autoActivationEnabled; + } + + + /** + * Returns whether auto-completion is enabled. + * + * @return Whether auto-completion is enabled. + * @see #setAutoCompleteEnabled(boolean) + */ + public boolean isAutoCompleteEnabled() { + return autoCompleteEnabled; + } + + + /** + * Returns whether parameter assistance is enabled. + * + * @return Whether parameter assistance is enabled. + * @see #setParameterAssistanceEnabled(boolean) + */ + public boolean isParameterAssistanceEnabled() { + return parameterAssistanceEnabled; + } + + + /** + * Returns whether the completion popup window is visible. + * + * @return Whether the completion popup window is visible. + */ + public boolean isPopupVisible() { + return popupWindow != null && popupWindow.isVisible(); + } + + private boolean needSetPopupWindow(int count, int textLen) { + return (count == 1 && (isPopupVisible() || textLen == 0)) + || (count == 1 && !isAutoCompleteSingleChoices()) + || count > 1; + } + + protected abstract AutoCompleteWithExtraRefreshPopupWindow createAutoCompletePopupWindow(); + + /** + * Sets the delay between when the user types a character and when the + * code completion popup should automatically appear (if applicable). + * + * @param ms The delay, in milliseconds. This should be greater than zero. + * @see #getAutoActivationDelay() + */ + public void setAutoActivationDelay(int ms) { + ms = Math.max(0, ms); + autoActivationListener.timer.stop(); + autoActivationListener.timer.setInitialDelay(ms); + } + + + /** + * Toggles whether auto-activation is enabled. Note that auto-activation + * also depends on auto-completion itself being enabled. + * + * @param enabled Whether auto-activation is enabled. + * @see #isAutoActivationEnabled() + * @see #setAutoActivationDelay(int) + */ + public void setAutoActivationEnabled(boolean enabled) { + if (enabled != autoActivationEnabled) { + autoActivationEnabled = enabled; + if (textComponent != null) { + if (autoActivationEnabled) { + autoActivationListener.addTo(textComponent); + } else { + autoActivationListener.removeFrom(textComponent); + } + } + } + } + + + /** + * Sets whether auto-completion is enabled. + * + * @param enabled Whether auto-completion is enabled. + * @see #isAutoCompleteEnabled() + */ + public void setAutoCompleteEnabled(boolean enabled) { + if (enabled != autoCompleteEnabled) { + autoCompleteEnabled = enabled; + hidePopupWindow(); + } + } + + + /** + * Sets whether, if a single auto-complete choice is available, it should + * be automatically inserted, without displaying the popup menu. + * + * @param autoComplete Whether to auto-complete single choices. + * @see #isAutoCompleteSingleChoices() + */ + public void setAutoCompleteSingleChoices(boolean autoComplete) { + autoCompleteSingleChoices = autoComplete; + } + + + /** + * Sets the completion provider being used. + * + * @param provider The new completion provider. This cannot be + * null. + * @throws IllegalArgumentException If provider is + * null. + */ + public void setCompletionProvider(CompletionProvider provider) { + if (provider == null) { + throw new IllegalArgumentException("provider cannot be null"); + } + this.provider = provider; + hidePopupWindow(); // In case new choices should be displayed. + } + + + /** + * Sets the size of the completion choices window. + * + * @param w The new width. + * @param h The new height. + * @see #setDescriptionWindowSize(int, int) + */ + public void setChoicesWindowSize(int w, int h) { + preferredChoicesWindowSize = new Dimension(w, h); + if (popupWindow != null) { + popupWindow.setSize(preferredChoicesWindowSize); + } + } + + + /** + * Sets the size of the description window. + * + * @param w The new width. + * @param h The new height. + * @see #setChoicesWindowSize(int, int) + */ + public void setDescriptionWindowSize(int w, int h) { + preferredDescWindowSize = new Dimension(w, h); + if (popupWindow != null) { + popupWindow.setDescriptionWindowSize(preferredDescWindowSize); + } + } + + + /** + * Sets the handler to use when an external URL is clicked in the + * description window. This handler can perform some action, such as + * open the URL in a web browser. The default implementation will open + * the URL in a browser, but only if running in Java 6. If you want + * browser support for Java 5 and below, or otherwise want to respond to + * hyperlink clicks, you will have to install your own handler to do so. + * + * @param handler The new handler. + * @see #getExternalURLHandler() + */ + public void setExternalURLHandler(ExternalURLHandler handler) { + this.externalURLHandler = handler; + } + + + /** + * Sets the redirector for external URL's found in code completion + * documentation. When a non-local link in completion popups is clicked, + * this redirector is given the chance to modify the URL fetched and + * displayed. + * + * @param redirector The link redirector, or null for + * none. + * @see #getLinkRedirector() + */ + public static void setLinkRedirector(LinkRedirector redirector) { + linkRedirector = redirector; + } + + + /** + * Sets the default list cell renderer to use when a completion provider + * does not supply its own. + * + * @param renderer The renderer to use. If this is null, + * a default renderer is used. + * @see #getListCellRenderer() + */ + public void setListCellRenderer(ListCellRenderer renderer) { + this.renderer = renderer; + if (popupWindow != null) { + popupWindow.setListCellRenderer(renderer); + hidePopupWindow(); + } + } + + + /** + * Sets the renderer to use for {@link Completion}s in the optional + * parameter choices popup window (displayed when a + * {@link ParameterizedCompletion} is code-completed). If this isn't set, + * a default renderer is used. + * + * @param r The renderer to use. + * @see #getParamChoicesRenderer() + * @see #setParameterAssistanceEnabled(boolean) + */ + public void setParamChoicesRenderer(ListCellRenderer r) { + paramChoicesRenderer = r; + } + + + /** + * Sets whether parameter assistance is enabled. If parameter assistance + * is enabled, and a "parameterized" completion (such as a function or + * method) is inserted, the user will get "assistance" in inserting the + * parameters in the form of a popup window with documentation and easy + * tabbing through the arguments (as seen in Eclipse and NetBeans). + * + * @param enabled Whether parameter assistance should be enabled. + * @see #isParameterAssistanceEnabled() + */ + public void setParameterAssistanceEnabled(boolean enabled) { + parameterAssistanceEnabled = enabled; + } + + + /** + * Sets whether the "description window" should be shown beside the + * completion window. + * + * @param show Whether to show the description window. + * @see #isShowDescWindow() + */ + public void setShowDescWindow(boolean show) { + hidePopupWindow(); // Needed to force it to take effect + showDescWindow = show; + } + + + /** + * Sets the keystroke that should be used to trigger the auto-complete + * popup window. + * + * @param ks The keystroke. + * @throws IllegalArgumentException If ks is null. + * @see #getTriggerKey() + */ + public void setTriggerKey(KeyStroke ks) { + if (ks == null) { + throw new IllegalArgumentException("trigger key cannot be null"); + } + if (!ks.equals(trigger)) { + if (textComponent != null) { + // Put old trigger action back. + uninstallTriggerKey(); + // Grab current action for new trigger and replace it. + installTriggerKey(ks); + } + trigger = ks; + } + } + + + /** + * Uninstalls this auto-completion from its text component. If it is not + * installed on any text component, nothing happens. + * + * @see #install(JTextComponent) + */ + public void uninstall() { + + if (textComponent != null) { + + hidePopupWindow(); // Unregisters listeners, actions, etc. + + uninstallTriggerKey(); + + // Uninstall the function completion key. + char start = provider.getParameterListStart(); + if (start != 0) { + KeyStroke ks = KeyStroke.getKeyStroke(start); + InputMap im = textComponent.getInputMap(); + im.put(ks, oldParenKey); + ActionMap am = textComponent.getActionMap(); + am.put(PARAM_COMPLETE_KEY, oldParenAction); + } + + textComponentListener.removeFrom(textComponent); + if (parentWindow != null) { + parentWindowListener.removeFrom(parentWindow); + } + + if (isAutoActivationEnabled()) { + autoActivationListener.removeFrom(textComponent); + } + + UIManager.removePropertyChangeListener(lafListener); + + textComponent = null; + popupWindow = null; + + } + + } + + + /** + * Replaces the "trigger key" action with the one that was there + * before auto-completion was installed. + */ + private void uninstallTriggerKey() { + InputMap im = textComponent.getInputMap(); + im.put(trigger, oldTriggerKey); + ActionMap am = textComponent.getActionMap(); + am.put(PARAM_TRIGGER_KEY, oldTriggerAction); + } + + + /** + * Updates the LookAndFeel of the popup window. Applications can call + * this method as appropriate if they support changing the LookAndFeel + * at runtime. + */ + private void updateUI() { + if (popupWindow != null) { + popupWindow.updateUI(); + } + if (pcc != null) { + pcc.updateUI(); + } + // Will practically always be a JComponent (a JLabel) + if (paramChoicesRenderer instanceof JComponent) { + ((JComponent) paramChoicesRenderer).updateUI(); + } + } + + + /** + * Listens for events in the text component to auto-activate the code + * completion popup. + */ + private class AutoActivationListener extends FocusAdapter + implements DocumentListener, CaretListener, ActionListener { + + private Timer timer; + private boolean justInserted; + + public AutoActivationListener() { + timer = new Timer(200, this); + timer.setRepeats(false); + } + + public void actionPerformed(ActionEvent e) { + doCompletion(); + } + + public void addTo(JTextComponent tc) { + tc.addFocusListener(this); + tc.getDocument().addDocumentListener(this); + tc.addCaretListener(this); + } + + public void caretUpdate(CaretEvent e) { + if (justInserted) { + justInserted = false; + } else { + timer.stop(); + } + } + + public void changedUpdate(DocumentEvent e) { + // Ignore + } + + @Override + public void focusLost(FocusEvent e) { + timer.stop(); + //hideChildWindows(); Other listener will do this + } + + public void insertUpdate(DocumentEvent e) { + justInserted = false; + if (isAutoCompleteEnabled() && isAutoActivationEnabled() && + e.getLength() == 1) { + if (provider.isAutoActivateOkay(textComponent)) { + timer.restart(); + justInserted = true; + } else { + timer.stop(); + } + } else { + timer.stop(); + } + } + + public void removeFrom(JTextComponent tc) { + tc.removeFocusListener(this); + tc.getDocument().removeDocumentListener(this); + tc.removeCaretListener(this); + timer.stop(); + justInserted = false; + } + + public void removeUpdate(DocumentEvent e) { + timer.stop(); + } + + } + + + /** + * The Action that displays the popup window if + * auto-completion is enabled. + */ + private class AutoCompleteAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isAutoCompleteEnabled()) { + refreshPopupWindow(); + } else if (oldTriggerAction != null) { + oldTriggerAction.actionPerformed(e); + } + } + + } + + + /** + * Listens for LookAndFeel changes and updates the various popup windows + * involved in auto-completion accordingly. + */ + private class LookAndFeelChangeListener implements PropertyChangeListener { + + public void propertyChange(PropertyChangeEvent e) { + String name = e.getPropertyName(); + if ("lookAndFeel".equals(name)) { + updateUI(); + } + } + + } + + + /** + * Action that starts a parameterized completion, e.g. after '(' is + * typed. + */ + private class ParameterizedCompletionStartAction extends AbstractAction { + + private String start; + + public ParameterizedCompletionStartAction(char ch) { + this.start = Character.toString(ch); + } + + public void actionPerformed(ActionEvent e) { + + // Prevents keystrokes from messing up + boolean wasVisible = hidePopupWindow(); + + // Only proceed if they were selecting a completion + if (!wasVisible || !isParameterAssistanceEnabled()) { + textComponent.replaceSelection(start); + return; + } + + Completion c = popupWindow.getSelection(); + if (c instanceof ParameterizedCompletion) { // Should always be true + // Fixes capitalization of the entered text. + insertCompletion(c, true); + } + + } + + } + + + /** + * Listens for events in the parent window of the text component with + * auto-completion enabled. + */ + private class ParentWindowListener extends ComponentAdapter + implements WindowFocusListener { + + public void addTo(Window w) { + w.addComponentListener(this); + w.addWindowFocusListener(this); + } + + @Override + public void componentHidden(ComponentEvent e) { + hideChildWindows(); + } + + @Override + public void componentMoved(ComponentEvent e) { + hideChildWindows(); + } + + @Override + public void componentResized(ComponentEvent e) { + hideChildWindows(); + } + + public void removeFrom(Window w) { + w.removeComponentListener(this); + w.removeWindowFocusListener(this); + } + + public void windowGainedFocus(WindowEvent e) { + } + + public void windowLostFocus(WindowEvent e) { + hideChildWindows(); + } + + } + + + /** + * Listens for events from the text component we're installed on. + */ + private class TextComponentListener extends FocusAdapter + implements HierarchyListener { + + void addTo(JTextComponent tc) { + tc.addFocusListener(this); + tc.addHierarchyListener(this); + } + + /** + * Hide the auto-completion windows when the text component loses + * focus. + */ + @Override + public void focusLost(FocusEvent e) { + hideChildWindows(); + } + + /** + * Called when the component hierarchy for our text component changes. + * When the text component is added to a new {@link Window}, this + * method registers listeners on that Window. + * + * @param e The event. + */ + public void hierarchyChanged(HierarchyEvent e) { + + // NOTE: e many be null as we call this method at other times. + //System.out.println("Hierarchy changed! " + e); + + Window oldParentWindow = parentWindow; + parentWindow = SwingUtilities.getWindowAncestor(textComponent); + if (parentWindow != oldParentWindow) { + if (oldParentWindow != null) { + parentWindowListener.removeFrom(oldParentWindow); + } + if (parentWindow != null) { + parentWindowListener.addTo(parentWindow); + } + } + + } + + public void removeFrom(JTextComponent tc) { + tc.removeFocusListener(this); + tc.removeHierarchyListener(this); + } + + } + + public void installExtraRefreshComponent(AutoCompleteExtraRefreshComponent jComp) { + area = jComp; + } + + + /** + * Displays a "tool tip" detailing the inputs to the function just entered. + * + * @param pc The completion. + * @param typedParamListStartChar Whether the parameterized completion list + * starting character was typed. + */ + protected void startParameterizedCompletionAssistance( + ParameterizedCompletion pc, boolean typedParamListStartChar) { + + // Get rid of the previous tool tip window, if there is one. + hideParameterCompletionPopups(); + + // Don't bother with a tool tip if there are no parameters, but if + // they typed e.g. the opening '(', make them overtype the ')'. + if (pc.getParamCount() == 0 && !(pc instanceof TemplateCompletion)) { + CompletionProvider p = pc.getProvider(); + char end = p.getParameterListEnd(); // Might be '\0' + String text = end == '\0' ? "" : Character.toString(end); + if (typedParamListStartChar) { + String template = "${}" + text + "${cursor}"; + textComponent.replaceSelection(Character.toString(p.getParameterListStart())); + TemplateCompletion tc = new TemplateCompletion(p, null, null, template); + pc = tc; + } else { + text = p.getParameterListStart() + text; + textComponent.replaceSelection(text); + return; + } + } + + pcc = new ParameterizedCompletionContext(parentWindow, this, pc); + pcc.activate(); + + } + + protected int refreshPopupWindow() { + // A return value of null => don't suggest completions + String text = provider.getAlreadyEnteredText(textComponent); + if (text == null && !isPopupVisible()) { + return getLineOfCaret(); + } + // If the popup is currently visible, and they type a space (or any + // character that resets the completion list to "all completions"), + // the popup window should be hidden instead of being reset to show + // everything. + int textLen = text == null ? 0 : text.length(); + if (textLen == 0 && isPopupVisible()) { + hidePopupWindow(); + return getLineOfCaret(); + } + final List completions = provider.getCompletions(textComponent); + int count = completions.size(); + if (needSetPopupWindow(count, textLen)) { + if (popupWindow == null) { + popupWindow = createAutoCompletePopupWindow(); + } + popupWindow.installComp(area); + popupWindow.setCompletions(completions); + if (!popupWindow.isVisible()) { + Rectangle r = null; + try { + r = textComponent.modelToView(textComponent.getCaretPosition()); + } catch (BadLocationException ble) { + return -1; + } + Point p = new Point(r.x, r.y); + SwingUtilities.convertPointToScreen(p, textComponent); + r.x = p.x; + r.y = p.y; + popupWindow.setLocationRelativeTo(r); + popupWindow.setVisible(true); + } + } else if (count == 1) { // !isPopupVisible && autoCompleteSingleChoices + SwingUtilities.invokeLater(new Runnable() { + public void run() { + insertCompletion(completions.get(0)); + } + }); + } else { + hidePopupWindow(); + } + return getLineOfCaret(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaAutoCompletePopupWindow.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaAutoCompletePopupWindow.java index 0e1c7c6ac..daed7cd4c 100644 --- a/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaAutoCompletePopupWindow.java +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaAutoCompletePopupWindow.java @@ -9,41 +9,7 @@ */ package com.fr.design.gui.autocomplete; -import com.fr.design.formula.FormulaPane; -import com.fr.design.gui.syntax.ui.rsyntaxtextarea.PopupWindowDecorator; -import com.fr.log.FineLoggerFactory; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.InputMap; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JWindow; -import javax.swing.KeyStroke; -import javax.swing.ListCellRenderer; -import javax.swing.SwingUtilities; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.plaf.ListUI; -import javax.swing.text.Caret; -import javax.swing.text.JTextComponent; -import java.awt.BorderLayout; -import java.awt.ComponentOrientation; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.Toolkit; import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.util.List; - /** * The actual popup window of choices. When visible, this window intercepts @@ -55,949 +21,11 @@ import java.util.List; * @author Robert Futrell * @version 1.0 */ -class FormulaAutoCompletePopupWindow extends JWindow implements CaretListener, - ListSelectionListener, MouseListener { - - private final static int DIS = 5; - /** - * The parent AutoCompletion instance. - */ - private FormulaPaneAutoCompletion ac; - - /** - * The list of completion choices. - */ - private JList list; - - /** - * The contents of {@link #list()}. - */ - private CompletionListModel model; - - /** - * A hack to work around the fact that we clear our completion model (and - * our selection) when hiding the completion window. This allows us to - * still know what the user selected after the popup is hidden. - */ - private Completion lastSelection; - - /** - * Optional popup window containing a description of the currently - * selected completion. - */ - private AutoCompleteDescWindow descWindow; - - /** - * The preferred size of the optional description window. This field - * only exists because the user may (and usually will) set the size of - * the description window before it exists (it must be parented to a - * Window). - */ - private Dimension preferredDescWindowSize; - - private FormulaPane.VariableTreeAndDescriptionArea component; - - /** - * Whether the completion window and the optional description window - * should be displayed above the current caret position (as opposed to - * underneath it, which is preferred unless there is not enough space). - */ - private boolean aboveCaret; - - private int lastLine; - - private KeyActionPair escapeKap; - private KeyActionPair upKap; - private KeyActionPair downKap; - private KeyActionPair leftKap; - private KeyActionPair rightKap; - private KeyActionPair enterKap; - private KeyActionPair tabKap; - private KeyActionPair homeKap; - private KeyActionPair endKap; - private KeyActionPair pageUpKap; - private KeyActionPair pageDownKap; - private KeyActionPair ctrlCKap; - - private KeyActionPair oldEscape, oldUp, oldDown, oldLeft, oldRight, - oldEnter, oldTab, oldHome, oldEnd, oldPageUp, oldPageDown, - oldCtrlC; - - /** - * The space between the caret and the completion popup. - */ - private static final int VERTICAL_SPACE = 1; - - /** - * The class name of the Substance List UI. - */ - private static final String SUBSTANCE_LIST_UI = - "org.pushingpixels.substance.internal.ui.SubstanceListUI"; +class FormulaAutoCompletePopupWindow extends AutoCompleteWithExtraRefreshPopupWindow { - /** - * Constructor. - * - * @param parent The parent window (hosting the text component). - * @param ac The auto-completion instance. - */ public FormulaAutoCompletePopupWindow(Window parent, final FormulaPaneAutoCompletion ac) { - - super(parent); - ComponentOrientation o = ac.getTextComponentOrientation(); - - this.ac = ac; - model = new CompletionListModel(); - list = new PopupList(model); - - list.setCellRenderer(new DelegatingCellRenderer()); - list.addListSelectionListener(this); - list.addMouseListener(this); - - JPanel contentPane = new JPanel(new BorderLayout()); - JScrollPane sp = new JScrollPane(list, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); - - // In 1.4, JScrollPane.setCorner() has a bug where it won't accept - // JScrollPane.LOWER_TRAILING_CORNER, even though that constant is - // defined. So we have to put the logic added in 1.5 to handle it - // here. - JPanel corner = new SizeGrip(); - //sp.setCorner(JScrollPane.LOWER_TRAILING_CORNER, corner); - boolean isLeftToRight = o.isLeftToRight(); - String str = isLeftToRight ? JScrollPane.LOWER_RIGHT_CORNER : - JScrollPane.LOWER_LEFT_CORNER; - sp.setCorner(str, corner); - - contentPane.add(sp); - setContentPane(contentPane); - applyComponentOrientation(o); - - // Give apps a chance to decorate us with drop shadows, etc. - if (Util.getShouldAllowDecoratingMainAutoCompleteWindows()) { - PopupWindowDecorator decorator = PopupWindowDecorator.get(); - if (decorator != null) { - decorator.decorate(this); - } - } - - pack(); - - setFocusableWindowState(false); - - lastLine = -1; - - } - - - public void caretUpdate(CaretEvent e) { - if (isVisible()) { // Should always be true - int line = ac.getLineOfCaret(); - if (line != lastLine) { - lastLine = -1; - setVisible(false); - } else { - doAutocomplete(); - } - } else if (AutoCompletion.isDebug()) { - Thread.dumpStack(); - } - } - - - /** - * Creates the description window. - * - * @return The description window. - */ - private AutoCompleteDescWindow createDescriptionWindow() { - AutoCompleteDescWindow dw = new AutoCompleteDescWindow(this, ac); - dw.applyComponentOrientation(ac.getTextComponentOrientation()); - Dimension size = preferredDescWindowSize; - if (size == null) { - size = getSize(); - } - dw.setSize(size); - return dw; - } - - - /** - * Creates the mappings from keys to Actions we'll be putting into the - * text component's ActionMap and InputMap. - */ - private void createKeyActionPairs() { - - // Actions we'll install. - EnterAction enterAction = new EnterAction(); - escapeKap = new KeyActionPair("Escape", new EscapeAction()); - upKap = new KeyActionPair("Up", new UpAction()); - downKap = new KeyActionPair("Down", new DownAction()); - leftKap = new KeyActionPair("Left", new LeftAction()); - rightKap = new KeyActionPair("Right", new RightAction()); - enterKap = new KeyActionPair("Enter", enterAction); - tabKap = new KeyActionPair("Tab", enterAction); - homeKap = new KeyActionPair("Home", new HomeAction()); - endKap = new KeyActionPair("End", new EndAction()); - pageUpKap = new KeyActionPair("PageUp", new PageUpAction()); - pageDownKap = new KeyActionPair("PageDown", new PageDownAction()); - ctrlCKap = new KeyActionPair("CtrlC", new CopyAction()); - - // Buffers for the actions we replace. - oldEscape = new KeyActionPair(); - oldUp = new KeyActionPair(); - oldDown = new KeyActionPair(); - oldLeft = new KeyActionPair(); - oldRight = new KeyActionPair(); - oldEnter = new KeyActionPair(); - oldTab = new KeyActionPair(); - oldHome = new KeyActionPair(); - oldEnd = new KeyActionPair(); - oldPageUp = new KeyActionPair(); - oldPageDown = new KeyActionPair(); - oldCtrlC = new KeyActionPair(); - - } - - - protected void doAutocomplete() { - lastLine = ac.refreshPopupWindow(); - } - - - /** - * Returns the copy keystroke to use for this platform. - * - * @return The copy keystroke. - */ - private static final KeyStroke getCopyKeyStroke() { - int key = KeyEvent.VK_C; - int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - return KeyStroke.getKeyStroke(key, mask); - } - - - /** - * Returns the default list cell renderer used when a completion provider - * does not supply its own. - * - * @return The default list cell renderer. - * @see #setListCellRenderer(ListCellRenderer) - */ - public ListCellRenderer getListCellRenderer() { - DelegatingCellRenderer dcr = (DelegatingCellRenderer) list. - getCellRenderer(); - return dcr.getFallbackCellRenderer(); - } - - - /** - * Returns the selected value, or null if nothing is selected. - * - * @return The selected value. - */ - public Completion getSelection() { - return isShowing() ? (Completion) list.getSelectedValue() : lastSelection; - } - - - /** - * Inserts the currently selected completion. - * - * @see #getSelection() - */ - private void insertSelectedCompletion() { - Completion comp = getSelection(); - ac.insertCompletion(comp); - } - - public void installComp(FormulaPane.VariableTreeAndDescriptionArea component) { - this.component = component; - } - - private void refreshInstallComp() { - component.refreshText(getSelection().getReplacementText()); - } - - - /** - * Registers keyboard actions to listen for in the text component and - * intercept. - * - * @see #uninstallKeyBindings() - */ - private void installKeyBindings() { - - if (AutoCompletion.isDebug()) { - FineLoggerFactory.getLogger().debug("PopupWindow: Installing keybindings"); - } - - if (escapeKap == null) { // Lazily create actions. - createKeyActionPairs(); - } - - JTextComponent comp = ac.getTextComponent(); - InputMap im = comp.getInputMap(); - ActionMap am = comp.getActionMap(); - - replaceAction(im, am, KeyEvent.VK_ESCAPE, escapeKap, oldEscape); - if (AutoCompletion.isDebug() && oldEscape.action == escapeKap.action) { - Thread.dumpStack(); - } - replaceAction(im, am, KeyEvent.VK_UP, upKap, oldUp); - replaceAction(im, am, KeyEvent.VK_LEFT, leftKap, oldLeft); - replaceAction(im, am, KeyEvent.VK_DOWN, downKap, oldDown); - replaceAction(im, am, KeyEvent.VK_RIGHT, rightKap, oldRight); - replaceAction(im, am, KeyEvent.VK_ENTER, enterKap, oldEnter); - replaceAction(im, am, KeyEvent.VK_TAB, tabKap, oldTab); - replaceAction(im, am, KeyEvent.VK_HOME, homeKap, oldHome); - replaceAction(im, am, KeyEvent.VK_END, endKap, oldEnd); - replaceAction(im, am, KeyEvent.VK_PAGE_UP, pageUpKap, oldPageUp); - replaceAction(im, am, KeyEvent.VK_PAGE_DOWN, pageDownKap, oldPageDown); - - // Make Ctrl+C copy from description window. This isn't done - // automagically because the desc. window is not focusable, and copying - // from text components can only be done from focused components. - KeyStroke ks = getCopyKeyStroke(); - oldCtrlC.key = im.get(ks); - im.put(ks, ctrlCKap.key); - oldCtrlC.action = am.get(ctrlCKap.key); - am.put(ctrlCKap.key, ctrlCKap.action); - - comp.addCaretListener(this); - - } - - - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2 && e.getButton() == 1) { - insertSelectedCompletion(); - } - } - - - public void mouseEntered(MouseEvent e) { - } - - - public void mouseExited(MouseEvent e) { - } - - - public void mousePressed(MouseEvent e) { - refreshInstallComp(); - } - - - public void mouseReleased(MouseEvent e) { - } - - - /** - * Positions the description window relative to the completion choices - * window. We assume there is room on one side of the other for this - * entire window to fit. - */ - private void positionDescWindow() { - - boolean showDescWindow = descWindow != null && ac.isShowDescWindow(); - if (!showDescWindow) { - return; - } - - // Don't use getLocationOnScreen() as this throws an exception if - // window isn't visible yet, but getLocation() doesn't, and is in - // screen coordinates! - Point p = getLocation(); - Rectangle screenBounds = Util.getScreenBoundsForPoint(p.x, p.y); - //Dimension screenSize = getToolkit().getScreenSize(); - //int totalH = Math.max(getHeight(), descWindow.getHeight()); - - // Try to position to the right first (LTR) - int x; - if (ac.getTextComponentOrientation().isLeftToRight()) { - x = getX() + getWidth() + DIS; - if (x + descWindow.getWidth() > screenBounds.x + screenBounds.width) { // doesn't fit - x = getX() - DIS - descWindow.getWidth(); - } - } else { // RTL - x = getX() - DIS - descWindow.getWidth(); - if (x < screenBounds.x) { // Doesn't fit - x = getX() + getWidth() + DIS; - } - } - - int y = getY(); - if (aboveCaret) { - y = y + getHeight() - descWindow.getHeight(); - } - - if (x != descWindow.getX() || y != descWindow.getY()) { - descWindow.setLocation(x, y); - } - - } - - - /** - * "Puts back" the original key/Action pair for a keystroke. This is used - * when this popup is hidden. - * - * @param im The input map. - * @param am The action map. - * @param key The keystroke whose key/Action pair to change. - * @param kap The (original) key/Action pair. - * @see #replaceAction(InputMap, ActionMap, int, KeyActionPair, KeyActionPair) - */ - private void putBackAction(InputMap im, ActionMap am, int key, - KeyActionPair kap) { - KeyStroke ks = KeyStroke.getKeyStroke(key, 0); - am.put(im.get(ks), kap.action); // Original action for the "new" key - im.put(ks, kap.key); // Original key for the keystroke. - } - - - /** - * Replaces a key/Action pair in an InputMap and ActionMap with a new - * pair. - * - * @param im The input map. - * @param am The action map. - * @param key The keystroke whose information to replace. - * @param kap The new key/Action pair for key. - * @param old A buffer in which to place the old key/Action pair. - * @see #putBackAction(InputMap, ActionMap, int, KeyActionPair) - */ - private void replaceAction(InputMap im, ActionMap am, int key, - KeyActionPair kap, KeyActionPair old) { - KeyStroke ks = KeyStroke.getKeyStroke(key, 0); - old.key = im.get(ks); - im.put(ks, kap.key); - old.action = am.get(kap.key); - am.put(kap.key, kap.action); - } - - - /** - * Selects the first item in the completion list. - * - * @see #selectLastItem() - */ - private void selectFirstItem() { - if (model.getSize() > 0) { - list.setSelectedIndex(0); - list.ensureIndexIsVisible(0); - } - } - - - /** - * Selects the last item in the completion list. - * - * @see #selectFirstItem() - */ - private void selectLastItem() { - int index = model.getSize() - 1; - if (index > -1) { - list.setSelectedIndex(index); - list.ensureIndexIsVisible(index); - } - } - - - /** - * Selects the next item in the completion list. - * - * @see #selectPreviousItem() - */ - private void selectNextItem() { - int index = list.getSelectedIndex(); - if (index > -1) { - index = (index + 1) % model.getSize(); - list.setSelectedIndex(index); - list.ensureIndexIsVisible(index); - } - } - - - /** - * Selects the completion item one "page down" from the currently selected - * one. - * - * @see #selectPageUpItem() - */ - private void selectPageDownItem() { - int visibleRowCount = list.getVisibleRowCount(); - int i = Math.min(list.getModel().getSize() - 1, - list.getSelectedIndex() + visibleRowCount); - list.setSelectedIndex(i); - list.ensureIndexIsVisible(i); - } - - - /** - * Selects the completion item one "page up" from the currently selected - * one. - * - * @see #selectPageDownItem() - */ - private void selectPageUpItem() { - int visibleRowCount = list.getVisibleRowCount(); - int i = Math.max(0, list.getSelectedIndex() - visibleRowCount); - list.setSelectedIndex(i); - list.ensureIndexIsVisible(i); - } - - - /** - * Selects the previous item in the completion list. - * - * @see #selectNextItem() - */ - private void selectPreviousItem() { - int index = list.getSelectedIndex(); - switch (index) { - case 0: - index = list.getModel().getSize() - 1; - break; - case -1: // Check for an empty list (would be an error) - index = list.getModel().getSize() - 1; - if (index == -1) { - return; - } - break; - default: - index = index - 1; - break; - } - list.setSelectedIndex(index); - list.ensureIndexIsVisible(index); - } - - - /** - * Sets the completions to display in the choices list. The first - * completion is selected. - * - * @param completions The completions to display. - */ - public void setCompletions(List completions) { - model.setContents(completions); - selectFirstItem(); - } - - - /** - * Sets the size of the description window. - * - * @param size The new size. This cannot be null. - */ - public void setDescriptionWindowSize(Dimension size) { - if (descWindow != null) { - descWindow.setSize(size); - } else { - preferredDescWindowSize = size; - } - } - - - /** - * Sets the default list cell renderer to use when a completion provider - * does not supply its own. - * - * @param renderer The renderer to use. If this is null, - * a default renderer is used. - * @see #getListCellRenderer() - */ - public void setListCellRenderer(ListCellRenderer renderer) { - DelegatingCellRenderer dcr = (DelegatingCellRenderer) list. - getCellRenderer(); - dcr.setFallbackCellRenderer(renderer); - } - - - /** - * Sets the location of this window to be "good" relative to the specified - * rectangle. That rectangle should be the location of the text - * component's caret, in screen coordinates. - * - * @param r The text component's caret position, in screen coordinates. - */ - public void setLocationRelativeTo(Rectangle r) { - - // Multi-monitor support - make sure the completion window (and - // description window, if applicable) both fit in the same window in - // a multi-monitor environment. To do this, we decide which monitor - // the rectangle "r" is in, and use that one (just pick top-left corner - // as the defining point). - Rectangle screenBounds = Util.getScreenBoundsForPoint(r.x, r.y); - //Dimension screenSize = getToolkit().getScreenSize(); - - boolean showDescWindow = descWindow != null && ac.isShowDescWindow(); - int totalH = getHeight(); - if (showDescWindow) { - totalH = Math.max(totalH, descWindow.getHeight()); - } - - // Try putting our stuff "below" the caret first. We assume that the - // entire height of our stuff fits on the screen one way or the other. - aboveCaret = false; - int y = r.y + r.height + VERTICAL_SPACE; - if (y + totalH > screenBounds.height) { - y = r.y - VERTICAL_SPACE - getHeight(); - aboveCaret = true; - } - - // Get x-coordinate of completions. Try to align left edge with the - // caret first. - int x = r.x; - if (!ac.getTextComponentOrientation().isLeftToRight()) { - x -= getWidth(); // RTL => align right edge - } - if (x < screenBounds.x) { - x = screenBounds.x; - } else if (x + getWidth() > screenBounds.x + screenBounds.width) { // completions don't fit - x = screenBounds.x + screenBounds.width - getWidth(); - } - - setLocation(x, y); - - // Position the description window, if necessary. - if (showDescWindow) { - positionDescWindow(); - } - - } - - - /** - * Toggles the visibility of this popup window. - * - * @param visible Whether this window should be visible. - */ - @Override - public void setVisible(boolean visible) { - - if (visible != isVisible()) { - - if (visible) { - installKeyBindings(); - lastLine = ac.getLineOfCaret(); - selectFirstItem(); - if (descWindow == null && ac.isShowDescWindow()) { - descWindow = createDescriptionWindow(); - positionDescWindow(); - } - // descWindow needs a kick-start the first time it's displayed. - // Also, the newly-selected item in the choices list is - // probably different from the previous one anyway. - if (descWindow != null) { - Completion c = (Completion) list.getSelectedValue(); - if (c != null) { - descWindow.setDescriptionFor(c); - } - } - } else { - uninstallKeyBindings(); - } - - super.setVisible(visible); - - // Some languages, such as Java, can use quite a lot of memory - // when displaying hundreds of completion choices. We pro-actively - // clear our list model here to make them available for GC. - // Otherwise, they stick around, and consider the following: a - // user starts code-completion for Java 5 SDK classes, then hides - // the dialog, then changes the "class path" to use a Java 6 SDK - // instead. On pressing Ctrl+space, a new array of Completions is - // created. If this window holds on to the previous Completions, - // you're getting roughly 2x the necessary Completions in memory - // until the Completions are actually passed to this window. - if (!visible) { // Do after super.setVisible(false) - lastSelection = (Completion) list.getSelectedValue(); - model.clear(); - } - - // Must set descWindow's visibility one way or the other each time, - // because of the way child JWindows' visibility is handled - in - // some ways it's dependent on the parent, in other ways it's not. - if (descWindow != null) { - descWindow.setVisible(visible && ac.isShowDescWindow()); - } - - } - - } - - - /** - * Stops intercepting certain keystrokes from the text component. - * - * @see #installKeyBindings() - */ - private void uninstallKeyBindings() { - - if (AutoCompletion.isDebug()) { - FineLoggerFactory.getLogger().debug("PopupWindow: Removing keybindings"); - } - - JTextComponent comp = ac.getTextComponent(); - InputMap im = comp.getInputMap(); - ActionMap am = comp.getActionMap(); - - putBackAction(im, am, KeyEvent.VK_ESCAPE, oldEscape); - putBackAction(im, am, KeyEvent.VK_UP, oldUp); - putBackAction(im, am, KeyEvent.VK_DOWN, oldDown); - putBackAction(im, am, KeyEvent.VK_LEFT, oldLeft); - putBackAction(im, am, KeyEvent.VK_RIGHT, oldRight); - putBackAction(im, am, KeyEvent.VK_ENTER, oldEnter); - putBackAction(im, am, KeyEvent.VK_TAB, oldTab); - putBackAction(im, am, KeyEvent.VK_HOME, oldHome); - putBackAction(im, am, KeyEvent.VK_END, oldEnd); - putBackAction(im, am, KeyEvent.VK_PAGE_UP, oldPageUp); - putBackAction(im, am, KeyEvent.VK_PAGE_DOWN, oldPageDown); - - // Ctrl+C - KeyStroke ks = getCopyKeyStroke(); - am.put(im.get(ks), oldCtrlC.action); // Original action - im.put(ks, oldCtrlC.key); // Original key - - comp.removeCaretListener(this); - - } - - - /** - * Updates the LookAndFeel of this window and the description - * window. - */ - public void updateUI() { - SwingUtilities.updateComponentTreeUI(this); - if (descWindow != null) { - descWindow.updateUI(); - } - } - - - /** - * Called when a new item is selected in the popup list. - * - * @param e The event. - */ - public void valueChanged(ListSelectionEvent e) { - if (!e.getValueIsAdjusting()) { - Object value = list.getSelectedValue(); - if (value != null && descWindow != null) { - descWindow.setDescriptionFor((Completion) value); - positionDescWindow(); - } - } - } - - - class CopyAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - boolean doNormalCopy = false; - if (descWindow != null && descWindow.isVisible()) { - doNormalCopy = !descWindow.copy(); - } - if (doNormalCopy) { - ac.getTextComponent().copy(); - } - } - - } - - - class DownAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - selectNextItem(); - refreshInstallComp(); - } - } - - } - - - class EndAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - selectLastItem(); - } - } - - } - - - class EnterAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - insertSelectedCompletion(); - refreshInstallComp(); - } - } - + super(parent,ac); } - - class EscapeAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - setVisible(false); - } - } - - } - - - class HomeAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - selectFirstItem(); - } - } - - } - - - /** - * A mapping from a key (an Object) to an Action. - */ - private static class KeyActionPair { - - public Object key; - public Action action; - - public KeyActionPair() { - } - - public KeyActionPair(Object key, Action a) { - this.key = key; - this.action = a; - } - - } - - - class LeftAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - JTextComponent comp = ac.getTextComponent(); - Caret c = comp.getCaret(); - int dot = c.getDot(); - if (dot > 0) { - c.setDot(--dot); - // Ensure moving left hasn't moved us up a line, thus - // hiding the popup window. - if (comp.isVisible()) { - if (lastLine != -1) { - doAutocomplete(); - } - } - } - } - } - - } - - - class PageDownAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - selectPageDownItem(); - } - } - - } - - - class PageUpAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - selectPageUpItem(); - } - } - - } - - - /** - * The actual list of completion choices in this popup window. - */ - private class PopupList extends JList { - - public PopupList(CompletionListModel model) { - super(model); - } - - @Override - public void setUI(ListUI ui) { - if (Util.getUseSubstanceRenderers() && - SUBSTANCE_LIST_UI.equals(ui.getClass().getName())) { - // Substance requires its special ListUI be installed for - // its renderers to actually render (!), but long completion - // lists (e.g. PHPCompletionProvider in RSTALanguageSupport) - // will simply populate too slowly on initial display (when - // calculating preferred size of all items), so in this case - // we give a prototype cell value. - CompletionProvider p = ac.getCompletionProvider(); - BasicCompletion bc = new BasicCompletion(p, "Hello world"); - setPrototypeCellValue(bc); - } else { - // Our custom UI that is faster for long HTML completion lists. - ui = new FastListUI(); - setPrototypeCellValue(null); - } - super.setUI(ui); - } - - } - - - class RightAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - JTextComponent comp = ac.getTextComponent(); - Caret c = comp.getCaret(); - int dot = c.getDot(); - if (dot < comp.getDocument().getLength()) { - c.setDot(++dot); - // Ensure moving right hasn't moved us up a line, thus - // hiding the popup window. - if (comp.isVisible()) { - if (lastLine != -1) { - doAutocomplete(); - } - } - } - } - } - - } - - - class UpAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isVisible()) { - selectPreviousItem(); - refreshInstallComp(); - } - } - - } - - } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaPaneAutoCompletion.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaPaneAutoCompletion.java index 8168c767d..cd37fd9bc 100644 --- a/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaPaneAutoCompletion.java +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaPaneAutoCompletion.java @@ -2,226 +2,18 @@ package com.fr.design.gui.autocomplete; import com.fr.design.formula.FormulaPane; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.InputMap; -import javax.swing.JComponent; import javax.swing.KeyStroke; import javax.swing.ListCellRenderer; -import javax.swing.SwingUtilities; -import javax.swing.Timer; -import javax.swing.UIManager; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.BadLocationException; import javax.swing.text.Caret; -import javax.swing.text.Document; -import javax.swing.text.Element; import javax.swing.text.JTextComponent; -import java.awt.ComponentOrientation; -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.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.FocusAdapter; -import java.awt.event.FocusEvent; -import java.awt.event.HierarchyEvent; -import java.awt.event.HierarchyListener; -import java.awt.event.KeyEvent; -import java.awt.event.WindowEvent; -import java.awt.event.WindowFocusListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.List; - -import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; /** * @author Hoky * @date 2021/11/2 * @description 重写一个支持刷新公式树组件的AutoCompletion */ -public class FormulaPaneAutoCompletion extends AutoCompletion { - private FormulaPane.VariableTreeAndDescriptionArea area; - - /** - * The text component we're providing completion for. - */ - private JTextComponent textComponent; - - /** - * The parent window of {@link #textComponent}. - */ - private Window parentWindow; - - /** - * The popup window containing completion choices. - */ - private FormulaAutoCompletePopupWindow popupWindow; - - /** - * The preferred size of the completion choices window. This field exists - * because the user will likely set the preferred size of the window - * before it is actually created. - */ - private Dimension preferredChoicesWindowSize; - - /** - * The preferred size of the optional description window. This field - * only exists because the user may (and usually will) set the size of - * the description window before it exists (it must be parented to a - * Window). - */ - private Dimension preferredDescWindowSize; - - /** - * Manages any parameterized completions that are inserted. - */ - private ParameterizedCompletionContext pcc; - - /** - * Provides the completion options relevant to the current caret position. - */ - private CompletionProvider provider; - - /** - * The renderer to use for the completion choices. If this is - * null, then a default renderer is used. - */ - private ListCellRenderer renderer; - - /** - * The handler to use when an external URL is clicked in the help - * documentation. - */ - private ExternalURLHandler externalURLHandler; - - /** - * An optional redirector that converts URL's to some other location before - * being handed over to externalURLHandler. - */ - private static LinkRedirector linkRedirector; - - /** - * Whether the description window should be displayed along with the - * completion choice window. - */ - private boolean showDescWindow; - - /** - * Whether auto-complete is enabled. - */ - private boolean autoCompleteEnabled; - - /** - * Whether the auto-activation of auto-complete (after a delay, after the - * user types an appropriate character) is enabled. - */ - private boolean autoActivationEnabled; - - /** - * Whether or not, when there is only a single auto-complete option - * that matches the text at the current text position, that text should - * be auto-inserted, instead of the completion window displaying. - */ - private boolean autoCompleteSingleChoices; - - /** - * Whether parameter assistance is enabled. - */ - private boolean parameterAssistanceEnabled; - - /** - * A renderer used for {@link Completion}s in the optional parameter - * choices popup window (displayed when a {@link ParameterizedCompletion} - * is code-completed). If this isn't set, a default renderer is used. - */ - private ListCellRenderer paramChoicesRenderer; - - /** - * The keystroke that triggers the completion window. - */ - private KeyStroke trigger; - - /** - * The previous key in the text component's InputMap for the - * trigger key. - */ - private Object oldTriggerKey; - - /** - * The action previously assigned to {@link #trigger}, so we can reset it - * if the user disables auto-completion. - */ - private Action oldTriggerAction; - - /** - * The previous key in the text component's InputMap for the - * parameter completion trigger key. - */ - private Object oldParenKey; - - /** - * The action previously assigned to the parameter completion key, so we - * can reset it when we uninstall. - */ - private Action oldParenAction; - - /** - * Listens for events in the parent window that affect the visibility of - * the popup windows. - */ - private ParentWindowListener parentWindowListener; - - /** - * Listens for events from the text component that affect the visibility - * of the popup windows. - */ - private TextComponentListener textComponentListener; - - /** - * Listens for events in the text component that cause the popup windows - * to automatically activate. - */ - private AutoActivationListener autoActivationListener; - - /** - * Listens for LAF changes so the auto-complete windows automatically - * update themselves accordingly. - */ - private LookAndFeelChangeListener lafListener; - - /** - * The key used in the input map for the AutoComplete action. - */ - private static final String PARAM_TRIGGER_KEY = "AutoComplete"; - - /** - * Key used in the input map for the parameter completion action. - */ - private static final String PARAM_COMPLETE_KEY = "AutoCompletion.FunctionStart"; - - /** - * Stores how to render auto-completion-specific highlights in text - * components. - */ - private static final AutoCompletionStyleContext STYLE_CONTEXT = - new AutoCompletionStyleContext(); - - /** - * Whether debug messages should be printed to stdout as AutoCompletion - * runs. - */ - private static final boolean DEBUG = initDebug(); - - +public class FormulaPaneAutoCompletion extends AutoCompletionWithExtraRefresh { /** * Constructor. * @@ -230,957 +22,29 @@ public class FormulaPaneAutoCompletion extends AutoCompletion { */ public FormulaPaneAutoCompletion(CompletionProvider provider) { super(provider); - setChoicesWindowSize(350, 200); - setDescriptionWindowSize(350, 250); - - setCompletionProvider(provider); - setTriggerKey(getDefaultTriggerKey()); - setAutoCompleteEnabled(true); - setAutoCompleteSingleChoices(true); - setAutoActivationEnabled(false); - setShowDescWindow(false); - parentWindowListener = new ParentWindowListener(); - textComponentListener = new TextComponentListener(); - autoActivationListener = new AutoActivationListener(); - lafListener = new LookAndFeelChangeListener(); - } - - - /** - * Displays the popup window. Hosting applications can call this method - * to programmatically begin an auto-completion operation. - */ - public void doCompletion() { - refreshPopupWindow(); - } - - - /** - * Returns the delay between when the user types a character and when the - * code completion popup should automatically appear (if applicable). - * - * @return The delay, in milliseconds. - * @see #setAutoActivationDelay(int) - */ - public int getAutoActivationDelay() { - return autoActivationListener.timer.getDelay(); } - - /** - * Returns whether, if a single auto-complete choice is available, it - * should be automatically inserted, without displaying the popup menu. - * - * @return Whether to auto-complete single choices. - * @see #setAutoCompleteSingleChoices(boolean) - */ - public boolean isAutoCompleteSingleChoices() { - return autoCompleteSingleChoices; - } - - - /** - * Returns the completion provider. - * - * @return The completion provider. - */ - public CompletionProvider getCompletionProvider() { - return provider; - } - - - /** - * Returns whether debug is enabled for AutoCompletion. - * - * @return Whether debug is enabled. - */ - static boolean isDebug() { - return DEBUG; - } - - - /** - * Returns the default auto-complete "trigger key" for this OS. For - * Windows, for example, it is Ctrl+Space. - * - * @return The default auto-complete trigger key. - */ - public static KeyStroke getDefaultTriggerKey() { - // Default to CTRL, even on Mac, since Ctrl+Space activates Spotlight - return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, DEFAULT_MODIFIER); - } - - - /** - * Returns the handler to use when an external URL is clicked in the - * description window. - * - * @return The handler. - * @see #setExternalURLHandler(ExternalURLHandler) - * @see #getLinkRedirector() - */ - public ExternalURLHandler getExternalURLHandler() { - return externalURLHandler; - } - - - int getLineOfCaret() { - Document doc = textComponent.getDocument(); - Element root = doc.getDefaultRootElement(); - return root.getElementIndex(textComponent.getCaretPosition()); - } - - - /** - * Returns the link redirector, if any. - * - * @return The link redirector, or null if none. - * @see #setLinkRedirector(LinkRedirector) - */ - public static LinkRedirector getLinkRedirector() { - return linkRedirector; - } - - - /** - * Returns the default list cell renderer used when a completion provider - * does not supply its own. - * - * @return The default list cell renderer. - * @see #setListCellRenderer(ListCellRenderer) - */ - public ListCellRenderer getListCellRenderer() { - return renderer; - } - - - /** - * Returns the renderer to use for {@link Completion}s in the optional - * parameter choices popup window (displayed when a - * {@link ParameterizedCompletion} is code-completed). If this returns - * null, a default renderer is used. - * - * @return The renderer to use. - * @see #setParamChoicesRenderer(ListCellRenderer) - * @see #isParameterAssistanceEnabled() - */ - public ListCellRenderer getParamChoicesRenderer() { - return paramChoicesRenderer; - } - - - /** - * Returns the text to replace with in the document. This is a - * "last-chance" hook for subclasses to make special modifications to the - * completion text inserted. The default implementation simply returns - * c.getReplacementText(). You usually will not need to modify - * this method. - * - * @param c The completion being inserted. - * @param doc The document being modified. - * @param start The start of the text being replaced. - * @param len The length of the text being replaced. - * @return The text to replace with. - */ - protected String getReplacementText(Completion c, Document doc, int start, - int len) { - return c.getReplacementText(); - } - - - /** - * Returns whether the "description window" should be shown alongside - * the completion window. - * - * @return Whether the description window should be shown. - * @see #setShowDescWindow(boolean) - */ - public boolean isShowDescWindow() { - return showDescWindow; - } - - - /** - * Returns the style context describing how auto-completion related - * highlights in the editor are rendered. - * - * @return The style context. - */ - public static AutoCompletionStyleContext getStyleContext() { - return STYLE_CONTEXT; - } - - - /** - * Returns the text component for which auto-completion is enabled. - * - * @return The text component, or null if this - * {@link AutoCompletion} is not installed on any text component. - * @see #install(JTextComponent) - */ - public JTextComponent getTextComponent() { - return textComponent; - } - - - /** - * Returns the orientation of the text component we're installed to. - * - * @return The orientation of the text component, or null if - * we are not installed on one. - */ - ComponentOrientation getTextComponentOrientation() { - return textComponent == null ? null : - textComponent.getComponentOrientation(); - } - - - /** - * Returns the "trigger key" used for auto-complete. - * - * @return The trigger key. - * @see #setTriggerKey(KeyStroke) - */ - public KeyStroke getTriggerKey() { - return trigger; - } - - - /** - * Hides any child windows being displayed by the auto-completion system. - * - * @return Whether any windows were visible. - */ - public boolean hideChildWindows() { - //return hidePopupWindow() || hideToolTipWindow(); - boolean res = hidePopupWindow(); - res |= hideParameterCompletionPopups(); - return res; - } - - - /** - * Hides and disposes of any parameter completion-related popups. - * - * @return Whether any such windows were visible (and thus hidden). - */ - private boolean hideParameterCompletionPopups() { - if (pcc != null) { - pcc.deactivate(); - pcc = null; - return true; - } - return false; - } - - - /** - * Hides the popup window, if it is visible. - * - * @return Whether the popup window was visible. - */ - private boolean hidePopupWindow() { - if (popupWindow != null) { - if (popupWindow.isVisible()) { - popupWindow.setVisible(false); - return true; - } - } - return false; - } - - - /** - * Determines whether debug should be enabled for the AutoCompletion - * library. This method checks a system property, but takes care of - * {@link SecurityException}s in case we're in an applet or WebStart. - * - * @return Whether debug should be enabled. - */ - private static boolean initDebug() { - boolean debug = false; - try { - debug = Boolean.getBoolean("AutoCompletion.debug"); - } catch (SecurityException se) { // We're in an applet or WebStart. - debug = false; - } - return debug; - } - - - /** - * Installs this auto-completion on a text component. If this - * {@link AutoCompletion} is already installed on another text component, - * it is uninstalled first. - * - * @param c The text component. - * @see #uninstall() - */ - public void install(JTextComponent c) { - - if (textComponent != null) { - uninstall(); - } - - this.textComponent = c; - installTriggerKey(getTriggerKey()); - - // Install the function completion key, if there is one. - // NOTE: We cannot do this if the start char is ' ' (e.g. just a space - // between the function name and parameters) because it overrides - // RSTA's special space action. It seems KeyStorke.getKeyStroke(' ') - // hoses ctrl+space, shift+space, etc., even though I think it - // shouldn't... - char start = provider.getParameterListStart(); - if (start != 0 && start != ' ') { - InputMap im = c.getInputMap(); - ActionMap am = c.getActionMap(); - KeyStroke ks = KeyStroke.getKeyStroke(start); - oldParenKey = im.get(ks); - im.put(ks, PARAM_COMPLETE_KEY); - oldParenAction = am.get(PARAM_COMPLETE_KEY); - am.put(PARAM_COMPLETE_KEY, - new ParameterizedCompletionStartAction(start)); - } - - textComponentListener.addTo(this.textComponent); - // In case textComponent is already in a window... - textComponentListener.hierarchyChanged(null); - - if (isAutoActivationEnabled()) { - autoActivationListener.addTo(this.textComponent); - } - - UIManager.addPropertyChangeListener(lafListener); - updateUI(); // In case there have been changes since we uninstalled - - } - - - /** - * Installs a "trigger key" action onto the current text component. - * - * @param ks The keystroke that should trigger the action. - */ - private void installTriggerKey(KeyStroke ks) { - InputMap im = textComponent.getInputMap(); - oldTriggerKey = im.get(ks); - im.put(ks, PARAM_TRIGGER_KEY); - ActionMap am = textComponent.getActionMap(); - oldTriggerAction = am.get(PARAM_TRIGGER_KEY); - am.put(PARAM_TRIGGER_KEY, new AutoCompleteAction()); - } - - - /** - * Returns whether auto-activation is enabled (that is, whether the - * completion popup will automatically appear after a delay when the user - * types an appropriate character). Note that this parameter will be - * ignored if auto-completion is disabled. - * - * @return Whether auto-activation is enabled. - * @see #setAutoActivationEnabled(boolean) - * @see #getAutoActivationDelay() - * @see #isAutoCompleteEnabled() - */ - public boolean isAutoActivationEnabled() { - return autoActivationEnabled; - } - - - /** - * Returns whether auto-completion is enabled. - * - * @return Whether auto-completion is enabled. - * @see #setAutoCompleteEnabled(boolean) - */ - public boolean isAutoCompleteEnabled() { - return autoCompleteEnabled; - } - - - /** - * Returns whether parameter assistance is enabled. - * - * @return Whether parameter assistance is enabled. - * @see #setParameterAssistanceEnabled(boolean) - */ - public boolean isParameterAssistanceEnabled() { - return parameterAssistanceEnabled; - } - - - /** - * Returns whether the completion popup window is visible. - * - * @return Whether the completion popup window is visible. - */ - public boolean isPopupVisible() { - return popupWindow != null && popupWindow.isVisible(); - } - - private boolean needSetPopupWindow(int count, int textLen) { - return (count == 1 && (isPopupVisible() || textLen == 0)) - || (count == 1 && !isAutoCompleteSingleChoices()) - || count > 1; - } - - private FormulaAutoCompletePopupWindow createAutoCompletePopupWindow() { - FormulaAutoCompletePopupWindow popupWindow = new FormulaAutoCompletePopupWindow(parentWindow, this); + @Override + protected AutoCompleteWithExtraRefreshPopupWindow createAutoCompletePopupWindow() { + FormulaAutoCompletePopupWindow popupWindow = new FormulaAutoCompletePopupWindow(getParentWindow(), this); // Completion is usually done for code, which is always done // LTR, so make completion stuff RTL only if text component is // also RTL. popupWindow.applyComponentOrientation( getTextComponentOrientation()); - if (renderer != null) { - popupWindow.setListCellRenderer(renderer); + if (getCellRender() != null) { + popupWindow.setListCellRenderer(getCellRender()); } - if (preferredChoicesWindowSize != null) { - popupWindow.setSize(preferredChoicesWindowSize); + if (getPreferredChoicesWindowSize() != null) { + popupWindow.setSize(getPreferredChoicesWindowSize()); } - if (preferredDescWindowSize != null) { + if (getPreferredDescWindowSize() != null) { popupWindow.setDescriptionWindowSize( - preferredDescWindowSize); + getPreferredDescWindowSize()); } return popupWindow; } - /** - * Sets the delay between when the user types a character and when the - * code completion popup should automatically appear (if applicable). - * - * @param ms The delay, in milliseconds. This should be greater than zero. - * @see #getAutoActivationDelay() - */ - public void setAutoActivationDelay(int ms) { - ms = Math.max(0, ms); - autoActivationListener.timer.stop(); - autoActivationListener.timer.setInitialDelay(ms); - } - - - /** - * Toggles whether auto-activation is enabled. Note that auto-activation - * also depends on auto-completion itself being enabled. - * - * @param enabled Whether auto-activation is enabled. - * @see #isAutoActivationEnabled() - * @see #setAutoActivationDelay(int) - */ - public void setAutoActivationEnabled(boolean enabled) { - if (enabled != autoActivationEnabled) { - autoActivationEnabled = enabled; - if (textComponent != null) { - if (autoActivationEnabled) { - autoActivationListener.addTo(textComponent); - } else { - autoActivationListener.removeFrom(textComponent); - } - } - } - } - - - /** - * Sets whether auto-completion is enabled. - * - * @param enabled Whether auto-completion is enabled. - * @see #isAutoCompleteEnabled() - */ - public void setAutoCompleteEnabled(boolean enabled) { - if (enabled != autoCompleteEnabled) { - autoCompleteEnabled = enabled; - hidePopupWindow(); - } - } - - - /** - * Sets whether, if a single auto-complete choice is available, it should - * be automatically inserted, without displaying the popup menu. - * - * @param autoComplete Whether to auto-complete single choices. - * @see #isAutoCompleteSingleChoices() - */ - public void setAutoCompleteSingleChoices(boolean autoComplete) { - autoCompleteSingleChoices = autoComplete; - } - - - /** - * Sets the completion provider being used. - * - * @param provider The new completion provider. This cannot be - * null. - * @throws IllegalArgumentException If provider is - * null. - */ - public void setCompletionProvider(CompletionProvider provider) { - if (provider == null) { - throw new IllegalArgumentException("provider cannot be null"); - } - this.provider = provider; - hidePopupWindow(); // In case new choices should be displayed. - } - - - /** - * Sets the size of the completion choices window. - * - * @param w The new width. - * @param h The new height. - * @see #setDescriptionWindowSize(int, int) - */ - public void setChoicesWindowSize(int w, int h) { - preferredChoicesWindowSize = new Dimension(w, h); - if (popupWindow != null) { - popupWindow.setSize(preferredChoicesWindowSize); - } - } - - - /** - * Sets the size of the description window. - * - * @param w The new width. - * @param h The new height. - * @see #setChoicesWindowSize(int, int) - */ - public void setDescriptionWindowSize(int w, int h) { - preferredDescWindowSize = new Dimension(w, h); - if (popupWindow != null) { - popupWindow.setDescriptionWindowSize(preferredDescWindowSize); - } - } - - - /** - * Sets the handler to use when an external URL is clicked in the - * description window. This handler can perform some action, such as - * open the URL in a web browser. The default implementation will open - * the URL in a browser, but only if running in Java 6. If you want - * browser support for Java 5 and below, or otherwise want to respond to - * hyperlink clicks, you will have to install your own handler to do so. - * - * @param handler The new handler. - * @see #getExternalURLHandler() - */ - public void setExternalURLHandler(ExternalURLHandler handler) { - this.externalURLHandler = handler; - } - - - /** - * Sets the redirector for external URL's found in code completion - * documentation. When a non-local link in completion popups is clicked, - * this redirector is given the chance to modify the URL fetched and - * displayed. - * - * @param redirector The link redirector, or null for - * none. - * @see #getLinkRedirector() - */ - public static void setLinkRedirector(LinkRedirector redirector) { - linkRedirector = redirector; - } - - - /** - * Sets the default list cell renderer to use when a completion provider - * does not supply its own. - * - * @param renderer The renderer to use. If this is null, - * a default renderer is used. - * @see #getListCellRenderer() - */ - public void setListCellRenderer(ListCellRenderer renderer) { - this.renderer = renderer; - if (popupWindow != null) { - popupWindow.setListCellRenderer(renderer); - hidePopupWindow(); - } - } - - - /** - * Sets the renderer to use for {@link Completion}s in the optional - * parameter choices popup window (displayed when a - * {@link ParameterizedCompletion} is code-completed). If this isn't set, - * a default renderer is used. - * - * @param r The renderer to use. - * @see #getParamChoicesRenderer() - * @see #setParameterAssistanceEnabled(boolean) - */ - public void setParamChoicesRenderer(ListCellRenderer r) { - paramChoicesRenderer = r; - } - - - /** - * Sets whether parameter assistance is enabled. If parameter assistance - * is enabled, and a "parameterized" completion (such as a function or - * method) is inserted, the user will get "assistance" in inserting the - * parameters in the form of a popup window with documentation and easy - * tabbing through the arguments (as seen in Eclipse and NetBeans). - * - * @param enabled Whether parameter assistance should be enabled. - * @see #isParameterAssistanceEnabled() - */ - public void setParameterAssistanceEnabled(boolean enabled) { - parameterAssistanceEnabled = enabled; - } - - - /** - * Sets whether the "description window" should be shown beside the - * completion window. - * - * @param show Whether to show the description window. - * @see #isShowDescWindow() - */ - public void setShowDescWindow(boolean show) { - hidePopupWindow(); // Needed to force it to take effect - showDescWindow = show; - } - - - /** - * Sets the keystroke that should be used to trigger the auto-complete - * popup window. - * - * @param ks The keystroke. - * @throws IllegalArgumentException If ks is null. - * @see #getTriggerKey() - */ - public void setTriggerKey(KeyStroke ks) { - if (ks == null) { - throw new IllegalArgumentException("trigger key cannot be null"); - } - if (!ks.equals(trigger)) { - if (textComponent != null) { - // Put old trigger action back. - uninstallTriggerKey(); - // Grab current action for new trigger and replace it. - installTriggerKey(ks); - } - trigger = ks; - } - } - - - /** - * Uninstalls this auto-completion from its text component. If it is not - * installed on any text component, nothing happens. - * - * @see #install(JTextComponent) - */ - public void uninstall() { - - if (textComponent != null) { - - hidePopupWindow(); // Unregisters listeners, actions, etc. - - uninstallTriggerKey(); - - // Uninstall the function completion key. - char start = provider.getParameterListStart(); - if (start != 0) { - KeyStroke ks = KeyStroke.getKeyStroke(start); - InputMap im = textComponent.getInputMap(); - im.put(ks, oldParenKey); - ActionMap am = textComponent.getActionMap(); - am.put(PARAM_COMPLETE_KEY, oldParenAction); - } - - textComponentListener.removeFrom(textComponent); - if (parentWindow != null) { - parentWindowListener.removeFrom(parentWindow); - } - - if (isAutoActivationEnabled()) { - autoActivationListener.removeFrom(textComponent); - } - - UIManager.removePropertyChangeListener(lafListener); - - textComponent = null; - popupWindow = null; - - } - - } - - - /** - * Replaces the "trigger key" action with the one that was there - * before auto-completion was installed. - */ - private void uninstallTriggerKey() { - InputMap im = textComponent.getInputMap(); - im.put(trigger, oldTriggerKey); - ActionMap am = textComponent.getActionMap(); - am.put(PARAM_TRIGGER_KEY, oldTriggerAction); - } - - - /** - * Updates the LookAndFeel of the popup window. Applications can call - * this method as appropriate if they support changing the LookAndFeel - * at runtime. - */ - private void updateUI() { - if (popupWindow != null) { - popupWindow.updateUI(); - } - if (pcc != null) { - pcc.updateUI(); - } - // Will practically always be a JComponent (a JLabel) - if (paramChoicesRenderer instanceof JComponent) { - ((JComponent) paramChoicesRenderer).updateUI(); - } - } - - - /** - * Listens for events in the text component to auto-activate the code - * completion popup. - */ - private class AutoActivationListener extends FocusAdapter - implements DocumentListener, CaretListener, ActionListener { - - private Timer timer; - private boolean justInserted; - - public AutoActivationListener() { - timer = new Timer(200, this); - timer.setRepeats(false); - } - - public void actionPerformed(ActionEvent e) { - doCompletion(); - } - - public void addTo(JTextComponent tc) { - tc.addFocusListener(this); - tc.getDocument().addDocumentListener(this); - tc.addCaretListener(this); - } - - public void caretUpdate(CaretEvent e) { - if (justInserted) { - justInserted = false; - } else { - timer.stop(); - } - } - - public void changedUpdate(DocumentEvent e) { - // Ignore - } - - @Override - public void focusLost(FocusEvent e) { - timer.stop(); - //hideChildWindows(); Other listener will do this - } - - public void insertUpdate(DocumentEvent e) { - justInserted = false; - if (isAutoCompleteEnabled() && isAutoActivationEnabled() && - e.getLength() == 1) { - if (provider.isAutoActivateOkay(textComponent)) { - timer.restart(); - justInserted = true; - } else { - timer.stop(); - } - } else { - timer.stop(); - } - } - - public void removeFrom(JTextComponent tc) { - tc.removeFocusListener(this); - tc.getDocument().removeDocumentListener(this); - tc.removeCaretListener(this); - timer.stop(); - justInserted = false; - } - - public void removeUpdate(DocumentEvent e) { - timer.stop(); - } - - } - - - /** - * The Action that displays the popup window if - * auto-completion is enabled. - */ - private class AutoCompleteAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isAutoCompleteEnabled()) { - refreshPopupWindow(); - } else if (oldTriggerAction != null) { - oldTriggerAction.actionPerformed(e); - } - } - - } - - - /** - * Listens for LookAndFeel changes and updates the various popup windows - * involved in auto-completion accordingly. - */ - private class LookAndFeelChangeListener implements PropertyChangeListener { - - public void propertyChange(PropertyChangeEvent e) { - String name = e.getPropertyName(); - if ("lookAndFeel".equals(name)) { - updateUI(); - } - } - - } - - - /** - * Action that starts a parameterized completion, e.g. after '(' is - * typed. - */ - private class ParameterizedCompletionStartAction extends AbstractAction { - - private String start; - - public ParameterizedCompletionStartAction(char ch) { - this.start = Character.toString(ch); - } - - public void actionPerformed(ActionEvent e) { - - // Prevents keystrokes from messing up - boolean wasVisible = hidePopupWindow(); - - // Only proceed if they were selecting a completion - if (!wasVisible || !isParameterAssistanceEnabled()) { - textComponent.replaceSelection(start); - return; - } - - Completion c = popupWindow.getSelection(); - if (c instanceof ParameterizedCompletion) { // Should always be true - // Fixes capitalization of the entered text. - insertCompletion(c, true); - } - - } - - } - - - /** - * Listens for events in the parent window of the text component with - * auto-completion enabled. - */ - private class ParentWindowListener extends ComponentAdapter - implements WindowFocusListener { - - public void addTo(Window w) { - w.addComponentListener(this); - w.addWindowFocusListener(this); - } - - @Override - public void componentHidden(ComponentEvent e) { - hideChildWindows(); - } - - @Override - public void componentMoved(ComponentEvent e) { - hideChildWindows(); - } - - @Override - public void componentResized(ComponentEvent e) { - hideChildWindows(); - } - - public void removeFrom(Window w) { - w.removeComponentListener(this); - w.removeWindowFocusListener(this); - } - - public void windowGainedFocus(WindowEvent e) { - } - - public void windowLostFocus(WindowEvent e) { - hideChildWindows(); - } - - } - - - /** - * Listens for events from the text component we're installed on. - */ - private class TextComponentListener extends FocusAdapter - implements HierarchyListener { - - void addTo(JTextComponent tc) { - tc.addFocusListener(this); - tc.addHierarchyListener(this); - } - - /** - * Hide the auto-completion windows when the text component loses - * focus. - */ - @Override - public void focusLost(FocusEvent e) { - hideChildWindows(); - } - - /** - * Called when the component hierarchy for our text component changes. - * When the text component is added to a new {@link Window}, this - * method registers listeners on that Window. - * - * @param e The event. - */ - public void hierarchyChanged(HierarchyEvent e) { - - // NOTE: e many be null as we call this method at other times. - //System.out.println("Hierarchy changed! " + e); - - Window oldParentWindow = parentWindow; - parentWindow = SwingUtilities.getWindowAncestor(textComponent); - if (parentWindow != oldParentWindow) { - if (oldParentWindow != null) { - parentWindowListener.removeFrom(oldParentWindow); - } - if (parentWindow != null) { - parentWindowListener.addTo(parentWindow); - } - } - - } - - public void removeFrom(JTextComponent tc) { - tc.removeFocusListener(this); - tc.removeHierarchyListener(this); - } - - } - - public void installVariableTree(FormulaPane.VariableTreeAndDescriptionArea jComp) { - area = jComp; - } - /** * Inserts a completion. Any time a code completion event occurs, the * actual text insertion happens through this method. @@ -1223,89 +87,4 @@ public class FormulaPaneAutoCompletion extends AutoCompletion { } } - - /** - * Displays a "tool tip" detailing the inputs to the function just entered. - * - * @param pc The completion. - * @param typedParamListStartChar Whether the parameterized completion list - * starting character was typed. - */ - private void startParameterizedCompletionAssistance( - ParameterizedCompletion pc, boolean typedParamListStartChar) { - - // Get rid of the previous tool tip window, if there is one. - hideParameterCompletionPopups(); - - // Don't bother with a tool tip if there are no parameters, but if - // they typed e.g. the opening '(', make them overtype the ')'. - if (pc.getParamCount() == 0 && !(pc instanceof TemplateCompletion)) { - CompletionProvider p = pc.getProvider(); - char end = p.getParameterListEnd(); // Might be '\0' - String text = end == '\0' ? "" : Character.toString(end); - if (typedParamListStartChar) { - String template = "${}" + text + "${cursor}"; - textComponent.replaceSelection(Character.toString(p.getParameterListStart())); - TemplateCompletion tc = new TemplateCompletion(p, null, null, template); - pc = tc; - } else { - text = p.getParameterListStart() + text; - textComponent.replaceSelection(text); - return; - } - } - - pcc = new ParameterizedCompletionContext(parentWindow, this, pc); - pcc.activate(); - - } - - protected int refreshPopupWindow() { - // A return value of null => don't suggest completions - String text = provider.getAlreadyEnteredText(textComponent); - if (text == null && !isPopupVisible()) { - return getLineOfCaret(); - } - // If the popup is currently visible, and they type a space (or any - // character that resets the completion list to "all completions"), - // the popup window should be hidden instead of being reset to show - // everything. - int textLen = text == null ? 0 : text.length(); - if (textLen == 0 && isPopupVisible()) { - hidePopupWindow(); - return getLineOfCaret(); - } - final List completions = provider.getCompletions(textComponent); - int count = completions.size(); - if (needSetPopupWindow(count, textLen)) { - if (popupWindow == null) { - popupWindow = createAutoCompletePopupWindow(); - } - popupWindow.installComp(area); - popupWindow.setCompletions(completions); - if (!popupWindow.isVisible()) { - Rectangle r = null; - try { - r = textComponent.modelToView(textComponent.getCaretPosition()); - } catch (BadLocationException ble) { - return -1; - } - Point p = new Point(r.x, r.y); - SwingUtilities.convertPointToScreen(p, textComponent); - r.x = p.x; - r.y = p.y; - popupWindow.setLocationRelativeTo(r); - popupWindow.setVisible(true); - } - } else if (count == 1) { // !isPopupVisible && autoCompleteSingleChoices - SwingUtilities.invokeLater(new Runnable() { - public void run() { - insertCompletion(completions.get(0)); - } - }); - } else { - hidePopupWindow(); - } - return getLineOfCaret(); - } } diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/JSAutoCompletePopupWindow.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/JSAutoCompletePopupWindow.java new file mode 100644 index 000000000..80a26bf96 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/JSAutoCompletePopupWindow.java @@ -0,0 +1,16 @@ +package com.fr.design.gui.autocomplete; + +import java.awt.Window; + +public class JSAutoCompletePopupWindow extends AutoCompleteWithExtraRefreshPopupWindow { + + /** + * Constructor. + * + * @param parent The parent window (hosting the text component). + * @param ac The auto-completion instance. + */ + public JSAutoCompletePopupWindow(Window parent, AutoCompletion ac) { + super(parent, ac); + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/JSImplPaneAutoCompletion.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/JSImplPaneAutoCompletion.java new file mode 100644 index 000000000..0c534bf72 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/JSImplPaneAutoCompletion.java @@ -0,0 +1,31 @@ +package com.fr.design.gui.autocomplete; + +public class JSImplPaneAutoCompletion extends AutoCompletionWithExtraRefresh{ + /** + * Constructor. + * + * @param provider The completion provider. This cannot be + * null. + */ + public JSImplPaneAutoCompletion(CompletionProvider provider) { + super(provider); + } + + @Override + protected AutoCompleteWithExtraRefreshPopupWindow createAutoCompletePopupWindow() { + JSAutoCompletePopupWindow popupWindow = new JSAutoCompletePopupWindow(getParentWindow(),this); + popupWindow.applyComponentOrientation( + getTextComponentOrientation()); + if (getCellRender() != null) { + popupWindow.setListCellRenderer(getCellRender()); + } + if (getPreferredChoicesWindowSize() != null) { + popupWindow.setSize(getPreferredChoicesWindowSize()); + } + if (getPreferredDescWindowSize() != null) { + popupWindow.setDescriptionWindowSize( + getPreferredDescWindowSize()); + } + return popupWindow; + } +} diff --git a/designer-base/src/main/java/com/fr/design/javascript/JSContentPane.java b/designer-base/src/main/java/com/fr/design/javascript/JSContentPane.java index 10e11c8fb..10bee69d2 100644 --- a/designer-base/src/main/java/com/fr/design/javascript/JSContentPane.java +++ b/designer-base/src/main/java/com/fr/design/javascript/JSContentPane.java @@ -4,7 +4,9 @@ import com.fr.design.DesignerEnvManager; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.KeyWords; import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; +import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.gui.autocomplete.AutoCompletion; import com.fr.design.gui.autocomplete.BasicCompletion; import com.fr.design.gui.autocomplete.CompletionProvider; @@ -15,31 +17,145 @@ import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; import com.fr.design.javascript.beautify.JavaScriptFormatHelper; +import com.fr.design.javascript.jsapi.JSImplPopulateAction; +import com.fr.design.javascript.jsapi.JSImplUpdateAction; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; import com.fr.general.IOUtils; +import com.fr.js.JavaScriptImpl; -import javax.swing.*; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FontMetrics; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.SwingWorker; public class JSContentPane extends BasicPane { - private RSyntaxTextArea contentTextArea; - private UILabel funNameLabel; + protected RSyntaxTextArea contentTextArea; + private UILabel funNameLabel = new UILabel(); private AutoCompletion ac; private static final Dimension FUNCTION_NAME_LABEL_SIZE = new Dimension(300, 80); - + private String[] defaultArgs; private int titleWidth = 180; + private JPanel labelPane = new JPanel(new BorderLayout(6, 4));; + private NewJavaScriptImplPane newJavaScriptImplPane = null; + private JavaScriptImpl javaScript; + private JSImplUpdateAction jsImplUpdateAction; + private JSImplPopulateAction jsImplPopulateAction; + private boolean modal; + BasicDialog advancedEditorDialog ; + public JSContentPane(){} public JSContentPane(String[] args) { + defaultArgs = args; this.setLayout(FRGUIPaneFactory.createBorderLayout()); - funNameLabel = new UILabel(); - this.setFunctionTitle(args); + initFunctionTitle(args); + + JPanel jsParaPane = createJSParaPane(); + addNewPaneLabel(); + this.add(jsParaPane, BorderLayout.NORTH); + + UIScrollPane sp = createContentTextAreaPanel(); + initContentTextAreaListener(); + this.add(sp, BorderLayout.CENTER); + + UILabel funNameLabel2 = new UILabel(); + funNameLabel2.setText("}"); + this.add(funNameLabel2, BorderLayout.SOUTH); + } + public JSContentPane(String[] args,boolean modal) { + this(args); + this.modal = modal; + } + + + public void setJsImplUpdateAction(JSImplUpdateAction jsImplUpdateAction){ + this.jsImplUpdateAction = jsImplUpdateAction; + } + + public void setJsImplPopulateAction(JSImplPopulateAction jsImplPopulateAction){ + this.jsImplPopulateAction = jsImplPopulateAction; + } + + public void updateJSImpl(JavaScriptImpl javaScript){ + this.javaScript = javaScript; + } + + + private void addNewPaneLabel(){ + UILabel advancedEditorLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Advanced_Editor"), SwingConstants.LEFT); + advancedEditorLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); + advancedEditorLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if(newJavaScriptImplPane == null){ + newJavaScriptImplPane = new NewJavaScriptImplPane(defaultArgs); + } + jsImplUpdateAction.update(javaScript); + newJavaScriptImplPane.populate(javaScript); + if(advancedEditorDialog == null || !advancedEditorDialog.isVisible()) { + advancedEditorDialog = newJavaScriptImplPane.showWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + @Override + public void doOk() { + if (javaScript != null) { + newJavaScriptImplPane.updateBean(javaScript); + jsImplPopulateAction.populate(javaScript); + } + } + + @Override + public void doCancel() { + super.doCancel(); + } + }); + advancedEditorDialog.setModal(modal); + advancedEditorDialog.setResizable(true); + advancedEditorDialog.pack(); + advancedEditorDialog.setVisible(true); + } + advancedEditorDialog.requestFocus(); + } + }); + labelPane.add(advancedEditorLabel,BorderLayout.CENTER); + } + + protected UIScrollPane createContentTextAreaPanel(){ + contentTextArea = new RSyntaxTextArea(); + contentTextArea.setCloseCurlyBraces(true); + contentTextArea.setLineWrap(true); + contentTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); + contentTextArea.setCodeFoldingEnabled(true); + contentTextArea.setAntiAliasingEnabled(true); + return new UIScrollPane(contentTextArea); + } + + private void initContentTextAreaListener(){ + contentTextArea.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + // 获得焦点时 安装 + installAutoCompletion(); + } + + @Override + public void focusLost(FocusEvent e) { + // 失去焦点时 卸载 + uninstallAutoCompletion(); + } + }); + } + + protected JPanel createJSParaPane(){ UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Format_JavaScript"), IOUtils.readIcon("com/fr/design/images/edit/format.png"), SwingConstants.LEFT); label.setCursor(new Cursor(Cursor.HAND_CURSOR)); label.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Format_JavaScript")); @@ -65,43 +181,20 @@ public class JSContentPane extends BasicPane { } }); - //REPORT-10533 用户参数多达25个,导致JS没地方写,增加滚动条显示 + labelPane.add(label,BorderLayout.EAST); JPanel jsParaPane = new JPanel(new BorderLayout(4, 4)); jsParaPane.setPreferredSize(new Dimension(300, 80)); UIScrollPane scrollPane = new UIScrollPane(funNameLabel); scrollPane.setPreferredSize(FUNCTION_NAME_LABEL_SIZE); scrollPane.setBorder(new UIRoundedBorder(UIConstants.TITLED_BORDER_COLOR, 1, UIConstants.ARC)); jsParaPane.add(scrollPane, BorderLayout.WEST); - jsParaPane.add(label, BorderLayout.EAST); - this.add(jsParaPane, BorderLayout.NORTH); - - contentTextArea = new RSyntaxTextArea(); - contentTextArea.setCloseCurlyBraces(true); - contentTextArea.setLineWrap(true); - contentTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); - contentTextArea.setCodeFoldingEnabled(true); - contentTextArea.setAntiAliasingEnabled(true); - - UIScrollPane sp = new UIScrollPane(contentTextArea); - this.add(sp, BorderLayout.CENTER); - - contentTextArea.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - // 获得焦点时 安装 - installAutoCompletion(); - } - - @Override - public void focusLost(FocusEvent e) { - // 失去焦点时 卸载 - uninstallAutoCompletion(); - } - }); + jsParaPane.add(labelPane, BorderLayout.EAST); + return jsParaPane; + } - UILabel funNameLabel2 = new UILabel(); - funNameLabel2.setText("}"); - this.add(funNameLabel2, BorderLayout.SOUTH); + protected void initFunctionTitle(String[] args){ + funNameLabel = new UILabel(); + this.setFunctionTitle(args); } private KeyStroke convert2KeyStroke(String ks) { diff --git a/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java b/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java new file mode 100644 index 000000000..b1516fe36 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java @@ -0,0 +1,858 @@ +package com.fr.design.javascript; + +import com.fr.design.border.UIRoundedBorder; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.autocomplete.AutoCompleteExtraRefreshComponent; +import com.fr.design.gui.autocomplete.BasicCompletion; +import com.fr.design.gui.autocomplete.CompletionCellRenderer; +import com.fr.design.gui.autocomplete.CompletionProvider; +import com.fr.design.gui.autocomplete.DefaultCompletionProvider; +import com.fr.design.gui.autocomplete.JSImplPaneAutoCompletion; +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.gui.itextarea.UITextArea; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.javascript.jsapi.JSAPITreeHelper; +import com.fr.design.javascript.jsapi.JSAPIUserObject; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.general.CloudCenter; +import com.fr.general.ComparatorUtils; +import com.fr.general.http.HttpToolbox; +import com.fr.json.JSONArray; +import com.fr.json.JSONException; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Desktop; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +public class JSContentWithDescriptionPane extends JSContentPane implements KeyListener { + + //搜索关键词输入框 + private UITextField keyWordTextField = new UITextField(16); + //搜索出的提示列表 + private JList tipsList; + private DefaultListModel tipsListModel = new DefaultListModel(); + + private JList interfaceNameList; + private DefaultListModel interfaceNameModel; + + private JTree moduleTree; + + private DefaultCompletionProvider completionProvider; + private JSImplPaneAutoCompletion autoCompletion; + + //函数说明文本框 + private UITextArea descriptionTextArea; + + private JPopupMenu popupMenu; + + private InterfaceAndDescriptionPanel interfaceAndDescriptionPanel; + private JList helpDOCList; + + private int ifHasBeenWriten = 0; + private int currentPosition = 0; + private int beginPosition = 0; + private int insertPosition = 0; + private static final String SEPARATOR = "_"; + + private static final int KEY_10 = 10; + //上下左右 + private static final int KEY_37 = 37; + private static final int KEY_38 = 38; + private static final int KEY_39 = 39; + private static final int KEY_40 = 40; + + private static final String URL_FOR_TEST_NETWORK = "https://www.baidu.com"; + + private static final String DOCUMENT_SEARCH_URL = CloudCenter.getInstance().acquireUrlByKind("af.doc_search"); + + private String currentValue; + + public JSContentWithDescriptionPane(String[] args) { + this.setLayout(new BorderLayout()); + //=============================== + this.initFunctionTitle(args); + JPanel jsParaAndSearchPane = new JPanel(new BorderLayout()); + + //js函数声明面板 + JPanel jsParaPane = createJSParaPane(); + + jsParaPane.setPreferredSize(new Dimension(650, 80)); + //右上角的搜索提示面板 + JPanel tipsPane = createTipsPane(); + + jsParaAndSearchPane.add(jsParaPane, BorderLayout.CENTER); + jsParaAndSearchPane.add(tipsPane, BorderLayout.EAST); + + initPopTips(); + + //js文本编辑面板 + UIScrollPane contentTextAreaPanel = createContentTextAreaPanel(); + initContextAreaListener(); + + contentTextAreaPanel.setPreferredSize(new Dimension(850, 250)); + //js函数结束标签 + UILabel endBracketsLabel = new UILabel(); + endBracketsLabel.setText("}"); + + //结尾括号和复用函数按钮面板 + JPanel endBracketsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + endBracketsPanel.add(endBracketsLabel, BorderLayout.WEST); + + JPanel northPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + northPanel.add(jsParaAndSearchPane, BorderLayout.NORTH); + + northPanel.add(contentTextAreaPanel, BorderLayout.CENTER); + northPanel.add(endBracketsPanel, BorderLayout.SOUTH); + + //主编辑框,也就是面板的正中间部分 + this.add(northPanel, BorderLayout.CENTER); + + //函数分类和函数说明面板================================== + JPanel functionNameAndDescriptionPanel = createInterfaceAndDescriptionPanel(); + functionNameAndDescriptionPanel.setPreferredSize(new Dimension(880, 220)); + + this.add(functionNameAndDescriptionPanel, BorderLayout.SOUTH); + } + + private void initContextAreaListener() { + contentTextArea.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if ((e.getKeyChar() >= 'A' && e.getKeyChar() <= 'z') || e.getKeyChar() == '_') { + if (autoCompletion != null) { + autoCompletion.doCompletion(); + } + } + } + + @Override + public void keyReleased(KeyEvent e) { + contentTextArea.setForeground(Color.black); + } + }); + contentTextArea.addKeyListener(this); + contentTextArea.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + if (autoCompletion == null) { + installAutoCompletion(); + } + } + + @Override + public void focusLost(FocusEvent e) { + uninstallAutoCompletion(); + } + }); + } + + @Override + public void keyTyped(KeyEvent e) { + + } + + @Override + public void keyPressed(KeyEvent e) { + if (ifHasBeenWriten == 0) { + this.contentTextArea.setText(StringUtils.EMPTY); + } + } + + @Override + public void keyReleased(KeyEvent e) { + int key = e.getKeyCode(); + if (key == KEY_38 || key == KEY_40 || key == KEY_37 || key == KEY_39 || key == KEY_10) //如果是删除符号 ,为了可读性 没有和其他按键的程序相融合 + { + currentPosition = contentTextArea.getCaretPosition(); + insertPosition = currentPosition; + beginPosition = getBeginPosition(); + } else { + if (contentTextArea.getText().trim().length() == 0) { + insertPosition = 0; + } else { + contentTextArea.setForeground(Color.black); + currentPosition = contentTextArea.getCaretPosition(); + beginPosition = getBeginPosition(); + insertPosition = beginPosition; + ifHasBeenWriten = 1; + } + } + } + + private int getBeginPosition() { + int i = currentPosition; + String textArea = contentTextArea.getText(); + for (; i > 0; i--) { + String tested = textArea.substring(i - 1, i).toUpperCase(); + char[] testedChar = tested.toCharArray(); + if (isChar(testedChar[0]) || isNum(testedChar[0])) { + continue; + } else { + break; + } + } + return i; + } + + private static boolean isNum(char tested) { + return tested >= '0' && tested <= '9'; + } + + private boolean isChar(char tested) { + return tested >= 'A' && tested <= 'Z' || tested >= 'a' && tested < 'z'; + } + + public class InterfaceAndDescriptionPanel extends JPanel implements AutoCompleteExtraRefreshComponent { + @Override + public void refresh(String replacementText) { + fixInterfaceNameList(replacementText); + } + } + + private void fixInterfaceNameList(String interfaceName) { + DefaultTreeModel defaultTreeModel = (DefaultTreeModel) moduleTree.getModel(); + TreeNode root = (TreeNode) defaultTreeModel.getRoot(); + String directCategory = JSAPITreeHelper.getDirectCategory(interfaceName); + if (directCategory == null) { + return; + } + setModuleTreeSelection(root, directCategory, defaultTreeModel); + interfaceNameModel = (DefaultListModel) interfaceNameList.getModel(); + interfaceNameModel.clear(); + List interfaceNames = JSAPITreeHelper.getNames(directCategory); + int index = 0; + for (int i = 0; i < interfaceNames.size(); i++) { + interfaceNameModel.addElement(interfaceNames.get(i)); + if (StringUtils.equals(interfaceNames.get(i), interfaceName)) { + index = i; + } + } + interfaceNameList.setSelectedIndex(index); + interfaceNameList.ensureIndexIsVisible(index); + } + + private boolean setModuleTreeSelection(TreeNode node, String directCategory, DefaultTreeModel treeModel) { + + DefaultMutableTreeNode defaultMutableTreeNode = (DefaultMutableTreeNode) node; + Object userObject = defaultMutableTreeNode.getUserObject(); + if (userObject instanceof JSAPIUserObject) { + String value = ((JSAPIUserObject) userObject).getValue(); + if (StringUtils.equals(value, directCategory)) { + moduleTree.setSelectionPath(new TreePath(treeModel.getPathToRoot(node))); + return true; + } + return false; + } + for (int i = 0; i < node.getChildCount(); i++) { + if (setModuleTreeSelection(node.getChildAt(i), directCategory, treeModel)) { + return true; + } + } + return false; + } + + private JPanel createInterfaceAndDescriptionPanel() { + interfaceAndDescriptionPanel = new InterfaceAndDescriptionPanel(); + interfaceAndDescriptionPanel.setLayout(new BorderLayout(4, 4)); + JPanel interfacePanel = new JPanel(new BorderLayout(4, 4)); + interfaceAndDescriptionPanel.add(interfacePanel, BorderLayout.WEST); + JPanel descriptionAndDocumentPanel = new JPanel(new BorderLayout(4, 4)); + //函数说明和帮助文档框 + initDescriptionArea(descriptionAndDocumentPanel); + + //模块和接口面板 + initInterfaceModuleTree(interfacePanel); + initInterfaceNameList(interfacePanel); + + initHelpDocumentPane(descriptionAndDocumentPanel); + + interfaceAndDescriptionPanel.add(descriptionAndDocumentPanel, BorderLayout.CENTER); + return interfaceAndDescriptionPanel; + } + + private void doHelpDocumentSearch() { + Object value = interfaceNameList.getSelectedValue(); + if (value != null) { + String url = DOCUMENT_SEARCH_URL + value.toString(); + try { + String result = HttpToolbox.get(url); + JSONObject jsonObject = new JSONObject(result); + JSONArray jsonArray = jsonObject.optJSONArray("list"); + if (jsonArray != null) { + DefaultListModel helpDOCModel = (DefaultListModel) helpDOCList.getModel(); + helpDOCModel.clear(); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject resultJSONObject = jsonArray.optJSONObject(i); + String docURL = resultJSONObject.optString("url"); + String name = resultJSONObject.optString("title").trim(); + HelpDocument helpDocument = new HelpDocument(docURL, name); + helpDOCModel.addElement(helpDocument); + } + } + } catch (JSONException e) { + FineLoggerFactory.getLogger().debug(e.getMessage(), e); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } + + private void initHelpDocumentPane(JPanel descriptionAndDocumentPanel) { + UIScrollPane helpDOCScrollPane; + if (isNetworkOk()) { + helpDOCList = new JList(new DefaultListModel()); + initHelpDOCListRender(); + initHelpDOCListListener(); + helpDOCScrollPane = new UIScrollPane(helpDOCList); + doHelpDocumentSearch(); + } else { + UILabel label1 = new UILabel(Toolkit.i18nText("Fine-Design_Net_Connect_Failed"), 0); + label1.setPreferredSize(new Dimension(180, 20)); + UILabel label2 = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Reload"), 0); + label2.setPreferredSize(new Dimension(180, 20)); + label2.setForeground(Color.blue); + JPanel labelPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, 0, 0, 0); + labelPane.setBackground(Color.WHITE); + labelPane.add(label1); + labelPane.add(label2); + JPanel containerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + containerPanel.add(labelPane, BorderLayout.CENTER); + helpDOCScrollPane = new UIScrollPane(containerPanel); + label2.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + descriptionAndDocumentPanel.removeAll(); + initHelpDocumentPane(descriptionAndDocumentPanel); + + } + }); + } + helpDOCScrollPane.setPreferredSize(new Dimension(200, 200)); + helpDOCScrollPane.setBorder(null); + descriptionAndDocumentPanel.add(this.createNamePane(Toolkit.i18nText("Fine-Design_Relevant_Cases"), helpDOCScrollPane), BorderLayout.EAST); + + } + + private void initHelpDOCListListener() { + helpDOCList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + Object value = helpDOCList.getSelectedValue(); + if (value instanceof HelpDocument) { + String url = ((HelpDocument) value).getDocumentUrl(); + try { + Desktop.getDesktop().browse(new URI(url)); + } catch (IOException ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } catch (URISyntaxException ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + } + } + } + }); + } + + private void initHelpDOCListRender() { + helpDOCList.setCellRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof HelpDocument) { + this.setText(((HelpDocument) value).getName()); + this.setForeground(Color.BLUE); + } + return this; + } + }); + } + + private static boolean isNetworkOk() { + try { + HttpToolbox.get(URL_FOR_TEST_NETWORK); + return true; + } catch (Exception ignore) { + // 网络异常 + return false; + } + } + + private static class HelpDocument { + private String documentUrl; + + + private String name; + + public HelpDocument(String documentUrl, String name) { + this.documentUrl = documentUrl; + this.name = name; + } + + public String getDocumentUrl() { + return documentUrl; + } + + public String getName() { + return name; + } + } + + private void initDescriptionArea(JPanel descriptionPanel) { + descriptionTextArea = new UITextArea(); + UIScrollPane descriptionScrollPane = new UIScrollPane(descriptionTextArea); + descriptionScrollPane.setPreferredSize(new Dimension(300, 200)); + descriptionPanel.add(this.createNamePane(Toolkit.i18nText("Fine-Design_Interface_Description"), descriptionScrollPane), BorderLayout.CENTER); + descriptionTextArea.setBackground(Color.white); + descriptionTextArea.setLineWrap(true); + descriptionTextArea.setWrapStyleWord(true); + descriptionTextArea.setEditable(false); + } + + private void installAutoCompletion() { + CompletionProvider provider = createCompletionProvider(); + autoCompletion = new JSImplPaneAutoCompletion(provider); + autoCompletion.setListCellRenderer(new CompletionCellRenderer()); + autoCompletion.install(contentTextArea); + autoCompletion.installExtraRefreshComponent(interfaceAndDescriptionPanel); + } + + private void uninstallAutoCompletion() { + if (autoCompletion != null) { + autoCompletion.uninstall(); + autoCompletion = null; + } + } + + private CompletionProvider createCompletionProvider() { + if (completionProvider == null) { + completionProvider = new DefaultCompletionProvider(); + for (String name : JSAPITreeHelper.getAllNames()) { + completionProvider.addCompletion(new BasicCompletion(completionProvider, name)); + } + } + return completionProvider; + } + + private void initInterfaceModuleTree(JPanel interfacePanel) { + moduleTree = new JTree(); + UIScrollPane moduleTreePane = new UIScrollPane(moduleTree); + moduleTreePane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + interfacePanel.add(this.createNamePane(Toolkit.i18nText("Fine-Design_Module"), moduleTreePane), BorderLayout.WEST); + moduleTreePane.setPreferredSize(new Dimension(180, 200)); + + moduleTree.setRootVisible(false); + moduleTree.setShowsRootHandles(true); + moduleTree.setCellRenderer(moduleTreeCellRender); + DefaultTreeModel moduleTreeModel = (DefaultTreeModel) moduleTree.getModel(); + DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode) moduleTreeModel.getRoot(); + rootNode.removeAllChildren(); + + JSAPITreeHelper.createJSAPITree(rootNode); + moduleTreeModel.reload(); + + initModuleTreeSelectionListener(); + } + + private void initModuleTreeSelectionListener() { + moduleTree.addTreeSelectionListener(new TreeSelectionListener() { + @Override + public void valueChanged(TreeSelectionEvent e) { + DefaultMutableTreeNode selectedTreeNode = (DefaultMutableTreeNode) moduleTree.getLastSelectedPathComponent(); + Object selectedValue = selectedTreeNode.getUserObject(); + if (null == selectedValue) { + return; + } + if (selectedValue instanceof JSAPIUserObject) { + interfaceNameModel = (DefaultListModel) interfaceNameList.getModel(); + interfaceNameModel.clear(); + String text = ((JSAPIUserObject) selectedValue).getValue(); + List allInterfaceNames = JSAPITreeHelper.getNames(text); + for (String interfaceName : allInterfaceNames) { + interfaceNameModel.addElement(interfaceName); + } + if (interfaceNameModel.size() > 0) { + interfaceNameList.setSelectedIndex(0); + setDescription(interfaceNameList.getSelectedValue().toString()); + interfaceNameList.ensureIndexIsVisible(0); + } + } + } + }); + } + + + private DefaultTreeCellRenderer moduleTreeCellRender = new DefaultTreeCellRenderer() { + public Component getTreeCellRendererComponent(JTree tree, + Object value, boolean selected, boolean expanded, + boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, selected, + expanded, leaf, row, hasFocus); + + DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value; + Object userObj = treeNode.getUserObject(); + if (userObj instanceof JSAPIUserObject) { + this.setText(((JSAPIUserObject) userObj).getDisplayText()); + this.setIcon(null); + } + return this; + } + + }; + + + private void initInterfaceNameList(JPanel interfacePanel) { + interfaceNameList = new JList(new DefaultListModel()); + UIScrollPane interfaceNamePanelScrollPane = new UIScrollPane(interfaceNameList); + interfaceNamePanelScrollPane.setPreferredSize(new Dimension(180, 200)); + interfacePanel.add( + this.createNamePane(Toolkit.i18nText("Fine-Design_Interface") + ":", interfaceNamePanelScrollPane), + BorderLayout.CENTER); + + interfaceNamePanelScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + initInterfaceNameModule(); + initInterfaceNameListSelectionListener(); + initInterfaceNameListMouseListener(); + } + + private void initInterfaceNameModule() { + moduleTree.setSelectionPath(moduleTree.getPathForRow(0)); + } + + private void setDescription(String interfaceName) { + StringBuilder il8Key = new StringBuilder(); + moduleTree.getSelectionPath().getPath(); + Object obj = moduleTree.getSelectionPath().getPath()[moduleTree.getSelectionPath().getPath().length - 1]; + Object userObject = ((DefaultMutableTreeNode) obj).getUserObject(); + if (userObject instanceof JSAPIUserObject) { + il8Key.append(JSAPITreeHelper.getDirectCategory(interfaceName)); + } + interfaceName = interfaceName.toUpperCase(); + if (!interfaceName.startsWith(SEPARATOR)) { + interfaceName = SEPARATOR + interfaceName; + } + il8Key.append(interfaceName); + descriptionTextArea.setText(Toolkit.i18nText(il8Key.toString())); + descriptionTextArea.moveCaretPosition(0); + } + + private void initInterfaceNameListSelectionListener() { + interfaceNameList.addListSelectionListener(new ListSelectionListener() { + + public void valueChanged(ListSelectionEvent evt) { + Object selectedValue = interfaceNameList.getSelectedValue(); + if (selectedValue == null) { + return; + } + String interfaceName = selectedValue.toString(); + if (!StringUtils.equals(interfaceName, currentValue)) { + setDescription(interfaceName); + doHelpDocumentSearch(); + currentValue = interfaceName; + } + + } + }); + } + + + private void initInterfaceNameListMouseListener() { + interfaceNameList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() >= 2) { + Object selectedValue = interfaceNameList.getSelectedValue(); + String interfaceName = selectedValue.toString(); + applyText(interfaceName); + } + } + }); + } + + private void applyText(String text) { + if (text == null || text.length() <= 0) { + return; + } + if (ifHasBeenWriten == 0) { + contentTextArea.setForeground(Color.black); + contentTextArea.setText(StringUtils.EMPTY); + ifHasBeenWriten = 1; + insertPosition = 0; + } + String textAll = contentTextArea.getText(); + currentPosition = contentTextArea.getCaretPosition(); + int insert = 0; + int current = 0; + if (insertPosition <= currentPosition) { + insert = insertPosition; + current = currentPosition; + } else { + insert = currentPosition; + current = insertPosition; + } + String beforeIndexOfInsertString = textAll.substring(0, insert); + String afterIndexofInsertString = textAll.substring(current); + contentTextArea.setText(beforeIndexOfInsertString + text + afterIndexofInsertString); + contentTextArea.getText(); + contentTextArea.requestFocus(); + insertPosition = contentTextArea.getCaretPosition(); + } + + private JPanel createNamePane(String name, JComponent comp) { + JPanel namePane = new JPanel(new BorderLayout(4, 4)); + namePane.add(new UILabel(name), BorderLayout.NORTH); + namePane.add(comp, BorderLayout.CENTER); + return namePane; + } + + private JPanel createTipsPane() { + JPanel tipsPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tipsPane.setLayout(new BorderLayout(4, 4)); + tipsPane.setBorder(BorderFactory.createEmptyBorder(30, 2, 0, 0)); + JPanel searchPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + searchPane.setLayout(new BorderLayout(4, 4)); + searchPane.add(keyWordTextField, BorderLayout.CENTER); + + //搜索按钮 + UIButton searchButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Search")); + searchButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String toFind = keyWordTextField.getText(); + search(toFind); + popTips(); + tipsList.requestFocusInWindow(); + } + }); + + keyWordTextField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + e.consume(); + String toFind = keyWordTextField.getText(); + search(toFind); + popTips(); + tipsList.requestFocusInWindow(); + } + } + }); + + searchPane.add(searchButton, BorderLayout.EAST); + tipsPane.add(searchPane, BorderLayout.NORTH); + + tipsList = new JList(tipsListModel); + tipsList.addMouseListener(tipsListMouseListener); + tipsList.addListSelectionListener(tipsListSelectionListener); + tipsList.addKeyListener(tipListKeyListener); + + return tipsPane; + } + + private void search(String key) { + tipsListModel.removeAllElements(); + tipsListModel.clear(); + key = key.replaceAll(StringUtils.BLANK, StringUtils.EMPTY); + ArrayList list = new ArrayList<>(); + if (!StringUtils.isEmpty(key)) { + List allNames = JSAPITreeHelper.getAllNames(); + for (String name : allNames) { + if (searchResult(key, name)) { + list.add(name); + } + } + String finalKey = key; + Collections.sort(list, new Comparator() { + @Override + public int compare(String o1, String o2) { + int result; + boolean o1StartWidth = o1.toLowerCase().startsWith(finalKey.toLowerCase()); + boolean o2StartWidth = o2.toLowerCase().startsWith(finalKey.toLowerCase()); + if (o1StartWidth) { + result = o2StartWidth ? o1.compareTo(o2) : -1; + } else { + result = o2StartWidth ? 1 : o1.compareTo(o2); + } + return result; + } + }); + for (String name : list) { + tipsListModel.addElement(name); + } + if (!tipsListModel.isEmpty()) { + tipsList.setSelectedIndex(0); + } + } + } + + private boolean searchResult(String key, String interfaceName) { + if (StringUtils.isBlank(key) || StringUtils.isBlank(interfaceName)) { + return false; + } + int length = key.length(); + String temp = interfaceName.toUpperCase(); + for (int i = 0; i < length; i++) { + String check = key.substring(i, i + 1); + int index = temp.indexOf(check.toUpperCase()); + if (index == -1) { + return false; + } else { + temp = temp.substring(index + 1); + } + } + return true; + } + + private void initPopTips() { + popupMenu = new JPopupMenu(); + JScrollPane tipsScrollPane = new JScrollPane(tipsList); + popupMenu.add(tipsScrollPane); + tipsScrollPane.setPreferredSize(new Dimension(220, 146)); + tipsScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + } + + private void popTips() { + popupMenu.show(keyWordTextField, 0, 23); + } + + private ListSelectionListener tipsListSelectionListener = new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + Object selectValue = tipsList.getSelectedValue(); + if (selectValue == null) { + return; + } + String interfaceName = selectValue.toString(); + fixInterfaceNameList(interfaceName); + } + }; + + private KeyListener tipListKeyListener = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + Object selectValue = tipsList.getSelectedValue(); + if (selectValue == null) { + return; + } + tipListValueSelectAction(selectValue.toString()); + if (popupMenu != null) { + popupMenu.setVisible(false); + } + contentTextArea.requestFocusInWindow(); + } + } + }; + + private void tipListValueSelectAction(String value) { + if (ifHasBeenWriten == 0) { + contentTextArea.setForeground(Color.black); + contentTextArea.setText(StringUtils.EMPTY); + } + contentTextArea.setForeground(Color.black); + currentPosition = contentTextArea.getCaretPosition(); + String output = value; + String textAll = contentTextArea.getText(); + String textReplaced; + int position = 0; + if (insertPosition <= currentPosition) { + textReplaced = textAll.substring(0, insertPosition) + output + textAll.substring(currentPosition); + position = insertPosition + output.length(); + } else { + textReplaced = textAll.substring(0, currentPosition) + output + textAll.substring(insertPosition); + position = currentPosition + output.length(); + } + contentTextArea.setText(textReplaced); + contentTextArea.setCaretPosition(position); + insertPosition = position; + ifHasBeenWriten = 1; + tipsListModel.removeAllElements(); + } + + private MouseListener tipsListMouseListener = new MouseAdapter() { + String singlePressContent; + + String doublePressContent; + + @Override + public void mousePressed(MouseEvent e) { + int index = tipsList.getSelectedIndex(); + if (index != -1) { + if (e.getClickCount() == 1) { + singlePressContent = (String) tipsListModel.getElementAt(index); + } else if (e.getClickCount() == 2) { + doublePressContent = (String) tipsListModel.getElementAt(index); + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { + int index = tipsList.getSelectedIndex(); + if (index != -1) { + if (e.getClickCount() == 1) { + if (ComparatorUtils.equals((String) tipsListModel.getElementAt(index), singlePressContent)) { + singleClickActuator(singlePressContent); + } + } else if (e.getClickCount() == 2) { + if (ComparatorUtils.equals((String) tipsListModel.getElementAt(index), doublePressContent)) { + doubleClickActuator(doublePressContent); + } + if (popupMenu != null) { + popupMenu.setVisible(false); + } + } + } + } + + private void singleClickActuator(String currentLineContent) { + setDescription(currentLineContent); + fixInterfaceNameList(currentLineContent); + } + + private void doubleClickActuator(String currentLineContent) { + tipListValueSelectAction(currentLineContent); + } + }; +} diff --git a/designer-base/src/main/java/com/fr/design/javascript/JavaScriptImplPane.java b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptImplPane.java index 158c05d1e..6a83ad3d2 100644 --- a/designer-base/src/main/java/com/fr/design/javascript/JavaScriptImplPane.java +++ b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptImplPane.java @@ -9,6 +9,8 @@ import com.fr.design.gui.itableeditorpane.UITableEditAction; import com.fr.design.gui.itableeditorpane.UITableEditorPane; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.hyperlink.AbstractHyperLinkPane; +import com.fr.design.javascript.jsapi.JSImplPopulateAction; +import com.fr.design.javascript.jsapi.JSImplUpdateAction; import com.fr.design.mainframe.DesignerContext; import com.fr.design.scrollruler.ModLineBorder; import com.fr.design.utils.gui.GUICoreUtils; @@ -17,10 +19,16 @@ import com.fr.js.JavaScriptImpl; import com.fr.stable.ParameterProvider; import com.fr.stable.StringUtils; -import javax.swing.*; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridLayout; +import javax.swing.BorderFactory; +import javax.swing.JPanel; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; -import java.awt.*; + import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -28,11 +36,11 @@ import java.util.List; public class JavaScriptImplPane extends AbstractHyperLinkPane { private static final int BOTTOM_BORDER = 12; private UITextField itemNameTextField; - private JSContentPane jsPane; + protected JSContentPane jsPane; private UITableEditorPane importedJsPane; private ReportletParameterViewPane parameterPane; private String[] defaultArgs; - + private boolean modal; public JavaScriptImplPane() { this(new String[0]); @@ -50,8 +58,57 @@ public class JavaScriptImplPane extends AbstractHyperLinkPane { initComponents(); } + public JavaScriptImplPane(String[] args, boolean modal) { + this.modal = modal; + this.defaultArgs = args; + initComponents(); + } + protected void initComponents() { - parameterPane = new ReportletParameterViewPane(getChartParaType(), getValueEditorPane(), getValueEditorPane()); + parameterPane = createParameterViewPane(); + importedJsPane = createImportedJsPane(); + importedJsPane.setPreferredSize(new Dimension(265, 150)); + + jsPane = createJSContentPane(defaultArgs); + jsPane.setBorder(BorderFactory.createTitledBorder(new ModLineBorder(ModLineBorder.TOP), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_JavaScript"))); + + parameterPane.setPreferredSize(new Dimension(265, 150)); + JPanel topPane = new JPanel(new GridLayout(1,2)); + topPane.add(importedJsPane); + topPane.add(parameterPane); + + topPane.setBorder(BorderFactory.createEmptyBorder(0, 0, BOTTOM_BORDER, 0)); + + this.setLayout(new BorderLayout()); + this.add(topPane, BorderLayout.NORTH); + this.add(jsPane, BorderLayout.CENTER); + + this.reLayoutForChart(); + } + + protected JSContentPane createJSContentPane(String[] defaultArgs){ + JSContentPane jsContentPane= new JSContentPane(defaultArgs,modal); + jsContentPane.setJsImplUpdateAction(new JSImplUpdateAction() { + @Override + public void update(JavaScriptImpl javaScript) { + if(javaScript != null){ + updateBean(javaScript); + } + } + }); + jsContentPane.setJsImplPopulateAction(new JSImplPopulateAction() { + @Override + public void populate(JavaScriptImpl javaScript) { + if(javaScript != null){ + populateBean(javaScript); + } + } + }); + return jsContentPane; + } + + protected ReportletParameterViewPane createParameterViewPane(){ + ReportletParameterViewPane parameterPane = new ReportletParameterViewPane(getChartParaType(), getValueEditorPane(), getValueEditorPane()); parameterPane.setBorder(BorderFactory.createTitledBorder(new ModLineBorder(ModLineBorder.TOP), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Parameter"))); parameterPane.addTableEditorListener(new TableModelListener() { public void tableChanged(TableModelEvent e) { @@ -72,7 +129,10 @@ public class JavaScriptImplPane extends AbstractHyperLinkPane { parameterChanger(list); } }); + return parameterPane; + } + protected UITableEditorPane createImportedJsPane(){ OneListTableModel model = new OneListTableModel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_ReportServerP_Import_JavaScript"), this) { public UITableEditAction[] createAction() { @@ -84,26 +144,12 @@ public class JavaScriptImplPane extends AbstractHyperLinkPane { return new AddJsAction(); } }; - importedJsPane = new UITableEditorPane(model); + UITableEditorPane importedJsPane = new UITableEditorPane(model); importedJsPane.setBorder(BorderFactory.createTitledBorder(new ModLineBorder(ModLineBorder.TOP), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_ReportServerP_Import_JavaScript"))); - importedJsPane.setPreferredSize(new Dimension(265, 150)); - jsPane = new JSContentPane(defaultArgs); - jsPane.setBorder(BorderFactory.createTitledBorder(new ModLineBorder(ModLineBorder.TOP), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_JavaScript"))); + return importedJsPane; + } - parameterPane.setPreferredSize(new Dimension(265, 150)); - JPanel topPane = GUICoreUtils.createBorderLayoutPane( - importedJsPane, BorderLayout.CENTER, - parameterPane, BorderLayout.EAST - ); - topPane.setPreferredSize(new Dimension(300, 150)); - topPane.setBorder(BorderFactory.createEmptyBorder(0, 0, BOTTOM_BORDER, 0)); - this.setLayout(new BorderLayout()); - this.add(topPane, BorderLayout.NORTH); - this.add(jsPane, BorderLayout.CENTER); - - this.reLayoutForChart(); - } /** * 参数改变 @@ -140,10 +186,10 @@ public class JavaScriptImplPane extends AbstractHyperLinkPane { if (javaScriptImpl == null) { javaScriptImpl = new JavaScriptImpl(); jsPane.reset(); - }else{ + } else { jsPane.populate(javaScriptImpl.getContent()); } - + jsPane.updateJSImpl(javaScriptImpl); int rowCount = javaScriptImpl.getJSImportSize(); String[] value = new String[rowCount]; for (int i = 0; i < rowCount; i++) { @@ -160,6 +206,7 @@ public class JavaScriptImplPane extends AbstractHyperLinkPane { public JavaScriptImpl updateBean() { JavaScriptImpl javaScript = new JavaScriptImpl(); updateBean(javaScript); + jsPane.updateJSImpl(javaScript); return javaScript; } diff --git a/designer-base/src/main/java/com/fr/design/javascript/NewJavaScriptImplPane.java b/designer-base/src/main/java/com/fr/design/javascript/NewJavaScriptImplPane.java new file mode 100644 index 000000000..23226c6dd --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/NewJavaScriptImplPane.java @@ -0,0 +1,23 @@ +package com.fr.design.javascript; + + +import com.fr.js.JavaScriptImpl; + + +public class NewJavaScriptImplPane extends JavaScriptImplPane { + public NewJavaScriptImplPane(String[] args) { + super(args); + } + + protected JSContentPane createJSContentPane(String[] defaultArgs){ + return new JSContentWithDescriptionPane(defaultArgs); + } + + public void populate(JavaScriptImpl javaScript) { + if (javaScript != null) { + populateBean(javaScript); + } else { + jsPane.reset(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/javascript/jsapi/CategoryTreeNodesUserObject.java b/designer-base/src/main/java/com/fr/design/javascript/jsapi/CategoryTreeNodesUserObject.java new file mode 100644 index 000000000..7b568eff7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/jsapi/CategoryTreeNodesUserObject.java @@ -0,0 +1,21 @@ +package com.fr.design.javascript.jsapi; + +import com.fr.design.i18n.Toolkit; + +public class CategoryTreeNodesUserObject implements JSAPIUserObject { + private String value; + + public CategoryTreeNodesUserObject(String value) { + this.value = value; + } + + @Override + public String getValue() { + return value; + } + + @Override + public String getDisplayText() { + return Toolkit.i18nText(value); + } +} diff --git a/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPITreeHelper.java b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPITreeHelper.java new file mode 100644 index 000000000..a5def0596 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPITreeHelper.java @@ -0,0 +1,155 @@ +package com.fr.design.javascript.jsapi; + +import com.fr.general.IOUtils; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.swing.tree.DefaultMutableTreeNode; + +public class JSAPITreeHelper { + private static final String JSAPI_PATH = "com/fr/design/javascript/jsapi/jsapi.json"; + private static final String CATEGORY_PATH = "com/fr/design/javascript/jsapi/category.json"; + private static JSONObject categoryJSON ; + private static JSONObject jsapiJSON ; + + static { + jsapiJSON = createJSON(JSAPI_PATH); + categoryJSON = createJSON(CATEGORY_PATH); + } + + private static JSONObject createJSON(String path) { + StringBuilder jsonString = new StringBuilder(StringUtils.EMPTY); + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(IOUtils.readResource(path)))) { + String s; + while ((s = bufferedReader.readLine()) != null) { + jsonString.append(s); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return new JSONObject(jsonString.toString()); + } + + + public static void createJSAPITree(DefaultMutableTreeNode rootNode) { + createJSAPITree(categoryJSON, rootNode); + } + + public static String getDirectCategory(String name) { + if (jsapiJSON != null) { + Iterator it = jsapiJSON.keys(); + while (it.hasNext()) { + String key = it.next(); + JSONArray nameArray = jsapiJSON.optJSONArray(key); + for (int i = 0; i < nameArray.length(); i++) { + if (StringUtils.equals(nameArray.getString(i), name)) { + return key; + } + } + } + } + return null; + } + + private static void createJSAPITree(JSONObject jsonObject, DefaultMutableTreeNode rootNode) { + if (jsonObject != null && rootNode != null) { + Iterator it = jsonObject.keys(); + while (it.hasNext()) { + String key = it.next(); + JSONObject subNode = jsonObject.optJSONObject(key); + if (subNode.size() == 0) { + rootNode.add(new DefaultMutableTreeNode(new CategoryTreeNodesUserObject(key))); + } else { + DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(new CategoryTreeNodesUserObject(key)); + rootNode.add(treeNode); + createJSAPITree(subNode, treeNode); + } + } + } + } + + private static List getAllSubNodes(String name) { + return getAllSubNodes(name, categoryJSON); + } + + public static List getAllNames() { + ArrayList result = new ArrayList<>(); + if (jsapiJSON != null) { + Iterator it = jsapiJSON.keys(); + while (it.hasNext()) { + String key = it.next(); + JSONArray nameArray = jsapiJSON.optJSONArray(key); + for (int i = 0; i < nameArray.length(); i++) { + result.add(nameArray.getString(i)); + } + } + } + return result; + } + + public static List getNames(String category) { + ArrayList result = new ArrayList<>(); + List subCategories = getAllSubNodes(category); + if (jsapiJSON != null) { + for (String subCategory : subCategories) { + if (jsapiJSON.containsKey(subCategory)) { + JSONArray nameArray = jsapiJSON.optJSONArray(subCategory); + for (int i = 0; i < nameArray.length(); i++) { + result.add(nameArray.getString(i)); + } + } + } + } + return result; + } + + private static List getAllSubNodes(String name, JSONObject jsonObject) { + ArrayList result = new ArrayList<>(); + if (jsonObject != null) { + Iterator it = jsonObject.keys(); + while (it.hasNext()) { + String key = it.next(); + JSONObject subNode = jsonObject.optJSONObject(key); + if (subNode.size() == 0) { + if (StringUtils.equals(key, name)) { + result.add(key); + return result; + } + } else { + if (StringUtils.equals(key, name)) { + result.add(key); + result.addAll(getAllSubNodes(subNode)); + return result; + } else { + result.addAll(getAllSubNodes(name, subNode)); + } + } + } + } + return result; + } + + private static List getAllSubNodes(JSONObject jsonObject) { + ArrayList result = new ArrayList<>(); + if (jsonObject != null) { + Iterator it = jsonObject.keys(); + while (it.hasNext()) { + String key = it.next(); + JSONObject subNode = jsonObject.optJSONObject(key); + if (subNode.size() == 0) { + result.add(key); + } else { + result.add(key); + result.addAll(getAllSubNodes(subNode)); + } + } + } + return result; + } +} diff --git a/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPIUserObject.java b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPIUserObject.java new file mode 100644 index 000000000..6790ec71e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSAPIUserObject.java @@ -0,0 +1,9 @@ +package com.fr.design.javascript.jsapi; + + +public interface JSAPIUserObject { + + String getValue(); + + String getDisplayText(); +} diff --git a/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplPopulateAction.java b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplPopulateAction.java new file mode 100644 index 000000000..c33d7fe0e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplPopulateAction.java @@ -0,0 +1,7 @@ +package com.fr.design.javascript.jsapi; + +import com.fr.js.JavaScriptImpl; + +public interface JSImplPopulateAction { + void populate(JavaScriptImpl javaScript); +} diff --git a/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplUpdateAction.java b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplUpdateAction.java new file mode 100644 index 000000000..b812d8b87 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/jsapi/JSImplUpdateAction.java @@ -0,0 +1,7 @@ +package com.fr.design.javascript.jsapi; + +import com.fr.js.JavaScriptImpl; + +public interface JSImplUpdateAction { + void update(JavaScriptImpl javaScript); +} diff --git a/designer-base/src/main/resources/com/fr/design/javascript/jsapi/category.json b/designer-base/src/main/resources/com/fr/design/javascript/jsapi/category.json new file mode 100644 index 000000000..ad1792976 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/javascript/jsapi/category.json @@ -0,0 +1,47 @@ +{ + "Fine-Design_JSAPI_Public_Module": { + "Fine-Design_JSAPI_Public_Module_Global": { + "Fine-Design_JSAPI_Public_Module_Global_Universal": {}, + "Fine-Design_JSAPI_Public_Module_Global_FR": {}, + "Fine-Design_JSAPI_Public_Module_Global_FS": {}, + "Fine-Design_JSAPI_Public_Module_Global_Mobile": {} + }, + "Fine-Design_JSAPI_Public_Module_Widget": { + "Fine-Design_JSAPI_Public_Module_Widget_Get": {}, + "Fine-Design_JSAPI_Public_Module_Widget_Universal": {}, + "Fine-Design_JSAPI_Public_Module_Date_Widget_Peculiar": {}, + "Fine-Design_JSAPI_Public_Module_Button_Widget_Peculiar": {}, + "Fine-Design_JSAPI_Public_Module_Combobox_Widget_Peculiar": {} + }, + "Fine-Design_JSAPI_Public_Module_Table": { + "Fine-Design_JSAPI_Public_Module_Table_Marquee": {}, + "Fine-Design_JSAPI_Public_Module_Table_Scrollbar": {}, + "Fine-Design_JSAPI_Public_Module_Table_Cell_Style": {}, + "Fine-Design_JSAPI_Public_Module_Table_Row_Height_Col_Width": {}, + "Fine-Design_JSAPI_Public_Module_Table_Cell_Value": {}, + "Fine-Design_JSAPI_Public_Module_Table_Cell_Radius": {} + }, + "Fine-Design_JSAPI_Public_Module_Toolbar": { + "Fine-Design_JSAPI_Public_Module_Toolbar_Email_Button": {} + }, + "Fine-Design_JSAPI_Public_Module_Report_Page": { + "Fine-Design_JSAPI_Public_Module_Report_Page_Jump": {}, + "Fine-Design_JSAPI_Public_Module_Report_Page_Number_Get": {} + }, + "Fine-Design_JSAPI_Public_Module_Report_Export": {} + }, + "Fine-Design_JSAPI_Cpt": { + "Fine-Design_JSAPI_Cpt_Page_Preview": { + "Fine-Design_JSAPI_Cpt_Page_Preview_Folding_Tree": {} + }, + "Fine-Design_JSAPI_Cpt_Write_Preview": {}, + "Fine-Design_JSAPI_Cpt_View_Preview": { + "Fine-Design_JSAPI_Cpt_View_Preview_Report_Location": {} + } + }, + "Fine-Design_JSAPI_Form": { + "Fine-Design_JSAPI_Form_Component_Get": {}, + "Fine-Design_JSAPI_Form_Component_Universal": {}, + "Fine-Design_JSAPI_Form_Component_Tab": {} + } +} \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/javascript/jsapi/jsapi.json b/designer-base/src/main/resources/com/fr/design/javascript/jsapi/jsapi.json new file mode 100644 index 000000000..e268f70e1 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/javascript/jsapi/jsapi.json @@ -0,0 +1,33 @@ +{ + "Fine-Design_JSAPI_Public_Module_Global_Universal": ["_g()", "getParameterContainer", "parameterCommit", "loadContentPane", "getPreviewType"], + "Fine-Design_JSAPI_Public_Module_Global_FR": [ "servletURL", "serverURL", "server", "fineServletURL", "SessionMgr.getSessionID", "showDialog", "closeDialog", + "doHyperlinkByGet", "doHyperlinkByPost", "doURLPrint", "Msg", "remoteEvaluate", "jsonEncode", "jsonDecode", + "ajax", "isEmpty", "isArray", "cellStr2ColumnRow", "columnRow2CellStr"], + "Fine-Design_JSAPI_Public_Module_Global_FS": ["signOut", "tabPane.closeActiveTab", "tabPane.addItem"], + "Fine-Design_JSAPI_Public_Module_Global_Mobile": ["location", "Mobile.getDeviceInfo"], + "Fine-Design_JSAPI_Public_Module_Widget_Get": ["this", "this.options.form", "getWidgetByName"], + "Fine-Design_JSAPI_Public_Module_Widget_Universal": ["getValue", "getText", "setValue", "visible", "invisible", "setVisible", "isVisible", "setEnable", "isEnabled", + "reset", "getType", "setWaterMark", "fireEvent", "setPopupStyle"], + "Fine-Design_JSAPI_Public_Module_Date_Widget_Peculiar":["setMaxAndMinDate"], + "Fine-Design_JSAPI_Public_Module_Button_Widget_Peculiar":["doClick"], + "Fine-Design_JSAPI_Public_Module_Combobox_Widget_Peculiar":["setName4Empty"], + "Fine-Design_JSAPI_Public_Module_Table_Marquee":["startMarquee", "stopMarquee"], + "Fine-Design_JSAPI_Public_Module_Table_Scrollbar":["setHScrollBarVisible", "setVScrollBarVisible"], + "Fine-Design_JSAPI_Public_Module_Table_Cell_Style":["addEffect"], + "Fine-Design_JSAPI_Public_Module_Table_Row_Height_Col_Width":["setRowHeight", "setColWidth"], + "Fine-Design_JSAPI_Public_Module_Table_Cell_Value":["getCellValue", "setCellValue"], + "Fine-Design_JSAPI_Public_Module_Table_Cell_Radius":["setCellRadius"], + "Fine-Design_JSAPI_Public_Module_Toolbar":["toolBarFloat", "setStyle","getToolbar"], + "Fine-Design_JSAPI_Public_Module_Toolbar_Email_Button":["changeFormat"], + "Fine-Design_JSAPI_Public_Module_Report_Page_Jump":["gotoPreviousPage", "gotoNextPage", "gotoLastPage", "gotoFirstPage", "gotoPage"], + "Fine-Design_JSAPI_Public_Module_Report_Page_Number_Get":["getCurrentPageIndex", "getReportTotalPage", "currentPageIndex", "reportTotalPage"], + "Fine-Design_JSAPI_Public_Module_Report_Export":["exportReportToExcel", "exportReportToImage", "exportReportToPDF", "exportReportToWord"], + "Fine-Design_JSAPI_Cpt_Page_Preview_Folding_Tree":["expandNodeLayer", "collapseNodeLayer", "expandAllNodeLayer", "collapseAllNodeLayer"], + "Fine-Design_JSAPI_Cpt_Write_Preview":["getWidgetByCell", "appendReportRC", "appendReportRow", + "deleteReportRC", "deleteRows", "refreshAllSheets", "loadSheetByIndex", "loadSheetByName", "isDirtyPage", + "isAutoStash", "writeReport", "verifyAndWriteReport", "verifyReport", "importExcel", "importExcel_Clean", + "importExcel_Append", "importExcel_Cover", "stash", "clear"], + "Fine-Design_JSAPI_Cpt_View_Preview_Report_Location":["centerReport"], + "Fine-Design_JSAPI_Form_Component_Get":["getAllWidgets"], + "Fine-Design_JSAPI_Form_Component_Tab":["showCardByIndex", "showCardByIndex", "getShowIndex", "setTitleVisible"] +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java b/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java index 095d011f7..056707896 100644 --- a/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java +++ b/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java @@ -89,7 +89,7 @@ public class ListenerEditPane extends BasicBeanPane { card = new CardLayout(); hyperlinkPane = FRGUIPaneFactory.createCardLayout_S_Pane(); hyperlinkPane.setLayout(card); - JavaScriptImplPane javaScriptPane = new JavaScriptImplPane(defaultArgs); + JavaScriptImplPane javaScriptPane = new JavaScriptImplPane(defaultArgs,true); hyperlinkPane.add(JS, javaScriptPane); // 提交入库 List dbManiList = new ArrayList(); From a6c350c17c78a831886f69fe450b3bf8acca1624 Mon Sep 17 00:00:00 2001 From: pengda Date: Thu, 6 Jan 2022 16:25:52 +0800 Subject: [PATCH 17/19] =?UTF-8?q?REPORT-58833=20js=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../javascript/jsapi/JSAPITreeHelperTest.java | 31 +++++++++++++++++++ .../fr/design/javascript/jsapi/category.json | 17 ++++++++++ .../com/fr/design/javascript/jsapi/jsapi.json | 8 +++++ 3 files changed, 56 insertions(+) create mode 100644 designer-base/src/test/java/com/fr/design/javascript/jsapi/JSAPITreeHelperTest.java create mode 100644 designer-base/src/test/resources/com/fr/design/javascript/jsapi/category.json create mode 100644 designer-base/src/test/resources/com/fr/design/javascript/jsapi/jsapi.json diff --git a/designer-base/src/test/java/com/fr/design/javascript/jsapi/JSAPITreeHelperTest.java b/designer-base/src/test/java/com/fr/design/javascript/jsapi/JSAPITreeHelperTest.java new file mode 100644 index 000000000..e0d5ae7c9 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/javascript/jsapi/JSAPITreeHelperTest.java @@ -0,0 +1,31 @@ +package com.fr.design.javascript.jsapi; + +import java.util.List; +import javax.swing.tree.DefaultMutableTreeNode; +import junit.framework.TestCase; + +public class JSAPITreeHelperTest extends TestCase { + public void testGetName(){ + List names = JSAPITreeHelper.getNames("Fine-Design_JSAPI_Public_Module_Toolbar"); + assertEquals(names.size(),4); + assertTrue(names.contains( "toolBarFloat")); + assertTrue(names.contains( "setStyle")); + assertTrue(names.contains( "getToolbar")); + assertTrue(names.contains( "changeFormat")); + List allNames = JSAPITreeHelper.getAllNames(); + assertEquals(allNames.size(),16); + } + + public void testGetDirectCategory(){ + String directCategory = JSAPITreeHelper.getDirectCategory("_g()"); + assertEquals(directCategory,"Fine-Design_JSAPI_Public_Module_Global_Universal"); + directCategory = JSAPITreeHelper.getDirectCategory("showCardByIndex"); + assertEquals(directCategory,"Fine-Design_JSAPI_Form_Component_Tab"); + } + + public void testCreateJSAPITree(){ + DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(); + JSAPITreeHelper.createJSAPITree(rootNode); + assertEquals(2,rootNode.getChildCount()); + } +} diff --git a/designer-base/src/test/resources/com/fr/design/javascript/jsapi/category.json b/designer-base/src/test/resources/com/fr/design/javascript/jsapi/category.json new file mode 100644 index 000000000..2d0e50ba0 --- /dev/null +++ b/designer-base/src/test/resources/com/fr/design/javascript/jsapi/category.json @@ -0,0 +1,17 @@ +{ + "Fine-Design_JSAPI_Public_Module": { + "Fine-Design_JSAPI_Public_Module_Global": { + "Fine-Design_JSAPI_Public_Module_Global_Universal": {}, + "Fine-Design_JSAPI_Public_Module_Global_Mobile": {} + }, + "Fine-Design_JSAPI_Public_Module_Widget": { + "Fine-Design_JSAPI_Public_Module_Date_Widget_Peculiar": {} + }, + "Fine-Design_JSAPI_Public_Module_Toolbar": { + "Fine-Design_JSAPI_Public_Module_Toolbar_Email_Button": {} + } + }, + "Fine-Design_JSAPI_Form": { + "Fine-Design_JSAPI_Form_Component_Tab": {} + } +} \ No newline at end of file diff --git a/designer-base/src/test/resources/com/fr/design/javascript/jsapi/jsapi.json b/designer-base/src/test/resources/com/fr/design/javascript/jsapi/jsapi.json new file mode 100644 index 000000000..4ff0a321e --- /dev/null +++ b/designer-base/src/test/resources/com/fr/design/javascript/jsapi/jsapi.json @@ -0,0 +1,8 @@ +{ + "Fine-Design_JSAPI_Public_Module_Global_Universal": ["_g()", "getParameterContainer", "parameterCommit", "loadContentPane", "getPreviewType"], + "Fine-Design_JSAPI_Public_Module_Global_Mobile": ["location", "Mobile.getDeviceInfo"], + "Fine-Design_JSAPI_Public_Module_Date_Widget_Peculiar":["setMaxAndMinDate"], + "Fine-Design_JSAPI_Public_Module_Toolbar":["toolBarFloat", "setStyle","getToolbar"], + "Fine-Design_JSAPI_Public_Module_Toolbar_Email_Button":["changeFormat"], + "Fine-Design_JSAPI_Form_Component_Tab":["showCardByIndex", "showCardByIndex", "getShowIndex", "setTitleVisible"] +} \ No newline at end of file From 510117c2a75a9bcb6229832a3bc84f08c047e92c Mon Sep 17 00:00:00 2001 From: kerry Date: Thu, 6 Jan 2022 17:17:44 +0800 Subject: [PATCH 18/19] =?UTF-8?q?REPORT-64445=20=E6=96=B0=E8=80=81?= =?UTF-8?q?=E8=87=AA=E9=80=82=E5=BA=94=E9=85=8D=E7=BD=AE=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gui/ilable/UIAutoChangeLineLabel.java | 78 ++++ .../report/fit/AdaptiveFrmFitAttrModel.java | 6 +- .../fr/design/report/fit/BaseFitAttrPane.java | 130 +----- .../fr/design/report/fit/FitAttrModel.java | 9 + .../com/fr/design/report/fit/FitType.java | 11 + .../report/fit/FormFitAttrModelType.java | 128 ++++++ .../design/report/fit/FormFitConfigPane.java | 59 +++ .../fr/design/report/fit/FrmFitAttrModel.java | 9 +- .../design/report/fit/NewFitPreviewPane.java | 71 ++++ .../report/fit/ReportFitConfigPane.java | 172 ++++++++ .../com/fr/design/fit/FormFitAttrAction.java | 85 ++++ .../com/fr/design/fit/FormFitAttrPane.java | 377 ++++++++++++++++++ .../java/com/fr/design/mainframe/JForm.java | 14 +- .../FRAbsoluteBodyLayoutDefinePane.java | 110 +---- .../layout/FRAbsoluteLayoutDefinePane.java | 54 +-- .../layout/FRFitLayoutDefinePane.java | 118 +----- 16 files changed, 1032 insertions(+), 399 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/gui/ilable/UIAutoChangeLineLabel.java create mode 100644 designer-base/src/main/java/com/fr/design/report/fit/FormFitAttrModelType.java create mode 100644 designer-base/src/main/java/com/fr/design/report/fit/FormFitConfigPane.java create mode 100644 designer-base/src/main/java/com/fr/design/report/fit/NewFitPreviewPane.java create mode 100644 designer-base/src/main/java/com/fr/design/report/fit/ReportFitConfigPane.java create mode 100644 designer-form/src/main/java/com/fr/design/fit/FormFitAttrAction.java create mode 100644 designer-form/src/main/java/com/fr/design/fit/FormFitAttrPane.java diff --git a/designer-base/src/main/java/com/fr/design/gui/ilable/UIAutoChangeLineLabel.java b/designer-base/src/main/java/com/fr/design/gui/ilable/UIAutoChangeLineLabel.java new file mode 100644 index 000000000..d2bb0450b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/ilable/UIAutoChangeLineLabel.java @@ -0,0 +1,78 @@ +package com.fr.design.gui.ilable; + +import javax.swing.JLabel; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.util.ArrayList; +import java.util.List; + +public class UIAutoChangeLineLabel extends JLabel { + private final String text; + private final int width; + + + public UIAutoChangeLineLabel(String text, int width) { + super(text); + this.text = text; + this.width = width; + } + + + @Override + public void doLayout() { + super.doLayout(); + this.setText(wrapperHtmlText()); + } + + private String wrapperHtmlText() { + List stringList = autoChangeLine(this.getWidth()); + StringBuilder builder = new StringBuilder(""); + for (String s : stringList) { + //用THML标签进行拼接,以实现自动换行 + builder.append(s).append("
"); + } + builder.append(""); + return builder.toString(); + } + + private List autoChangeLine(int width) { + List result = new ArrayList<>(); + if (width <= 0) { + result.add(this.text); + } else { + + char[] chars = this.text.toCharArray(); + //获取字体计算大小 + FontMetrics fontMetrics = this.getFontMetrics(this.getFont()); + int start = 0; + int len = 0; + while (start + len < this.text.length()) { + while (true) { + len++; + if (start + len > this.text.length()) + break; + if (fontMetrics.charsWidth(chars, start, len) + > width) { + break; + } + } + result.add(String.copyValueOf(chars, start, len - 1)); + start = start + len - 1; + len = 0; + } + if (this.text.length() - start > 0) { + result.add(String.copyValueOf(chars, start, this.text.length() - start)); + } + } + return result; + } + + + @Override + public Dimension getPreferredSize() { + Dimension preferredSize = super.getPreferredSize(); + List stringList = autoChangeLine(width); + FontMetrics fontMetrics = this.getFontMetrics(this.getFont()); + return new Dimension(preferredSize.width, fontMetrics.getHeight() * stringList.size()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/report/fit/AdaptiveFrmFitAttrModel.java b/designer-base/src/main/java/com/fr/design/report/fit/AdaptiveFrmFitAttrModel.java index 9e60c6cc8..8c5e8858a 100644 --- a/designer-base/src/main/java/com/fr/design/report/fit/AdaptiveFrmFitAttrModel.java +++ b/designer-base/src/main/java/com/fr/design/report/fit/AdaptiveFrmFitAttrModel.java @@ -13,11 +13,7 @@ import com.fr.report.fit.ReportFitAttr; public class AdaptiveFrmFitAttrModel extends AbstractFitAttrModelProvider { public FitType[] getFitTypes() { - return new FitType[]{ - FitType.DOUBLE_FIT, - FitType.HORIZONTAL_FIT, - FitType.NOT_FIT - }; + return new FitType[0]; } public String getFitName() { diff --git a/designer-base/src/main/java/com/fr/design/report/fit/BaseFitAttrPane.java b/designer-base/src/main/java/com/fr/design/report/fit/BaseFitAttrPane.java index 2c38d597c..48d6a5686 100644 --- a/designer-base/src/main/java/com/fr/design/report/fit/BaseFitAttrPane.java +++ b/designer-base/src/main/java/com/fr/design/report/fit/BaseFitAttrPane.java @@ -2,27 +2,17 @@ package com.fr.design.report.fit; import com.fr.design.ExtraDesignClassManager; import com.fr.design.beans.BasicBeanPane; -import com.fr.design.gui.ibutton.UIRadioButton; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; -import com.fr.design.i18n.DesignSizeI18nManager; import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.report.fit.menupane.FitPreviewPane; -import com.fr.design.report.fit.menupane.FitRadioGroup; -import com.fr.design.report.fit.menupane.FontRadioGroup; import com.fr.design.report.fit.provider.FitAttrModelProvider; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.general.ComparatorUtils; import com.fr.report.fit.ReportFitAttr; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.ItemListener; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.Set; import java.util.stream.Collectors; @@ -35,11 +25,8 @@ public abstract class BaseFitAttrPane extends BasicBeanPane { protected UILabel belowSetLabel; protected UIComboBox itemChoose; protected java.util.List fitAttrModelList = new ArrayList<>(); + private ReportFitConfigPane fitConfigPane; - public FontRadioGroup fontRadioGroup; - public FitRadioGroup adaptRadioGroup; - public JPanel attrJPanel; - public FitPreviewPane previewJPanel; public FitAttrModel fitAttrModel; private static final int BELOW_SET_COMPONENT_HSPACE = 8; @@ -64,128 +51,27 @@ public abstract class BaseFitAttrPane extends BasicBeanPane { protected void populateModel(FitAttrModel fitAttrModel) { this.fitAttrModel = fitAttrModel; - if (attrJPanel != null) { - contentJPanel.remove(attrJPanel); + if (fitConfigPane != null) { + contentJPanel.remove(fitConfigPane); } - if (previewJPanel != null) { - contentJPanel.remove(previewJPanel); - } - - fontRadioGroup = new FontRadioGroup(); - adaptRadioGroup = new FitRadioGroup(); - initAttrJPanel(); - initPreviewJPanel(); + this.fitConfigPane = fitAttrModel instanceof CptFitAttrModel ? new ReportFitConfigPane(fitAttrModel, true) : new FormFitConfigPane(fitAttrModel, true); + contentJPanel.add(fitConfigPane); } - - protected void initAttrJPanel() { - int colCount = fitAttrModel.getFitTypes().length + 1; - Component[][] components = new Component[2][colCount]; - initFitRadioGroup(fontRadioGroup, i18nText("Fine-Designer_Fit-Font"), new String[]{i18nText("Fine-Designer_Fit"), i18nText("Fine-Designer_Fit-No")}, components[0]); - initFitRadioGroup(adaptRadioGroup, fitAttrModel.getFitName(), Arrays.stream(fitAttrModel.getFitTypes()).map(FitType::description).toArray(String[]::new), components[1]); - - double[] rowSize = new double[2]; - double[] columnSize = new double[colCount]; - for (int i = 0; i < rowSize.length; i++) { - rowSize[i] = 20; - } - for (int i = 0; i < columnSize.length; i++) { - if (i == 0) { - columnSize[i] = DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.report.fit.firstColumn").getWidth(); - } else { - columnSize[i] = DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.report.fit.column").getWidth(); - } - } - - attrJPanel = TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize); - attrJPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 10, 0)); - contentJPanel.add(attrJPanel); - } - - private void initFitRadioGroup(FitRadioGroup fitRadioGroup, String name, String[] options, Component[] components) { - components[0] = new UILabel(name); - for (int i = 0; i < options.length; i++) { - - if (options[i] != null) { - UIRadioButton fontFitRadio = new UIRadioButton(options[i]); - fitRadioGroup.add(fontFitRadio); - components[i + 1] = fontFitRadio; - } else { - components[i + 1] = null; - } - } - fitRadioGroup.addActionListener(getPreviewActionListener()); - } - - protected ActionListener getPreviewActionListener() { - return new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - refreshPreviewJPanel(); - } - }; - } - - protected void refreshPreviewJPanel() { - String previewIndex = getPreviewIndex(); - previewJPanel.refreshPreview(previewIndex, fontRadioGroup.isEnabled()); - } - - protected String getPreviewIndex() { - return getStateInPC(adaptRadioGroup.getSelectRadioIndex()) + "" + fontRadioGroup.getSelectRadioIndex(); - } - - protected void initPreviewJPanel() { - previewJPanel = new FitPreviewPane(); - previewJPanel.setBorder(BorderFactory.createEmptyBorder(0, getPreviewJPanelLeft(), 0, 0)); - contentJPanel.add(previewJPanel); - } - - private int getPreviewJPanelLeft() { - int left = 0; - if (belowSetLabel.getPreferredSize() != null) { - left = belowSetLabel.getPreferredSize().width + BELOW_SET_COMPONENT_HSPACE; - } - return left; - } - - protected int getStateInPC(int index) { - FitType[] fitTypes = fitAttrModel.getFitTypes(); - return fitTypes[index].getState(); - } - - protected int getOptionIndex(int state) { - FitType[] fitTypes = fitAttrModel.getFitTypes(); - for (int i = 0; i < fitTypes.length; i++) { - if (ComparatorUtils.equals(state, fitTypes[i].getState())) { - return i; - } - } - return 0; - } - - @Override public void populateBean(ReportFitAttr ob) { - fontRadioGroup.selectIndexButton(ob.isFitFont() ? 0 : 1); - adaptRadioGroup.selectIndexButton(getOptionIndex(ob.fitStateInPC())); - refreshPreviewJPanel(); + this.fitConfigPane.populateBean(ob); } @Override public ReportFitAttr updateBean() { - ReportFitAttr reportFitAttr = new ReportFitAttr(); - reportFitAttr.setFitFont(fontRadioGroup.isFontFit()); - reportFitAttr.setFitStateInPC(getStateInPC(adaptRadioGroup.getSelectRadioIndex())); - return reportFitAttr; + return this.fitConfigPane.updateBean(); } public void setEnabled(boolean enabled) { super.setEnabled(enabled); - fontRadioGroup.setEnabled(enabled); - adaptRadioGroup.setEnabled(enabled); - refreshPreviewJPanel(); + this.fitConfigPane.setEnabled(enabled); } @Override diff --git a/designer-base/src/main/java/com/fr/design/report/fit/FitAttrModel.java b/designer-base/src/main/java/com/fr/design/report/fit/FitAttrModel.java index 1d1ac02f0..2a834eebd 100644 --- a/designer-base/src/main/java/com/fr/design/report/fit/FitAttrModel.java +++ b/designer-base/src/main/java/com/fr/design/report/fit/FitAttrModel.java @@ -3,6 +3,8 @@ package com.fr.design.report.fit; import com.fr.design.mainframe.JTemplate; import com.fr.report.fit.ReportFitAttr; +import java.util.Arrays; + public interface FitAttrModel { /** * @Description 名称,比如:普通报表、决策报表等 @@ -19,6 +21,12 @@ public interface FitAttrModel { **/ FitType[] getFitTypes(); + /** + * @Description 表格自适应选项名称集合 + **/ + default String[] getFitTypeNames(){ + return Arrays.stream(getFitTypes()).map(FitType::description).toArray(String[]::new); + } /** * @Description 获取全局的自适应属性 @@ -41,4 +49,5 @@ public interface FitAttrModel { * @param: jTemplate **/ boolean isAvailable(JTemplate jTemplate); + } diff --git a/designer-base/src/main/java/com/fr/design/report/fit/FitType.java b/designer-base/src/main/java/com/fr/design/report/fit/FitType.java index 00aceb6eb..dd4888b4e 100644 --- a/designer-base/src/main/java/com/fr/design/report/fit/FitType.java +++ b/designer-base/src/main/java/com/fr/design/report/fit/FitType.java @@ -60,6 +60,17 @@ public enum FitType { return DEFAULT; } + public static FitType parseByFitState(int state) { + + for (FitType attrState : values()) { + if (attrState.state == state) { + return attrState; + } + } + + return DEFAULT; + } + public int getState() { return this.state; } diff --git a/designer-base/src/main/java/com/fr/design/report/fit/FormFitAttrModelType.java b/designer-base/src/main/java/com/fr/design/report/fit/FormFitAttrModelType.java new file mode 100644 index 000000000..a77566442 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/report/fit/FormFitAttrModelType.java @@ -0,0 +1,128 @@ +package com.fr.design.report.fit; + + +import com.fr.design.designer.properties.items.Item; +import com.fr.form.fit.common.LightTool; +import com.fr.form.main.BodyScaleAttrTransformer; +import com.fr.form.main.Form; +import com.fr.form.ui.container.WAbsoluteLayout; +import com.fr.form.ui.container.WBodyLayoutType; +import com.fr.form.ui.container.WFitLayout; + +public enum FormFitAttrModelType { + PLAIN_FORM_FIT_ATTR_MODEL { + @Override + public FitAttrModel getFitAttrModel() { + return new FrmFitAttrModel(); + } + + @Override + public Item[] getFitLayoutScaleAttr() { + return new Item[]{ + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Attr_Bidirectional_Adaptive"), WFitLayout.STATE_FULL), + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Attr_Horizontal_Adaptive"), WFitLayout.STATE_ORIGIN)}; + + } + + @Override + public Item[] getAbsoluteLayoutSaleAttr() { + return new Item[]{ + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Scaling_Mode_Fit"), WAbsoluteLayout.STATE_FIT), + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Scaling_Mode_Fixed"), WAbsoluteLayout.STATE_FIXED) + }; + } + + + @Override + public int getScaleAttrShowIndex(WFitLayout wFitLayout) { + int scale = wFitLayout.getScaleAttr(); + if (wFitLayout.getBodyLayoutType() == WBodyLayoutType.FIT) { + return BodyScaleAttrTransformer.getFitBodyCompStateFromScaleAttr(scale); + } else { + return BodyScaleAttrTransformer.getAbsoluteBodyCompStateFromScaleAttr(scale); + } + } + + @Override + public int parseScaleAttrFromShowIndex(int showIndex, WBodyLayoutType wBodyLayoutType) { + if (wBodyLayoutType == WBodyLayoutType.FIT) { + if (showIndex == 0) { + return WFitLayout.SCALE_FULL; + } else { + return WFitLayout.SCALE_HOR; + } + } else { + if (showIndex == 0) { + return WFitLayout.SCALE_FULL; + } else { + return WFitLayout.SCALE_NO; + } + } + } + + + }, + NEW_FORM_FIT_ATTR_MODEL { + @Override + public FitAttrModel getFitAttrModel() { + return new AdaptiveFrmFitAttrModel(); + } + + @Override + public Item[] getFitLayoutScaleAttr() { + return new Item[]{ + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Attr_Bidirectional_Adaptive"), WFitLayout.STATE_FULL), + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Attr_Horizontal_Adaptive"), WFitLayout.STATE_ORIGIN), + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Scaling_Mode_Fixed"), 2)}; + } + + @Override + public Item[] getAbsoluteLayoutSaleAttr() { + return new Item[]{ + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Attr_Bidirectional_Adaptive"), WFitLayout.STATE_FULL), + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Attr_Horizontal_Adaptive"), WFitLayout.STATE_ORIGIN), + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Scaling_Mode_Fixed"), 2)}; + } + + + @Override + public int getScaleAttrShowIndex(WFitLayout wFitLayout) { + int scale = wFitLayout.getScaleAttr(); + if (scale == WFitLayout.SCALE_NO) { + return 2; + } else if (scale == WFitLayout.SCALE_HOR) { + return 1; + } else { + return 0; + } + } + + @Override + public int parseScaleAttrFromShowIndex(int showIndex, WBodyLayoutType wBodyLayoutType) { + if (showIndex == 0) { + return WFitLayout.SCALE_FULL; + } else if (showIndex == 1) { + return WFitLayout.SCALE_HOR; + } else { + return WFitLayout.SCALE_NO; + } + } + + + }; + + public abstract FitAttrModel getFitAttrModel(); + + public abstract Item[] getFitLayoutScaleAttr(); + + public abstract Item[] getAbsoluteLayoutSaleAttr(); + + public abstract int getScaleAttrShowIndex(WFitLayout wFitLayout); + + public abstract int parseScaleAttrFromShowIndex(int showIndex, WBodyLayoutType wBodyLayoutType); + + + public static FormFitAttrModelType parse(Form form) { + return LightTool.containNewFormFlag(form) ? NEW_FORM_FIT_ATTR_MODEL : PLAIN_FORM_FIT_ATTR_MODEL; + } +} diff --git a/designer-base/src/main/java/com/fr/design/report/fit/FormFitConfigPane.java b/designer-base/src/main/java/com/fr/design/report/fit/FormFitConfigPane.java new file mode 100644 index 000000000..08b70cb77 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/report/fit/FormFitConfigPane.java @@ -0,0 +1,59 @@ +package com.fr.design.report.fit; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.report.fit.ReportFitAttr; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; + +public class FormFitConfigPane extends ReportFitConfigPane { + private static final int DEFAULT_ITEM = 0; + private static final int CUSTOM_ITEM = 1; + + public FormFitConfigPane(FitAttrModel fitAttrModel) { + this(fitAttrModel, false); + } + + public FormFitConfigPane(FitAttrModel fitAttrModel, boolean globalConfig) { + super(fitAttrModel, globalConfig); + } + + protected JPanel initECConfigPane() { + JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + if (fitAttrModel.getFitTypeNames().length != 0) { + Component[] ecComponents = new Component[fitAttrModel.getFitTypeNames().length + 1]; + initRadioGroup(ecConfigRadioGroup, fitAttrModel.getFitName(), fitAttrModel.getFitTypeNames(), ecComponents); + jPanel.add(createSubAttrPane(ecComponents), BorderLayout.CENTER); + jPanel.add(createTipPane(), BorderLayout.SOUTH); + } + return jPanel; + } + + private JPanel createTipPane() { + JPanel jPanel = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); + UILabel label1 = new UILabel(Toolkit.i18nText("Fine-Design_Form_PC_FIT_Config_Tip1")); + jPanel.add(label1); + label1.setForeground(Color.lightGray); + UILabel label2 = new UILabel(Toolkit.i18nText("Fine-Design_Form_PC_FIT_Config_Tip2")); + jPanel.add(label2); + label2.setForeground(Color.lightGray); + return jPanel; + } + + protected void refreshPreviewJPanel() { + previewJPanel.refreshPreview(fontRadioGroup.isFontFit()); + } + + protected void populateECConfigRadioGroup(int fitStateInPC) { + ecConfigRadioGroup.selectIndexButton(fitStateInPC == 0 ? DEFAULT_ITEM : CUSTOM_ITEM); + } + + protected void updateECConfigRadioGroup(ReportFitAttr reportFitAttr) { + reportFitAttr.setFitStateInPC(ecConfigRadioGroup.getSelectRadioIndex()); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/report/fit/FrmFitAttrModel.java b/designer-base/src/main/java/com/fr/design/report/fit/FrmFitAttrModel.java index c4bdaf6de..81ee474de 100644 --- a/designer-base/src/main/java/com/fr/design/report/fit/FrmFitAttrModel.java +++ b/designer-base/src/main/java/com/fr/design/report/fit/FrmFitAttrModel.java @@ -17,7 +17,7 @@ public class FrmFitAttrModel implements FitAttrModel { @Override public String getFitName() { - return Toolkit.i18nText("Fine-Designer_Fit-Element"); + return Toolkit.i18nText("Fine-Design_Form_PC_FIT_Config_EC_Label"); } public FitType[] getFitTypes() { @@ -29,6 +29,13 @@ public class FrmFitAttrModel implements FitAttrModel { }; } + @Override + public String[] getFitTypeNames() { + return new String[]{ + Toolkit.i18nText("Fine-Designer_Fit-Default"), Toolkit.i18nText("Fine-Design_Basic_Custom") + }; + } + @Override public ReportFitAttr getGlobalReportFitAttr() { return ReportFitConfig.getInstance().getFrmFitAttr(); diff --git a/designer-base/src/main/java/com/fr/design/report/fit/NewFitPreviewPane.java b/designer-base/src/main/java/com/fr/design/report/fit/NewFitPreviewPane.java new file mode 100644 index 000000000..8b0710de3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/report/fit/NewFitPreviewPane.java @@ -0,0 +1,71 @@ +package com.fr.design.report.fit; + +import com.fr.base.GraphHelper; +import com.fr.general.FRFont; + +import javax.swing.JPanel; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; + + +public class NewFitPreviewPane extends JPanel { + private boolean fitFont = false; + private FitType fitType = FitType.DOUBLE_FIT; + private static final Color DEFAULT_PAINT_COLOR = Color.decode("#419BF9"); + private static final int FIT_FONT_SIZE = 15; + private static final int NO_FIT_FONT_SIZE = 9; + private static final Dimension NO_FIT_CONTAINER_DIMENSION = new Dimension(200, 136); + + @Override + public void paint(Graphics g) { + super.paint(g); + g.setColor(Color.GRAY); + GraphHelper.drawRect(g, 1, 1, this.getWidth() - 2, this.getHeight() - 2); + g.setColor(DEFAULT_PAINT_COLOR); + FRFont textFont = FRFont.getInstance(FRFont.DEFAULT_FONTNAME, Font.PLAIN, fitFont ? FIT_FONT_SIZE : NO_FIT_FONT_SIZE); + g.setFont(textFont); + Dimension dimension = calculateCellDimension(); + GraphHelper.drawLine(g, 1, dimension.height, dimension.width * 2 - 1, dimension.height); + GraphHelper.drawLine(g, dimension.width, 1, dimension.width, dimension.height * 2 - 1); + GraphHelper.drawRect(g, 1, 1, dimension.width * 2 - 2, dimension.height * 2 - 2); + double startX = calculateTextDrawStartX(dimension.width, this.getFontMetrics(textFont), "text1"); + double startY = calculateTextDrawStartY(dimension.height); + GraphHelper.drawString(g, "text1", startX, startY); + GraphHelper.drawString(g, "text2", dimension.width + startX, startY); + GraphHelper.drawString(g, "text3", startX, dimension.height + startY); + GraphHelper.drawString(g, "text4", dimension.width + startX, dimension.height + startY); + } + + private Dimension calculateCellDimension() { + if (fitType == FitType.DOUBLE_FIT) { + return new Dimension(this.getWidth() / 2, this.getHeight() / 2); + } else if (fitType == FitType.NOT_FIT) { + return new Dimension(NO_FIT_CONTAINER_DIMENSION.width / 2, NO_FIT_CONTAINER_DIMENSION.height / 2); + } else { + return new Dimension(this.getWidth() / 2, NO_FIT_CONTAINER_DIMENSION.height / 2); + } + } + + private double calculateTextDrawStartX(int containerWidth, FontMetrics fontMetrics, String text) { + return (containerWidth - fontMetrics.stringWidth(text)) / 2.0D; + } + + private double calculateTextDrawStartY(int containerHeight) { + return containerHeight / 2.0D; + } + + public void refreshPreview(boolean fitFont, FitType fitType) { + this.fitFont = fitFont; + this.fitType = fitType; + repaint(); + } + + public void refreshPreview(boolean fitFont) { + this.fitFont = fitFont; + repaint(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/report/fit/ReportFitConfigPane.java b/designer-base/src/main/java/com/fr/design/report/fit/ReportFitConfigPane.java new file mode 100644 index 000000000..399e7fef9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/report/fit/ReportFitConfigPane.java @@ -0,0 +1,172 @@ +package com.fr.design.report.fit; + +import com.fr.design.gui.ibutton.UIRadioButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.DesignSizeI18nManager; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.report.fit.menupane.FitRadioGroup; +import com.fr.design.report.fit.menupane.FontRadioGroup; +import com.fr.general.ComparatorUtils; +import com.fr.report.fit.ReportFitAttr; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import static com.fr.design.i18n.Toolkit.i18nText; + +public class ReportFitConfigPane extends JPanel { + public FontRadioGroup fontRadioGroup; + public FitRadioGroup ecConfigRadioGroup; + protected NewFitPreviewPane previewJPanel; + protected FitAttrModel fitAttrModel; + protected boolean globalConfig; + + + public ReportFitConfigPane(FitAttrModel fitAttrModel, boolean globalConfig) { + this.fitAttrModel = fitAttrModel; + this.globalConfig = globalConfig; + initComponent(); + } + + private void initComponent() { + JPanel contentJPanel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(false, FlowLayout.LEFT, 0, 0); + this.add(contentJPanel); + fontRadioGroup = new FontRadioGroup(); + ecConfigRadioGroup = new FitRadioGroup(); + contentJPanel.add(initAttrJPanel()); + contentJPanel.add(initPreviewJPanel()); + } + + private JPanel initAttrJPanel() { + JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + Component[] fontComponents = new Component[3]; + initRadioGroup(fontRadioGroup, i18nText("Fine-Designer_Fit-Font"), new String[]{i18nText("Fine-Designer_Fit"), i18nText("Fine-Designer_Fit-No")}, fontComponents); + jPanel.add(createSubAttrPane(fontComponents), BorderLayout.NORTH); + jPanel.add(initECConfigPane(), BorderLayout.CENTER); + return jPanel; + } + + protected JPanel initECConfigPane() { + JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + Component[] ecComponents = new Component[fitAttrModel.getFitTypeNames().length + 1]; + initRadioGroup(ecConfigRadioGroup, fitAttrModel.getFitName(), fitAttrModel.getFitTypeNames(), ecComponents); + jPanel.add(createSubAttrPane(ecComponents), BorderLayout.CENTER); + return jPanel; + } + + + protected JPanel createSubAttrPane(Component[] components) { + double[] rowSize = new double[]{20}; + double[] columnSize = new double[components.length]; + for (int i = 0; i < columnSize.length; i++) { + if (i == 0) { + columnSize[i] = DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.report.fit.firstColumn").getWidth(); + } else { + columnSize[i] = DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.report.fit.column").getWidth(); + } + } + + JPanel attrJPanel = TableLayoutHelper.createTableLayoutPane(new Component[][]{components}, rowSize, columnSize); + attrJPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 10, 0)); + return attrJPanel; + } + + protected void initRadioGroup(FitRadioGroup fitRadioGroup, String name, String[] options, Component[] components) { + components[0] = new UILabel(name); + for (int i = 0; i < options.length; i++) { + + if (options[i] != null) { + UIRadioButton fontFitRadio = new UIRadioButton(options[i]); + fitRadioGroup.add(fontFitRadio); + components[i + 1] = fontFitRadio; + } else { + components[i + 1] = null; + } + } + fitRadioGroup.addActionListener(getPreviewActionListener()); + } + + private ActionListener getPreviewActionListener() { + return new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + refreshPreviewJPanel(); + } + }; + } + + public void refreshPreviewJPanel(FitType fitType) { + previewJPanel.refreshPreview(fontRadioGroup.isFontFit(), fitType); + } + + protected void refreshPreviewJPanel() { + previewJPanel.refreshPreview(fontRadioGroup.isFontFit(), FitType.parse(updateBean())); + } + + private JPanel initPreviewJPanel() { + JPanel wrapperPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + previewJPanel = new NewFitPreviewPane(); + wrapperPane.add(previewJPanel, BorderLayout.CENTER); + int leftIndent = globalConfig ? (int) DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.report.fit.firstColumn").getWidth() : 0; + wrapperPane.setBorder(BorderFactory.createEmptyBorder(0, leftIndent, 0, 0)); + wrapperPane.setPreferredSize(new Dimension(300 + leftIndent, 204)); + return wrapperPane; + } + + + public void populateBean(ReportFitAttr ob) { + fontRadioGroup.selectIndexButton(ob.isFitFont() ? 0 : 1); + populateECConfigRadioGroup(ob.fitStateInPC()); + refreshPreviewJPanel(); + } + + protected void populateECConfigRadioGroup(int fitStateInPC){ + ecConfigRadioGroup.selectIndexButton(getOptionIndex(fitStateInPC)); + } + + + protected void updateECConfigRadioGroup(ReportFitAttr reportFitAttr){ + reportFitAttr.setFitStateInPC(getStateInPC(ecConfigRadioGroup.getSelectRadioIndex())); + } + + public ReportFitAttr updateBean() { + ReportFitAttr reportFitAttr = new ReportFitAttr(); + reportFitAttr.setFitFont(fontRadioGroup.isFontFit()); + updateECConfigRadioGroup(reportFitAttr); + return reportFitAttr; + } + + + protected int getStateInPC(int index) { + FitType[] fitTypes = fitAttrModel.getFitTypes(); + if (index > fitTypes.length - 1) { + return index; + } + return fitTypes[index].getState(); + } + + protected int getOptionIndex(int state) { + FitType[] fitTypes = fitAttrModel.getFitTypes(); + for (int i = 0; i < fitTypes.length; i++) { + if (ComparatorUtils.equals(state, fitTypes[i].getState())) { + return i; + } + } + return 0; + } + + + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + fontRadioGroup.setEnabled(enabled); + ecConfigRadioGroup.setEnabled(enabled); + } + +} diff --git a/designer-form/src/main/java/com/fr/design/fit/FormFitAttrAction.java b/designer-form/src/main/java/com/fr/design/fit/FormFitAttrAction.java new file mode 100644 index 000000000..dad6e9be9 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/fit/FormFitAttrAction.java @@ -0,0 +1,85 @@ +package com.fr.design.fit; + +import com.fr.design.actions.JTemplateAction; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.dialog.UIDialog; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JForm; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.menu.MenuKeySet; +import com.fr.design.report.fit.FormFitAttrModelType; +import com.fr.form.main.Form; +import com.fr.report.fit.FitProvider; +import com.fr.report.fit.ReportFitAttr; + +import javax.swing.KeyStroke; +import java.awt.Dimension; +import java.awt.event.ActionEvent; + +public class FormFitAttrAction extends JTemplateAction { + private static final MenuKeySet REPORT_FIT_ATTR = new MenuKeySet() { + @Override + public char getMnemonic() { + return 'T'; + } + + @Override + public String getMenuName() { + return Toolkit.i18nText("Fine-Designer_PC_Fit_Attr"); + } + + @Override + public KeyStroke getKeyStroke() { + return null; + } + }; + + public FormFitAttrAction(JTemplate jTemplate) { + super(jTemplate); + initMenuStyle(); + } + + private void initMenuStyle() { + this.setMenuKeySet(REPORT_FIT_ATTR); + this.setName(getMenuKeySet().getMenuKeySetName() + "..."); + this.setMnemonic(getMenuKeySet().getMnemonic()); + this.setSmallIcon("/com/fr/design/images/reportfit/fit"); + } + + /** + * Action触发事件 + * + * @param e 事件 + */ + @Override + public void actionPerformed(ActionEvent e) { + final JTemplate jwb = getEditingComponent(); + if (jwb == null || !(jwb.getTarget() instanceof Form)) { + return; + } + JForm jForm = (JForm) jwb; + Form wbTpl = jForm.getTarget(); + ReportFitAttr fitAttr = wbTpl.getReportFitAttr(); + FormFitAttrPane formFitAttrPane = new FormFitAttrPane(jForm, FormFitAttrModelType.parse(wbTpl)); + showReportFitDialog(fitAttr, jwb, wbTpl, formFitAttrPane); + } + + private void showReportFitDialog(ReportFitAttr fitAttr, final JTemplate jwb, final FitProvider wbTpl, final BasicBeanPane attrPane) { + attrPane.populateBean(fitAttr); + UIDialog dialog = attrPane.showWindowWithCustomSize(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + @Override + public void doOk() { + fireEditingOk(jwb, wbTpl, attrPane.updateBean(), fitAttr); + } + }, new Dimension(660, 600)); + dialog.setVisible(true); + } + + private void fireEditingOk(final JTemplate jwb, final FitProvider wbTpl, ReportFitAttr newReportFitAttr, ReportFitAttr oldReportFitAttr) { + wbTpl.setReportFitAttr(newReportFitAttr); + jwb.fireTargetModified(); + } + +} diff --git a/designer-form/src/main/java/com/fr/design/fit/FormFitAttrPane.java b/designer-form/src/main/java/com/fr/design/fit/FormFitAttrPane.java new file mode 100644 index 000000000..51eda6d36 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/fit/FormFitAttrPane.java @@ -0,0 +1,377 @@ +package com.fr.design.fit; + +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.designer.IntervalConstants; +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.designer.creator.XWAbsoluteBodyLayout; +import com.fr.design.designer.creator.XWFitLayout; +import com.fr.design.designer.creator.XWScaleLayout; +import com.fr.design.designer.properties.items.FRLayoutTypeItems; +import com.fr.design.designer.properties.items.Item; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.FormSelectionUtils; +import com.fr.design.mainframe.JForm; +import com.fr.design.mainframe.WidgetPropertyPane; +import com.fr.design.report.fit.FitType; +import com.fr.design.report.fit.FormFitAttrModelType; +import com.fr.design.report.fit.FormFitConfigPane; +import com.fr.design.report.fit.ReportFitConfigPane; +import com.fr.design.widget.FRWidgetFactory; +import com.fr.form.main.Form; +import com.fr.form.ui.Widget; +import com.fr.form.ui.container.WAbsoluteBodyLayout; +import com.fr.form.ui.container.WAbsoluteLayout; +import com.fr.form.ui.container.WBodyLayoutType; +import com.fr.form.ui.container.WFitLayout; +import com.fr.form.ui.container.WSortLayout; +import com.fr.general.ComparatorUtils; +import com.fr.general.act.BorderPacker; +import com.fr.log.FineLoggerFactory; +import com.fr.report.fit.ReportFitAttr; + +import javax.swing.BorderFactory; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import static com.fr.design.i18n.Toolkit.i18nText; +import static javax.swing.JOptionPane.*; + +public class FormFitAttrPane extends BasicBeanPane { + + private UIComboBox layoutComboBox; + private UIComboBox scaleComboBox; + private FormFitAttrModelType fitAttrModelType; + + protected UIComboBox itemChoose; + + private JForm jForm; + private ReportFitConfigPane fitConfigPane; + + public FormFitAttrPane(JForm jForm, FormFitAttrModelType fitAttrModelType) { + this.fitAttrModelType = fitAttrModelType; + this.jForm = jForm; + initComponents(); + } + + + private void initComponents() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.setBorder(BorderFactory.createEmptyBorder(12, 5, 0, 5)); + this.add(createReportFitSettingPane(), BorderLayout.CENTER); + this.add(createReportLayoutSettingPane(), BorderLayout.NORTH); + + } + + + private JPanel createReportLayoutSettingPane() { + JPanel jPanel = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Form_PC_Fit_Config_Layout")); + jPanel.add(createAreaScalePane(), BorderLayout.CENTER); + jPanel.setPreferredSize(new Dimension(640, 84)); + return jPanel; + } + + protected String[] getItemNames() { + return new String[]{Toolkit.i18nText("Fine-Design_Report_Using_Server_Report_View_Settings"), + Toolkit.i18nText("Fine-Design_Report_I_Want_To_Set_Single")}; + } + + + private JPanel createReportFitSettingPane() { + JPanel jPanel = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Form_PC_Fit_Config_Content_Attr")); + JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + jPanel.add(contentPane, BorderLayout.CENTER); + UILabel label = new UILabel(Toolkit.i18nText("Fine-Design_Form_PC_Fit_Config_Settings")); + label.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0)); + contentPane.add(label, BorderLayout.WEST); + label.setPreferredSize(new Dimension(100, 0)); + label.setVerticalAlignment(SwingConstants.TOP); + itemChoose = new UIComboBox(getItemNames()); + itemChoose.setPreferredSize(new Dimension(160, 20)); + Form form = jForm.getTarget(); + itemChoose.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + if (isTemplateSingleSet()) { + if (form != null) { + ReportFitAttr fitAttr = form.getReportFitAttr(); + populate(fitAttr); + } + } else { + populate(fitAttrModelType.getFitAttrModel().getGlobalReportFitAttr()); + } + } + } + }); + JPanel centerPane = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); + centerPane.add(itemChoose); + centerPane.add(fitConfigPane = new FormFitConfigPane(this.fitAttrModelType.getFitAttrModel())); + contentPane.add(centerPane, BorderLayout.CENTER); + return jPanel; + } + + public void populate(ReportFitAttr reportFitAttr) { + if (reportFitAttr == null) { + reportFitAttr = fitAttrModelType.getFitAttrModel().getGlobalReportFitAttr(); + } + + this.setEnabled(isTemplateSingleSet()); + fitConfigPane.populateBean(reportFitAttr); + } + + + public ReportFitAttr updateBean() { + updateLayoutType(); + if (!isTemplateSingleSet()) { + return null; + } else { + return fitConfigPane.updateBean(); + } + } + + private void updateLayoutType() { + XLayoutContainer xLayoutContainer = this.jForm.getRootComponent(); + if (xLayoutContainer == null || !xLayoutContainer.acceptType(XWFitLayout.class)) { + return; + } + XWFitLayout xwFitLayout = (XWFitLayout) xLayoutContainer; + WFitLayout wFitLayout = xwFitLayout.toData(); + int state = layoutComboBox.getSelectedIndex(); + WBodyLayoutType selectType = WBodyLayoutType.parse(state); + if (selectType != wFitLayout.getBodyLayoutType()) { + wFitLayout.setLayoutType(selectType); + //从自适应布局切换到绝对布局 + if (selectType == WBodyLayoutType.ABSOLUTE) { + switchLayoutFromFit2Absolute(xwFitLayout); + } else { + //从绝对布局切换到自适应布局 + switchLayoutFromAbsolute2Fit(xwFitLayout); + } + } + wFitLayout.setCompatibleScaleAttr(fitAttrModelType.parseScaleAttrFromShowIndex(this.scaleComboBox.getSelectedIndex(), wFitLayout.getBodyLayoutType())); + } + + + private void switchLayoutFromFit2Absolute(XWFitLayout xWFitLayout) { + try { + WFitLayout layout = xWFitLayout.toData(); + WAbsoluteBodyLayout wAbsoluteBodyLayout = new WAbsoluteBodyLayout("body"); + wAbsoluteBodyLayout.setCompState(WAbsoluteLayout.STATE_FIXED); + // 切换布局类型时,保留body背景样式 + wAbsoluteBodyLayout.setBorderStyleFollowingTheme(layout.isBorderStyleFollowingTheme()); + wAbsoluteBodyLayout.setBorderStyle((BorderPacker) (layout.getBorderStyle().clone())); + Component[] components = xWFitLayout.getComponents(); + Rectangle[] backupBounds = getBackupBoundsFromFitLayout(xWFitLayout); + xWFitLayout.removeAll(); + layout.resetStyle(); + XWAbsoluteBodyLayout xwAbsoluteBodyLayout = xWFitLayout.getBackupParent() == null ? new XWAbsoluteBodyLayout(wAbsoluteBodyLayout, new Dimension(0, 0)) : (XWAbsoluteBodyLayout) xWFitLayout.getBackupParent(); + xWFitLayout.setFixLayout(false); + xWFitLayout.getLayoutAdapter().addBean(xwAbsoluteBodyLayout, 0, 0); + for (int i = 0; i < components.length; i++) { + XCreator xCreator = (XCreator) components[i]; + xCreator.setBounds(backupBounds[i]); + //部分控件被ScaleLayout包裹着,绝对布局里面要放出来 + if (xCreator.acceptType(XWScaleLayout.class)) { + if (xCreator.getComponentCount() > 0 && ((XCreator) xCreator.getComponent(0)).shouldScaleCreator()) { + Component component = xCreator.getComponent(0); + component.setBounds(xCreator.getBounds()); + } + } + if (!xCreator.acceptType(XOccupiedLayout.class)) { + xwAbsoluteBodyLayout.add(xCreator); + } + + } + copyLayoutAttr(layout, xwAbsoluteBodyLayout.toData()); + xWFitLayout.setBackupParent(xwAbsoluteBodyLayout); + FormDesigner formDesigner = WidgetPropertyPane.getInstance().getEditingFormDesigner(); + formDesigner.getSelectionModel().setSelectedCreators( + FormSelectionUtils.rebuildSelection(xWFitLayout, new Widget[]{wAbsoluteBodyLayout})); + if (xwAbsoluteBodyLayout.toData() != null) { + xwAbsoluteBodyLayout.toData().setBorderStyleFollowingTheme(wAbsoluteBodyLayout.isBorderStyleFollowingTheme()); + xwAbsoluteBodyLayout.toData().setBorderStyle(wAbsoluteBodyLayout.getBorderStyle()); + } + xwAbsoluteBodyLayout.refreshStylePreviewEffect(); + if (xWFitLayout.toData() != null) { + xWFitLayout.toData().resetStyle(); + } + xWFitLayout.refreshStylePreviewEffect(); + formDesigner.switchBodyLayout(xwAbsoluteBodyLayout); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + + } + } + + private Rectangle[] getBackupBoundsFromFitLayout(XWFitLayout xWFitLayout) { + int count = xWFitLayout.getComponentCount(); + Rectangle[] rectangles = new Rectangle[count]; + for (int i = 0; i < count; i++) { + rectangles[i] = xWFitLayout.getComponent(i).getBounds(); + } + return rectangles; + } + + protected void copyLayoutAttr(WSortLayout srcLayout, WSortLayout destLayout) { + destLayout.clearListeners(); + destLayout.clearMobileWidgetList(); + for (int i = 0, len = srcLayout.getMobileWidgetListSize(); i < len; i++) { + destLayout.addMobileWidget(srcLayout.getMobileWidget(i)); + } + destLayout.setSorted(true); + for (int i = 0, len = srcLayout.getListenerSize(); i < len; i++) { + destLayout.addListener(srcLayout.getListener(i)); + } + srcLayout.clearListeners(); + srcLayout.clearMobileWidgetList(); + } + + + private void switchLayoutFromAbsolute2Fit(XWFitLayout xwFitLayout) { + XWAbsoluteBodyLayout xwAbsoluteBodyLayout = getAbsoluteBodyLayout(xwFitLayout); + if (xwAbsoluteBodyLayout == null) { + return; + } + WAbsoluteBodyLayout layout = xwAbsoluteBodyLayout.toData(); + WFitLayout wFitLayout = xwFitLayout.toData(); + wFitLayout.resetStyle(); + xwFitLayout.switch2FitBodyLayout(xwAbsoluteBodyLayout); + // 切换布局类型时,保留body背景样式 + if (wFitLayout != null) { + wFitLayout.setBorderStyleFollowingTheme(layout.isBorderStyleFollowingTheme()); + wFitLayout.setBorderStyle(layout.getBorderStyle()); + } + copyLayoutAttr(layout, xwFitLayout.toData()); + + copyLayoutAttr(layout, xwFitLayout.toData()); + xwFitLayout.refreshStylePreviewEffect(); + } + + private XWAbsoluteBodyLayout getAbsoluteBodyLayout(XWFitLayout xwFitLayout) { + if (xwFitLayout != null && xwFitLayout.getComponentCount() > 0) { + Component component = xwFitLayout.getComponent(0); + if (component instanceof XWAbsoluteBodyLayout) { + return (XWAbsoluteBodyLayout) component; + } + } + return null; + } + + private JPanel createAreaScalePane() { + initLayoutComboBox(); + + UILabel layoutTypeLabel = FRWidgetFactory.createLineWrapLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Attr_Layout_Type")); + UILabel scaleModeLabel = FRWidgetFactory.createLineWrapLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_PC_Fit_Config_Scale_Setting")); + Component[][] components = new Component[][]{ + {layoutTypeLabel, layoutComboBox}, + {scaleModeLabel, scaleComboBox} + }; + JPanel contentPane = TableLayoutHelper.createGapTableLayoutPane(components, + TableLayoutHelper.FILL_LASTCOLUMN, 20, IntervalConstants.INTERVAL_L1); + JPanel containerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + containerPane.add(contentPane, BorderLayout.CENTER); + + return containerPane; + } + + + public void initLayoutComboBox() { + Item[] items = FRLayoutTypeItems.ITEMS; + DefaultComboBoxModel model = new DefaultComboBoxModel(); + for (Item item : items) { + model.addElement(item); + } + scaleComboBox = new UIComboBox(model); + scaleComboBox.setModel(new DefaultComboBoxModel(fitAttrModelType.getFitLayoutScaleAttr())); + layoutComboBox = new UIComboBox(model); + layoutComboBox.setPreferredSize(new Dimension(160, 20)); + scaleComboBox.setPreferredSize(new Dimension(160, 20)); + WFitLayout wFitLayout = jForm.getTarget().getWFitLayout(); + layoutComboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + int selectIndex = layoutComboBox.getSelectedIndex(); + if (selectIndex == 0) { + if (wFitLayout.getBodyLayoutType() == WBodyLayoutType.ABSOLUTE) { + int selVal = FineJOptionPane.showConfirmDialog( + FormFitAttrPane.this, + Toolkit.i18nText("Fine-Design_Form_Layout_Switch_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + OK_CANCEL_OPTION, + WARNING_MESSAGE + ); + if (OK_OPTION != selVal) { + layoutComboBox.setSelectedIndex(1); + return; + } + } + scaleComboBox.setModel(new DefaultComboBoxModel(fitAttrModelType.getFitLayoutScaleAttr())); + } else { + scaleComboBox.setModel(new DefaultComboBoxModel(fitAttrModelType.getAbsoluteLayoutSaleAttr())); + } + scaleComboBox.setSelectedIndex(0); + } + }); + + scaleComboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + WBodyLayoutType selectBodyType = WBodyLayoutType.parse(layoutComboBox.getSelectedIndex()); + int state = fitAttrModelType.parseScaleAttrFromShowIndex(scaleComboBox.getSelectedIndex(), selectBodyType); + fitConfigPane.refreshPreviewJPanel(FitType.parseByFitState(state)); + } + }); + } + + + @Override + public void populateBean(ReportFitAttr reportFitAttr) { + WFitLayout wFitLayout = jForm.getTarget().getWFitLayout(); + layoutComboBox.setSelectedIndex(wFitLayout.getBodyLayoutType().getTypeValue()); + scaleComboBox.setSelectedIndex(fitAttrModelType.getScaleAttrShowIndex(wFitLayout)); + + if (reportFitAttr == null) { + itemChoose.setSelectedItem(Toolkit.i18nText("Fine-Design_Report_Using_Server_Report_View_Settings")); + } else { + itemChoose.setSelectedItem(Toolkit.i18nText("Fine-Design_Report_I_Want_To_Set_Single")); + } + if (reportFitAttr == null) { + reportFitAttr = fitAttrModelType.getFitAttrModel().getGlobalReportFitAttr(); + } + setEnabled(isTemplateSingleSet()); + fitConfigPane.populateBean(reportFitAttr); + } + + private boolean isTemplateSingleSet() { + return ComparatorUtils.equals(Toolkit.i18nText("Fine-Design_Report_I_Want_To_Set_Single"), itemChoose.getSelectedItem()); + } + + + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + fitConfigPane.setEnabled(enabled); + } + + @Override + protected String title4PopupWindow() { + return i18nText("Fine-Designer_PC_Fit_Attr"); + } + +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/JForm.java b/designer-form/src/main/java/com/fr/design/mainframe/JForm.java index 8d2748eb3..ec3852437 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/JForm.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/JForm.java @@ -14,7 +14,6 @@ import com.fr.base.vcs.DesignerMode; import com.fr.design.DesignModelAdapter; import com.fr.design.DesignState; import com.fr.design.DesignerEnvManager; -import com.fr.design.ExtraDesignClassManager; import com.fr.design.actions.FormMobileAttrAction; import com.fr.design.actions.TemplateParameterAction; import com.fr.design.actions.core.WorkBookSupportable; @@ -37,7 +36,7 @@ import com.fr.design.designer.properties.FormWidgetAuthorityEditPane; import com.fr.design.event.TargetModifiedEvent; import com.fr.design.event.TargetModifiedListener; import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.fun.FormAdaptiveConfigUIProcessor; +import com.fr.design.fit.FormFitAttrAction; import com.fr.design.fun.PreviewProvider; import com.fr.design.fun.PropertyItemPaneProvider; import com.fr.design.gui.frpane.HyperlinkGroupPane; @@ -66,7 +65,6 @@ import com.fr.design.menu.ToolBarDef; import com.fr.design.parameter.ParameterPropertyPane; import com.fr.design.preview.FormPreview; import com.fr.design.preview.MobilePreview; -import com.fr.design.report.fit.menupane.ReportFitAttrAction; import com.fr.design.roleAuthority.RolesAlreadyEditedPane; import com.fr.design.utils.gui.LayoutUtils; import com.fr.file.FILE; @@ -597,11 +595,7 @@ public class JForm extends JTemplate implements BaseJForm implements BaseJForm { - protected UIComboBox comboBox; public FRAbsoluteLayoutDefinePane(XCreator xCreator) { super(xCreator); @@ -34,40 +19,8 @@ public class FRAbsoluteLayoutDefinePane extends AbstractFRLayoutDefinePane { - private static final int ADAPT_LABEL_MAX_WIDTH = 80; private XWFitLayout xWFitLayout; private WFitLayout wFitLayout; - private UIComboBox layoutComboBox; - private UIComboBox adaptComboBox; private UISpinner componentIntervel; private PaddingBoundPane paddingBound; private FollowingThemePane themePane; @@ -119,11 +106,7 @@ public class FRFitLayoutDefinePane extends AbstractFRLayoutDefinePane 0 && ((XCreator) xCreator.getComponent(0)).shouldScaleCreator()) { - Component component = xCreator.getComponent(0); - component.setBounds(xCreator.getBounds()); - } - } - if (!xCreator.acceptType(XOccupiedLayout.class)){ - xwAbsoluteBodyLayout.add(xCreator); - } - - } - copyLayoutAttr(wFitLayout, xwAbsoluteBodyLayout.toData()); - xWFitLayout.setBackupParent(xwAbsoluteBodyLayout); - FormDesigner formDesigner = WidgetPropertyPane.getInstance().getEditingFormDesigner(); - formDesigner.getSelectionModel().setSelectedCreators( - FormSelectionUtils.rebuildSelection(xWFitLayout, new Widget[]{wAbsoluteBodyLayout})); - if (xwAbsoluteBodyLayout.toData() != null) { - xwAbsoluteBodyLayout.toData().setBorderStyleFollowingTheme(wAbsoluteBodyLayout.isBorderStyleFollowingTheme()); - xwAbsoluteBodyLayout.toData().setBorderStyle(wAbsoluteBodyLayout.getBorderStyle()); - } - xwAbsoluteBodyLayout.refreshStylePreviewEffect(); - if (xWFitLayout.toData() != null) { - xWFitLayout.toData().resetStyle(); - } - xWFitLayout.refreshStylePreviewEffect(); - formDesigner.switchBodyLayout(xwAbsoluteBodyLayout); - return layout; - } - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - - } - int intervelValue = (int) componentIntervel.getValue(); if (xWFitLayout.canAddInterval(intervelValue)) { // 设置完间隔后,要同步处理界面组件,容器刷新后显示出对应效果 @@ -302,14 +210,6 @@ public class FRFitLayoutDefinePane extends AbstractFRLayoutDefinePane Date: Thu, 6 Jan 2022 18:08:15 +0800 Subject: [PATCH 19/19] =?UTF-8?q?REPORT-62440=20=E8=A1=A8=E5=A4=B4?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E5=86=85=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design/dscolumn/DSColumnAdvancedPane.java | 151 ++----- .../cell/AbstractDSCellEditorPane.java | 114 +----- .../cell/settingpane/CellExpandAttrPane.java | 20 +- .../CellDSColumnSortGroupPane.java | 40 ++ .../CellDSColumnSortItemPane.java | 40 ++ .../celldscolumn/CellDSColumnSortPane.java | 62 +++ .../cellexpand/CellExpandSortGroupPane.java | 19 + .../cellexpand/CellExpandSortItemPane.java | 37 ++ .../sort/cellexpand/CellExpandSortPane.java | 39 ++ .../sort/common/AbstractSortGroupPane.java | 152 ++++++++ .../sort/common/AbstractSortItemPane.java | 153 ++++++++ .../design/sort/common/AbstractSortPane.java | 112 ++++++ .../design/sort/common/SortColumnRowPane.java | 277 +++++++++++++ .../sort/common/SortUIExpandablePane.java | 119 ++++++ .../CellSortExpressionPane.java | 32 ++ .../CustomSequenceEditPane.java | 190 +++++++++ .../expressionpane/CustomSequencePane.java | 66 ++++ .../CustomSequenceSortExpressionPane.java | 37 ++ .../FormulaSortExpressionPane.java | 42 ++ .../expressionpane/SortExpressionPane.java | 23 ++ .../fr/design/sort/header/HeaderAreaPane.java | 267 +++++++++++++ .../design/sort/header/HeaderSettingPane.java | 81 ++++ .../sort/header/HeaderSortRulePane.java | 279 +++++++++++++ .../fr/design/sort/header/SortHeaderPane.java | 65 ++++ .../cellquick/CellDSColumnEditor.java | 367 +++--------------- 25 files changed, 2255 insertions(+), 529 deletions(-) create mode 100644 designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortGroupPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortItemPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortGroupPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortItemPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortGroupPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortItemPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/common/SortColumnRowPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/common/SortUIExpandablePane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/expressionpane/CellSortExpressionPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceEditPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequencePane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceSortExpressionPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/expressionpane/FormulaSortExpressionPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/expressionpane/SortExpressionPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/header/HeaderSettingPane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/header/HeaderSortRulePane.java create mode 100644 designer-realize/src/main/java/com/fr/design/sort/header/SortHeaderPane.java diff --git a/designer-realize/src/main/java/com/fr/design/dscolumn/DSColumnAdvancedPane.java b/designer-realize/src/main/java/com/fr/design/dscolumn/DSColumnAdvancedPane.java index b943778bf..32818de9f 100644 --- a/designer-realize/src/main/java/com/fr/design/dscolumn/DSColumnAdvancedPane.java +++ b/designer-realize/src/main/java/com/fr/design/dscolumn/DSColumnAdvancedPane.java @@ -3,6 +3,7 @@ package com.fr.design.dscolumn; import com.fr.base.BaseFormula; import com.fr.data.util.SortOrder; import com.fr.design.border.UITitledBorder; +import com.fr.design.constants.LayoutConstants; import com.fr.design.data.DesignTableDataManager; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; @@ -10,10 +11,10 @@ import com.fr.design.formula.CustomVariableResolver; import com.fr.design.formula.FormulaFactory; import com.fr.design.formula.SortFormulaPane; import com.fr.design.formula.UIFormula; -import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ispinner.UISpinner; import com.fr.design.gui.itextfield.UITextField; @@ -21,6 +22,7 @@ import com.fr.design.gui.style.TextFormatPane; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.sort.celldscolumn.CellDSColumnSortPane; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.report.cell.CellElement; import com.fr.report.cell.TemplateCellElement; @@ -28,19 +30,11 @@ import com.fr.report.cell.cellattr.CellExpandAttr; import com.fr.report.cell.cellattr.core.group.DSColumn; import com.fr.report.cell.cellattr.core.group.SelectCount; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Font; +import javax.swing.*; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.Arrays; import static com.fr.report.cell.cellattr.core.group.FilterTypeEnum.BOTTOM; import static com.fr.report.cell.cellattr.core.group.FilterTypeEnum.SPECIFY; @@ -64,8 +58,19 @@ public class DSColumnAdvancedPane extends BasicPane { } public DSColumnAdvancedPane(int setting) { - this.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); - this.setLayout(FRGUIPaneFactory.createBorderLayout()); + initContentPane(setting); + initScrollPane(); + } + + private void initScrollPane() { + ScrollPane scrollPane = new ScrollPane(contentPane); + this.add(scrollPane); + } + + private void initContentPane(int setting) { + contentPane = new JPanel(); + contentPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); + contentPane.setLayout(FRGUIPaneFactory.createBorderLayout()); sortPane = new SortPane(); sortPane.setBorder(UITitledBorder.createBorderWithTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Sort_Sort_Order"))); @@ -135,7 +140,7 @@ public class DSColumnAdvancedPane extends BasicPane { TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}; double[] columnSize = {TableLayout.FILL}; - this.add(TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize), BorderLayout.CENTER); + contentPane.add(TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize), BorderLayout.CENTER); } @Override @@ -148,7 +153,7 @@ public class DSColumnAdvancedPane extends BasicPane { return; } - sortPane.populate(cellElement); + sortPane.populateBean(cellElement); valuePane.populate(cellElement); formatAttrPane.populate(cellElement); @@ -198,7 +203,7 @@ public class DSColumnAdvancedPane extends BasicPane { return; } - sortPane.update(cellElement); + sortPane.updateBean(cellElement); valuePane.update(cellElement); formatAttrPane.update(cellElement); @@ -234,66 +239,25 @@ public class DSColumnAdvancedPane extends BasicPane { } } - private static class SortPane extends SortFormulaPane { - private CellElement cellElement; + private static class ScrollPane extends UIScrollPane { + ScrollPane(Component component) { + super(component); + this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + } @Override - public void formulaAction() { - if (cellElement == null) { - return; - } - Object value = cellElement.getValue(); - if (value == null || !(value instanceof DSColumn)) { - return; - } - - String[] displayNames = DesignTableDataManager.getSelectedColumnNames( - DesignTableDataManager.getEditingTableDataSource(), ((DSColumn) value).getDSName()); - - showFormulaDialog(displayNames); + public Dimension getPreferredSize() { + return new Dimension(DSColumnPane.DEFAULT_DIMENSION.width - 20, DSColumnPane.DEFAULT_DIMENSION.height - 100); } + } - void populate(CellElement cellElement) { - if (cellElement == null) { - return; - } - this.cellElement = cellElement; - - Object value = cellElement.getValue(); - if (value == null || !(value instanceof DSColumn)) { - return; - } - DSColumn dSColumn = (DSColumn) value; - - int sort = dSColumn.getOrder(); - this.sortOrderComboBox.setSortOrder(new SortOrder(sort)); - - String sortFormula = dSColumn.getSortFormula(); - sortFormulaTextField.setText(sortFormula); + private static class SortPane extends CellDSColumnSortPane { + SortPane() { + this.setLayout(new FlowLayout(FlowLayout.LEFT)); } - public void update(CellElement cellElement) { - if (cellElement == null) { - return; - } - Object value = cellElement.getValue(); - if (value == null || !(value instanceof DSColumn)) { - return; - } - DSColumn dSColumn = (DSColumn) (cellElement.getValue()); - - dSColumn.setOrder(this.sortOrderComboBox.getSortOrder().getOrder()); - //lance:sort formula - - String sText = null; - if (!(sortFormulaTextField.getText() == null || sortFormulaTextField.getText().trim().equals("") || sortFormulaTextField.getText().trim().equals("$$$"))) { - sText = new String(sortFormulaTextField.getText()); - } - if (!(sText == null || sText.length() < 1)) { - dSColumn.setSortFormula(sText); - } else { - dSColumn.setSortFormula(null); - } + protected boolean needSortHeaderPane() { + return false; } } @@ -548,11 +512,11 @@ public class DSColumnAdvancedPane extends BasicPane { } } - public static class ReLayoutTextFormatPane extends TextFormatPane { + public static class FormatAttrPane extends TextFormatPane { protected void initLayout() { - JComponent[][] components = new JComponent[][] { {typeComboBox, textField, roundingBox} }; - double[] rowSize = new double[] { TableLayout.FILL }; + JComponent[][] components = new JComponent[][]{{typeComboBox, textField, roundingBox}}; + double[] rowSize = new double[]{TableLayout.FILL}; double[] columnSize = {TableLayout.PREFERRED, 200, TableLayout.PREFERRED}; JPanel settingPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, 4, 0); @@ -578,45 +542,6 @@ public class DSColumnAdvancedPane extends BasicPane { } } - - public static class FormatAttrPane extends AbstractAttrNoScrollPane { - private TextFormatPane formatPane; - - @Override - protected JPanel createContentPane() { - this.formatPane = new ReLayoutTextFormatPane(); - return this.formatPane; - } - - @Override - public Dimension getPreferredSize() { - if (formatPane == null) { - return super.getPreferredSize(); - } - return formatPane.getPreferredSize(); - } - - protected void initContentPane() { - leftContentPane = createContentPane(); - if (leftContentPane != null) { - leftContentPane.setBorder(BorderFactory.createEmptyBorder()); - this.add(leftContentPane, BorderLayout.CENTER); - } - } - - public void populate(CellElement cellElement) { - if (cellElement != null && formatPane != null) { - formatPane.populateBean(cellElement.getStyle()); - } - } - - public void update(CellElement cellElement) { - if (cellElement != null && formatPane != null) { - cellElement.setStyle(formatPane.update(cellElement.getStyle())); - } - } - } - private void checkButtonEnabled() { if (useMultiplyNumCheckBox.isSelected()) { multiNumSpinner.setEnabled(true); diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/cell/AbstractDSCellEditorPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/cell/AbstractDSCellEditorPane.java index 8a3b2ded4..dd7d3608c 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/cell/AbstractDSCellEditorPane.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/cell/AbstractDSCellEditorPane.java @@ -1,17 +1,7 @@ package com.fr.design.mainframe.cell; -import com.fr.design.gui.iscrollbar.UIScrollBar; -import com.fr.design.mainframe.CellElementPropertyPane; -import com.fr.quickeditor.cellquick.layout.CellElementBarLayout; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.event.AdjustmentEvent; -import java.awt.event.AdjustmentListener; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; +import com.fr.design.gui.frpane.AttributeChangeListener; +import com.fr.design.mainframe.AbstractAttrPane; /** * 右侧单元格元素面板抽象类 @@ -20,26 +10,9 @@ import java.awt.event.MouseWheelListener; * @version 2017年7月25日 * @since 9.0 */ -public abstract class AbstractDSCellEditorPane extends JPanel { - - /** - * 滚动条相关配置 - */ - private static final int MAXVALUE = 100; - private static final int TITLE_HEIGHT = 95; - private static final int CONTENT_PANE_WIDTH_GAP = 3; - private static final int SCROLLBAR_WIDTH = 7; - private static final int MOUSE_WHEEL_SPEED = 5; - private int maxHeight = 280; - - private JPanel leftContentPane; - private UIScrollBar scrollBar; - - protected abstract JPanel createContentPane(); +public abstract class AbstractDSCellEditorPane extends AbstractAttrPane { - public abstract String getIconPath(); - - public abstract String title4PopupWindow(); + private static final int FIXED_HEIGHT = 40; /** * 从面板拿数据保存 @@ -51,78 +24,19 @@ public abstract class AbstractDSCellEditorPane extends JPanel { */ public abstract void populate(); - protected void createScrollPane() { - leftContentPane = this.createContentPane(); - this.prepareScrollBar(); - leftContentPane.setBorder(BorderFactory.createMatteBorder(10, 10, 0, 0, this.getBackground())); - - this.setLayout(new CellElementBarLayout(leftContentPane) { - @Override - public void layoutContainer(Container parent) { - maxHeight = CellElementPropertyPane.getInstance().getHeight() - TITLE_HEIGHT; - int beginY; - if ((MAXVALUE - scrollBar.getVisibleAmount()) == 0) { - beginY = 0; - } else { - int preferredHeight = leftContentPane.getPreferredSize().height; - int value = scrollBar.getValue(); - beginY = value * (preferredHeight - maxHeight) / (MAXVALUE - scrollBar.getVisibleAmount()); - } - int width = parent.getWidth(); - int height = parent.getHeight(); - if (leftContentPane.getPreferredSize().height > maxHeight) { - leftContentPane.setBounds(0, -beginY, width - SCROLLBAR_WIDTH - CONTENT_PANE_WIDTH_GAP, height + beginY); - scrollBar.setBounds(width - SCROLLBAR_WIDTH - CONTENT_PANE_WIDTH_GAP, 0, SCROLLBAR_WIDTH + CONTENT_PANE_WIDTH_GAP, height); - } else { - leftContentPane.setBounds(0, 0, width - SCROLLBAR_WIDTH - CONTENT_PANE_WIDTH_GAP, height); - } - } - }); - this.add(scrollBar); - this.add(leftContentPane); - } - - - private void prepareScrollBar() { - scrollBar = new UIScrollBar(UIScrollBar.VERTICAL) { - @Override - public int getVisibleAmount() { - int preferredHeight = leftContentPane.getPreferredSize().height; - int e = MAXVALUE * (maxHeight) / preferredHeight; - setVisibleAmount(e); - return e; - } - - @Override - public int getMaximum() { - return MAXVALUE; - } - }; - - scrollBar.addAdjustmentListener(new AdjustmentListener() { - - @Override - public void adjustmentValueChanged(AdjustmentEvent e) { - doLayout(); - } - }); - this.addMouseWheelListener(new MouseWheelListener() { - - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - int value = scrollBar.getValue(); - value += MOUSE_WHEEL_SPEED * e.getWheelRotation(); - scrollBar.setValue(value); - doLayout(); - } - }); - scrollBar.setPreferredSize(new Dimension(SCROLLBAR_WIDTH + CONTENT_PANE_WIDTH_GAP, this.getHeight())); - scrollBar.setBlockIncrement(SCROLLBAR_WIDTH + CONTENT_PANE_WIDTH_GAP); - scrollBar.setBorder(BorderFactory.createMatteBorder(0, CONTENT_PANE_WIDTH_GAP, 0, 0, this.getBackground())); - } /** * 释放tc */ protected abstract void release(); + + protected abstract AttributeChangeListener getAttributeChangeListener(); + + public void addAttributeChangeListener() { + this.addAttributeChangeListener(getAttributeChangeListener()); + } + + protected int getMaxHeight() { + return Math.max(super.getMaxHeight() - FIXED_HEIGHT, 0); + } } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellExpandAttrPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellExpandAttrPane.java index cd454660d..9549a3a7e 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellExpandAttrPane.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellExpandAttrPane.java @@ -4,7 +4,6 @@ import com.fr.design.constants.LayoutConstants; import com.fr.design.constants.UIConstants; import com.fr.design.expand.ExpandLeftFatherPane; import com.fr.design.expand.ExpandUpFatherPane; -import com.fr.design.expand.SortExpandAttrPane; import com.fr.design.foldablepane.UIExpandablePane; import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.icheckbox.UICheckBox; @@ -13,6 +12,7 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.theme.utils.DefaultThemedTemplateCellElementCase; +import com.fr.design.sort.cellexpand.CellExpandSortPane; import com.fr.general.ComparatorUtils; import com.fr.general.IOUtils; import com.fr.report.cell.TemplateCellElement; @@ -38,11 +38,11 @@ public class CellExpandAttrPane extends AbstractCellAttrPane { private ExpandUpFatherPane rightFatherPane; private UICheckBox horizontalExpandableCheckBox; private UICheckBox verticalExpandableCheckBox; - private SortExpandAttrPane sortAfterExpand; private JPanel layoutPane; private JPanel basicPane; private JPanel seniorPane; private CellExpandExtraAttrPane extraPane; + private CellExpandSortPane cellExpandSortPane; /** @@ -62,7 +62,6 @@ public class CellExpandAttrPane extends AbstractCellAttrPane { rightFatherPane = new ExpandUpFatherPane(); horizontalExpandableCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_ExpandD_Horizontal_Extendable")); verticalExpandableCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_ExpandD_Vertical_Extendable")); - sortAfterExpand = new SortExpandAttrPane(); initAllNames(); return layoutPane(); } @@ -81,8 +80,11 @@ public class CellExpandAttrPane extends AbstractCellAttrPane { seniorPane = new JPanel(); basicPane = new UIExpandablePane(Toolkit.i18nText("Fine-Design_Report_Basic"), 223, 24, basicPane()); seniorPane = new UIExpandablePane(Toolkit.i18nText("Fine-Design_Report_Advanced"), 223, 24, seniorPane()); + JPanel sortUIExpandablePane = new UIExpandablePane(Toolkit.i18nText("Fine-Design_Report_Expend_Sort"), + 223, 24, cellExpandSortPane = new CellExpandSortPane(this)); layoutPane.add(basicPane, BorderLayout.NORTH); layoutPane.add(seniorPane, BorderLayout.CENTER); + layoutPane.add(sortUIExpandablePane, BorderLayout.SOUTH); extraPane = CellExpandExtraAttrPane.getInstance(); @@ -119,16 +121,12 @@ public class CellExpandAttrPane extends AbstractCellAttrPane { private JPanel seniorPane() { double f = TableLayout.FILL; double p = TableLayout.PREFERRED; - UILabel expendSort = new UILabel(Toolkit.i18nText("Fine-Design_Report_Expend_Sort"), SwingConstants.LEFT); - JPanel expendSortPane = new JPanel(new BorderLayout()); - expendSortPane.add(expendSort, BorderLayout.NORTH); horizontalExpandableCheckBox.setBorder(UIConstants.CELL_ATTR_ZEROBORDER); verticalExpandableCheckBox.setBorder(UIConstants.CELL_ATTR_ZEROBORDER); Component[][] components = new Component[][]{ new Component[]{null, null}, new Component[]{horizontalExpandableCheckBox, null}, new Component[]{verticalExpandableCheckBox, null}, - new Component[]{expendSortPane, sortAfterExpand}, }; double[] rowSize = {p, p, p, p, p}; double[] columnSize = {p, f}; @@ -169,9 +167,8 @@ public class CellExpandAttrPane extends AbstractCellAttrPane { } } - sortAfterExpand.populate(cellExpandAttr); - extraPane.populate(cellElement); + cellExpandSortPane.populateBean(cellElement); } @@ -217,11 +214,8 @@ public class CellExpandAttrPane extends AbstractCellAttrPane { } } - if (ComparatorUtils.equals(getGlobalName(), Toolkit.i18nText("Fine-Design_Basic_ExpandD_Sort_After_Expand"))) { - sortAfterExpand.update(cellExpandAttr); - } - extraPane.update(cellElement); + cellExpandSortPane.updateBean(cellElement); } /** diff --git a/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortGroupPane.java b/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortGroupPane.java new file mode 100644 index 000000000..788f1a57c --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortGroupPane.java @@ -0,0 +1,40 @@ +package com.fr.design.sort.celldscolumn; + +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.tabledata.wrapper.TableDataWrapper; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.sort.common.AbstractSortGroupPane; +import com.fr.design.sort.common.AbstractSortItemPane; +import com.fr.report.cell.cellattr.core.group.DSColumn; +import com.fr.report.core.sort.sortexpression.SortExpression; + +public class CellDSColumnSortGroupPane extends AbstractSortGroupPane { + DSColumn dsColumn; + + public CellDSColumnSortGroupPane(int sortGroupPaneWidth, int sortGroupPaneRightWidth) { + super(sortGroupPaneWidth, sortGroupPaneRightWidth); + } + + public void populateDsColumn(DSColumn dsColumn) { + this.dsColumn = dsColumn; + } + + @Override + protected AbstractSortItemPane refreshSortItemPane(int sortItemPaneWidth, int sortItemPaneRightWidth, SortExpression sortExpression) { + CellDSColumnSortItemPane cellDSColumnSortItemPane = new CellDSColumnSortItemPane(sortItemPaneWidth, sortItemPaneRightWidth); + java.util.Map tableDataWrapperMap = + DesignTableDataManager.getAllEditingDataSet(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getTarget()); + TableDataWrapper tableDataWrapper = tableDataWrapperMap.get(dsColumn.getDSName()); + if (tableDataWrapper != null) { + java.util.List columnNameList = tableDataWrapper.calculateColumnNameList(); + String[] columnNames = new String[columnNameList.size()]; + columnNameList.toArray(columnNames); + cellDSColumnSortItemPane.sortAreaUiComboBox.removeAllItems(); + for (String columnName : columnNames) { + cellDSColumnSortItemPane.sortAreaUiComboBox.addItem(columnName); + } + } + cellDSColumnSortItemPane.populateBean(sortExpression); + return cellDSColumnSortItemPane; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortItemPane.java b/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortItemPane.java new file mode 100644 index 000000000..0c202fe0e --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortItemPane.java @@ -0,0 +1,40 @@ +package com.fr.design.sort.celldscolumn; + +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.sort.common.AbstractSortItemPane; +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.report.core.sort.sortexpression.SortExpression; + +import javax.swing.*; +import java.awt.*; + + +public class CellDSColumnSortItemPane extends AbstractSortItemPane { + + UIComboBox sortAreaUiComboBox; + + public CellDSColumnSortItemPane(int sortItemPaneWidth, int sortItemPaneRightWidth) { + super(sortItemPaneWidth, sortItemPaneRightWidth); + } + + @Override + public void initMainSortAreaPane(JPanel sortAreaPane) { + sortAreaUiComboBox = new UIComboBox(new String[0]); + sortAreaUiComboBox.setPreferredSize(new Dimension(sortItemPaneRightWidth, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + sortAreaPane.add(sortAreaUiComboBox); + } + + public void populateBean(SortExpression sortExpression) { + sortAreaUiComboBox.setSelectedItem(sortExpression.getSortArea()); + super.populateBean(sortExpression); + } + + public SortExpression updateBean() { + SortExpression sortExpression = super.updateBean(); + if (sortExpression != null && sortAreaUiComboBox.getSelectedItem() != null) { + sortExpression.setSortArea(sortAreaUiComboBox.getSelectedItem().toString()); + } + return sortExpression; + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortPane.java b/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortPane.java new file mode 100644 index 000000000..b5175e7fa --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/celldscolumn/CellDSColumnSortPane.java @@ -0,0 +1,62 @@ +package com.fr.design.sort.celldscolumn; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.general.data.TableDataColumn; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.cell.cellattr.core.group.DSColumn; +import com.fr.report.core.sort.common.CellSortAttr; + +import javax.swing.*; + + +public class CellDSColumnSortPane extends AbstractSortPane { + + public CellDSColumnSortPane() { + super(220, 150); + //this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + } + + @Override + protected void initSortGroupPane() { + sortGroupPane = new CellDSColumnSortGroupPane(sortPaneWidth, sortPaneRightWidth); + this.add(sortGroupPane); + } + + @Override + protected CellSortAttr getCellSortAttr(TemplateCellElement cellElement) { + if (cellElement.getValue() instanceof DSColumn) { + DSColumn dsColumn = ((DSColumn) cellElement.getValue()); + if (dsColumn.getCellSortAttr() == null) { + dsColumn.setCellSortAttr(new CellSortAttr()); + } + return dsColumn.getCellSortAttr(); + } + return null; + } + + protected void populateSortArea(TemplateCellElement cellElement) { + super.populateSortArea(cellElement); + if (cellElement.getValue() instanceof DSColumn) { + DSColumn dsColumn = ((DSColumn) cellElement.getValue()); + TableDataColumn tableDataColumn = dsColumn.getColumn(); + if (tableDataColumn instanceof TableDataColumn) { + selfSortArea = TableDataColumn.getColumnName(tableDataColumn); + } + } + } + + public void populateBean(TemplateCellElement cellElement) { + if (cellElement.getValue() instanceof DSColumn) { + DSColumn dsColumn = ((DSColumn) cellElement.getValue()); + if (sortGroupPane != null) { + ((CellDSColumnSortGroupPane) sortGroupPane).populateDsColumn(dsColumn); + } + } + super.populateBean(cellElement); + } + + protected boolean needSortHeaderPane() { + return false; + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortGroupPane.java b/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortGroupPane.java new file mode 100644 index 000000000..62cb37e91 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortGroupPane.java @@ -0,0 +1,19 @@ +package com.fr.design.sort.cellexpand; + +import com.fr.design.sort.common.AbstractSortGroupPane; +import com.fr.design.sort.common.AbstractSortItemPane; +import com.fr.report.core.sort.sortexpression.SortExpression; + +public class CellExpandSortGroupPane extends AbstractSortGroupPane { + + public CellExpandSortGroupPane(int sortGroupPaneWidth, int sortGroupPaneRightWidth) { + super(sortGroupPaneWidth, sortGroupPaneRightWidth); + } + + @Override + protected AbstractSortItemPane refreshSortItemPane(int sortItemPaneWidth, int sortItemPaneRightWidth, SortExpression sortExpression) { + AbstractSortItemPane abstractSortItemPane = new CellExpandSortItemPane( sortItemPaneWidth, sortItemPaneRightWidth); + abstractSortItemPane.populateBean(sortExpression); + return abstractSortItemPane; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortItemPane.java b/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortItemPane.java new file mode 100644 index 000000000..4b14dc692 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortItemPane.java @@ -0,0 +1,37 @@ +package com.fr.design.sort.cellexpand; + +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.design.sort.common.SortColumnRowPane; +import com.fr.design.sort.common.AbstractSortItemPane; +import com.fr.report.core.sort.sortexpression.SortExpression; +import com.fr.stable.ColumnRow; + +import javax.swing.*; + +public class CellExpandSortItemPane extends AbstractSortItemPane { + SortColumnRowPane columnRowPane; + + public CellExpandSortItemPane(int sortItemPaneWidth, int sortItemPaneRightWidth) { + super(sortItemPaneWidth, sortItemPaneRightWidth); + } + + @Override + public void initMainSortAreaPane(JPanel sortAreaPane) { + columnRowPane = new SortColumnRowPane(sortItemPaneRightWidth + 4, AbstractSortPane.PANE_COMPONENT_HEIGHT); + sortAreaPane.add(columnRowPane); + } + + public void populateBean(SortExpression sortExpression) { + columnRowPane.populateBean(ColumnRow.valueOf(sortExpression.getSortArea())); + super.populateBean(sortExpression); + } + + public SortExpression updateBean() { + SortExpression sortExpression = super.updateBean(); + if (sortExpression != null) { + ColumnRow columnRow = columnRowPane.updateBean(); + sortExpression.setSortArea(columnRow == null ? null : columnRow.toString()); + } + return sortExpression; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortPane.java b/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortPane.java new file mode 100644 index 000000000..5bfc20eea --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/cellexpand/CellExpandSortPane.java @@ -0,0 +1,39 @@ +package com.fr.design.sort.cellexpand; + + +import com.fr.design.mainframe.cell.settingpane.CellExpandAttrPane; +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.cell.cellattr.CellExpandAttr; +import com.fr.report.core.sort.common.CellSortAttr; + + +import javax.swing.*; + +public class CellExpandSortPane extends AbstractSortPane { + CellExpandAttrPane cellExpandAttrPane; + + public CellExpandSortPane(CellExpandAttrPane cellExpandAttrPane) { + super(227, 155); + this.cellExpandAttrPane = cellExpandAttrPane; + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + } + + @Override + protected void initSortGroupPane() { + sortGroupPane = new CellExpandSortGroupPane(sortPaneWidth, sortPaneRightWidth); + this.add(sortGroupPane); + } + + @Override + protected CellSortAttr getCellSortAttr(TemplateCellElement cellElement) { + CellExpandAttr cellExpandAttr = cellElement.getCellExpandAttr(); + if (cellExpandAttr != null) { + if (cellExpandAttr.getCellSortAttr() == null) { + cellExpandAttr.setCellSortAttr(new CellSortAttr()); + } + return cellExpandAttr.getCellSortAttr(); + } + return null; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortGroupPane.java b/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortGroupPane.java new file mode 100644 index 000000000..db6f574bd --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortGroupPane.java @@ -0,0 +1,152 @@ +package com.fr.design.sort.common; + +import com.fr.base.svg.IconUtils; +import com.fr.design.event.ComponentChangeListener; +import com.fr.design.event.ComponentChangeObserver; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.i18n.Toolkit; +import com.fr.report.core.sort.sortexpression.CellSortExpression; +import com.fr.report.core.sort.sortexpression.SortExpression; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + + +public abstract class AbstractSortGroupPane extends JPanel implements ComponentChangeObserver { + + private static final int SECOND_SORT_LENGTH_REDUCTION = 13; + + protected int sortGroupPaneWidth; + protected int sortGroupPaneRightWidth; + List sortExpressions; + List sortUIExpandablePanes = new ArrayList<>(); + AddSortItemBar addSortItemBar; + JPanel sortItemListPane; + UIButton uiButton; + String selfSortArea; + + ComponentChangeListener componentChangeListener; + + public AbstractSortGroupPane(int sortGroupPaneWidth, int sortGroupPaneRightWidth) { + this.sortGroupPaneRightWidth = sortGroupPaneRightWidth; + this.sortGroupPaneWidth = sortGroupPaneWidth; + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + initComponents(); + } + + private void initComponents() { + addSortItemBar = new AddSortItemBar(this); + sortItemListPane = new JPanel(); + sortItemListPane.setLayout(new BoxLayout(sortItemListPane, BoxLayout.Y_AXIS)); + this.add(sortItemListPane); + this.add(addSortItemBar); + } + + public void populateBean(List sortExpressions, String selfSortArea) { + this.sortItemListPane.removeAll(); + this.selfSortArea = selfSortArea; + this.sortExpressions = sortExpressions; + this.sortUIExpandablePanes = new ArrayList<>(); + for (int i = 0; i < sortExpressions.size(); i++) { + addSortItem(sortExpressions.get(i)); + } + refresh(); + } + + protected abstract AbstractSortItemPane refreshSortItemPane(int sortItemPaneWidth, int sortItemPaneRightWidth, SortExpression sortExpression); + + public List updateBean() { + List sortExpressions = new ArrayList<>(); + for (SortUIExpandablePane sortUIExpandablePane : sortUIExpandablePanes) { + SortExpression sortExpression = null; + if (sortUIExpandablePane != null) { + AbstractSortItemPane abstractSortItemPane + = (AbstractSortItemPane) sortUIExpandablePane.getContentPane(); + if (abstractSortItemPane != null) { + sortExpression = abstractSortItemPane.updateBean(); + } + } + if (sortExpression != null) { + sortExpressions.add(sortExpression); + } + } + return sortExpressions; + } + + + public void removeSortItem(int no) { + if (no < sortExpressions.size()) { + sortItemListPane.remove(sortUIExpandablePanes.get(no)); + sortExpressions.remove(no); + sortUIExpandablePanes.remove(no); + refresh(); + } + } + + public void removeSortItem(SortUIExpandablePane sortUIExpandablePane) { + for (int i = 0; i < sortUIExpandablePanes.size(); i++) { + if (sortUIExpandablePanes.get(i) == sortUIExpandablePane) { + removeSortItem(i); + return; + } + } + + } + + public void registerChangeListener(ComponentChangeListener componentChangeListener) { + this.componentChangeListener = componentChangeListener; + } + + public void addSortItem(SortExpression sortExpression) { + int sortItemPaneWidth = sortGroupPaneWidth - SECOND_SORT_LENGTH_REDUCTION; + int sortItemPaneRightWidth = sortGroupPaneRightWidth - SECOND_SORT_LENGTH_REDUCTION; + + if (sortExpression == null) { + sortExpression = new CellSortExpression(selfSortArea); + sortExpressions.add(sortExpression); + } + + AbstractSortItemPane abstractSortItemPane = + refreshSortItemPane(sortItemPaneWidth, sortItemPaneRightWidth, sortExpression); + + SortUIExpandablePane sortUIExpandablePane = new SortUIExpandablePane(abstractSortItemPane, this); + sortItemListPane.add(sortUIExpandablePane); + sortUIExpandablePanes.add(sortUIExpandablePane); + if (componentChangeListener != null) { + componentChangeListener.initListener(sortUIExpandablePane); + } + refresh(); + } + + protected void refresh() { + validate(); + repaint(); + revalidate(); + } + + class AddSortItemBar extends JPanel { + AbstractSortGroupPane sortGroupPane; + + AddSortItemBar(AbstractSortGroupPane sortGroupPane) { + init(); + this.sortGroupPane = sortGroupPane; + this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 5)); + } + + void init() { + uiButton = new UIButton(Toolkit.i18nText("Fine-Design_Sort_Add_Second_Sort"), + IconUtils.readIcon("/com/fr/design/images/sort/add.png")); + uiButton.setPreferredSize(new Dimension(sortGroupPaneWidth - 4, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + this.add(uiButton); + uiButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + sortGroupPane.addSortItem(null); + } + }); + } + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortItemPane.java b/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortItemPane.java new file mode 100644 index 000000000..82d14bb7e --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortItemPane.java @@ -0,0 +1,153 @@ +package com.fr.design.sort.common; + +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.sort.expressionpane.CellSortExpressionPane; +import com.fr.design.sort.expressionpane.CustomSequenceSortExpressionPane; +import com.fr.design.sort.expressionpane.FormulaSortExpressionPane; +import com.fr.design.sort.expressionpane.SortExpressionPane; +import com.fr.report.core.sort.sortexpression.SortExpression; +import com.fr.report.core.sort.common.SortRule; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractSortItemPane extends JPanel { + protected int sortItemPaneWidth; + protected int sortItemPaneRightWidth; + List sortExpressionPanes = new ArrayList<>(); + SortExpressionPane currentSortExpressionPane = null; + JPanel sortBasisPanel = null; + UIComboBox sortRuleUiComboBox; + UIComboBox sortBasisUiComboBox; + JPanel sortAreaPane; + JPanel sortRulePane; + + public AbstractSortItemPane(int sortItemPaneWidth, int sortItemPaneRightWidth) { + this.sortItemPaneWidth = sortItemPaneWidth; + this.sortItemPaneRightWidth = sortItemPaneRightWidth; + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + registerSortExpressionPanes(); + initComponents(); + } + + private void initComponents() { + initSortAreaPane(); + initSortBasisPanel(); + initSortRulePane(); + } + + private void registerSortExpressionPanes() { + sortExpressionPanes.add(new CellSortExpressionPane(sortItemPaneRightWidth)); + sortExpressionPanes.add(new FormulaSortExpressionPane(sortItemPaneRightWidth)); + sortExpressionPanes.add(new CustomSequenceSortExpressionPane(sortItemPaneWidth, sortItemPaneRightWidth)); + } + + void initSortAreaPane() { + sortAreaPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, AbstractSortPane.PANE_COMPONENT_V_GAP)); + sortAreaPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Sort_Sort_Area"), SwingConstants.LEFT)); + sortAreaPane.add(AbstractSortPane.createIntervalUILabel()); + initMainSortAreaPane(sortAreaPane); + this.add(sortAreaPane); + } + + public abstract void initMainSortAreaPane(JPanel sortAreaPane); + + void initSortRulePane() { + sortRulePane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, AbstractSortPane.PANE_COMPONENT_V_GAP)); + sortRuleUiComboBox = new UIComboBox(new String[]{SortRule.ASC.getDescription(), + SortRule.DES.getDescription(), SortRule.NO_SORT.getDescription()}); + sortRuleUiComboBox.setPreferredSize(new Dimension(sortItemPaneRightWidth, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + sortRulePane.add(new UILabel(Toolkit.i18nText("Fine-Design_Sort_Sort_Rule"), SwingConstants.LEFT)); + sortRulePane.add(AbstractSortPane.createIntervalUILabel()); + sortRulePane.add(sortRuleUiComboBox); + this.add(sortRulePane); + } + + void initSortBasisPanel() { + sortBasisPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, AbstractSortPane.PANE_COMPONENT_V_GAP)); + sortBasisUiComboBox = new UIComboBox(getSortNames()); + sortBasisUiComboBox.setPreferredSize(new Dimension(sortItemPaneRightWidth, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + sortBasisUiComboBox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (sortExpressionPanes.get(sortBasisUiComboBox.getSelectedIndex()) != currentSortExpressionPane) { + if (currentSortExpressionPane != null) { + currentSortExpressionPane.setVisible(false); + } + currentSortExpressionPane = sortExpressionPanes.get(sortBasisUiComboBox.getSelectedIndex()); + refreshCurrentSortExpressionPane(); + } + } + }); + sortBasisPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Sort_Sort_Basis"), SwingConstants.LEFT)); + sortBasisPanel.add(AbstractSortPane.createIntervalUILabel()); + sortBasisPanel.add(sortBasisUiComboBox); + this.add(sortBasisPanel); + for (SortExpressionPane sortExpressionPane : sortExpressionPanes) { + this.add(sortExpressionPane); + sortExpressionPane.setVisible(false); + } + } + + private void refreshCurrentSortExpressionPane() { + currentSortExpressionPane.setVisible(true); + sortAreaPane.setVisible(currentSortExpressionPane.needSortArea()); + sortRulePane.setVisible(currentSortExpressionPane.needSortRule()); + } + + private String[] getSortNames() { + String[] sortNames = new String[sortExpressionPanes.size()]; + for (int i = 0; i < sortExpressionPanes.size(); i++) { + sortNames[i] = sortExpressionPanes.get(i).getSortName(); + } + return sortNames; + } + + public void populateBean(SortExpression sortExpression) { + if (sortExpression.getSortRule() == SortRule.ASC) { + sortRuleUiComboBox.setSelectedIndex(0); + } else if (sortExpression.getSortRule() == SortRule.DES) { + sortRuleUiComboBox.setSelectedIndex(1); + } else if (sortExpression.getSortRule() == SortRule.NO_SORT) { + sortRuleUiComboBox.setSelectedIndex(2); + } + for (int i = 0; i < sortExpressionPanes.size(); i++) { + if (StringUtils.equals(sortExpression.getSortName(), sortExpressionPanes.get(i).getSortName())) { + if (currentSortExpressionPane != null) { + currentSortExpressionPane.setVisible(false); + } + currentSortExpressionPane = sortExpressionPanes.get(i); + currentSortExpressionPane.populateBean(sortExpression); + sortBasisUiComboBox.setSelectedIndex(i); + refreshCurrentSortExpressionPane(); + break; + } + } + refresh(); + } + + public SortExpression updateBean() { + SortExpression sortExpression = currentSortExpressionPane.updateBean(); + if (sortExpression != null) { + String sortRule = sortRuleUiComboBox.getSelectedItem().toString(); + if (StringUtils.isNotBlank(sortRule)) { + sortExpression.setSortRule(SortRule.parse(sortRule)); + } + } + return sortExpression; + } + + protected void refresh() { + validate(); + repaint(); + revalidate(); + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortPane.java b/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortPane.java new file mode 100644 index 000000000..6491d04a8 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortPane.java @@ -0,0 +1,112 @@ +package com.fr.design.sort.common; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.sort.header.SortHeaderPane; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.core.sort.common.CellSortAttr; +import com.fr.report.core.sort.sortexpression.CellSortExpression; +import com.fr.report.core.sort.sortexpression.SortExpression; +import com.fr.report.core.sort.header.SortHeader; +import com.fr.stable.ColumnRow; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + + +public abstract class AbstractSortPane extends JPanel { + protected int sortPaneWidth; + protected int sortPaneRightWidth; + public static final int PANE_COMPONENT_HEIGHT = 20; + public static final int PANE_COMPONENT_V_GAP = 4; + public static final int PANE_COMPONENT_H_GAP = 14; + protected AbstractSortGroupPane sortGroupPane; + protected SortHeaderPane sortHeaderPane; + protected String selfSortArea; + protected String defaultHeaderArea; + + public AbstractSortPane(int sortPaneWidth, int sortPaneRightWidth) { + this.sortPaneWidth = sortPaneWidth; + this.sortPaneRightWidth = sortPaneRightWidth; + initComponents(); + } + + private void initComponents() { + initSortGroupPane(); + if (needSortHeaderPane()) { + sortHeaderPane = new SortHeaderPane(sortPaneWidth, sortPaneRightWidth + 5); + this.add(sortHeaderPane); + } + } + + protected abstract void initSortGroupPane(); + + + protected boolean needSortHeaderPane() { + return true; + } + + protected abstract CellSortAttr getCellSortAttr(TemplateCellElement cellElement); + + public void populateBean(TemplateCellElement cellElement) { + populateSortArea(cellElement); + List sortExpressions = null; + CellSortAttr cellSortAttr = getCellSortAttr(cellElement); + if (cellSortAttr != null) { + sortExpressions = cellSortAttr.getSortExpressions(); + } + if (sortExpressions == null) { + sortExpressions = new ArrayList<>(); + } + sortGroupPane.populateBean(sortExpressions, selfSortArea); + if (needSortHeaderPane()) { + SortHeader sortHeader = null; + if (cellSortAttr != null) { + sortHeader = cellSortAttr.getSortHeader(); + } + sortHeaderPane.populateBean(sortHeader, defaultHeaderArea); + } + refresh(); + } + + protected void populateSortArea(TemplateCellElement cellElement) { + int row = cellElement.getRow(); + int column = cellElement.getColumn(); + selfSortArea = ColumnRow.valueOf(column, row).toString(); + if (row > 0) { + defaultHeaderArea = ColumnRow.valueOf(column, row - 1).toString(); + } else { + defaultHeaderArea = null; + } + } + + public void updateBean(TemplateCellElement cellElement) { + List sortExpressions = sortGroupPane.updateBean(); + CellSortAttr cellSortAttr = getCellSortAttr(cellElement); + cellSortAttr.setSortExpressions(sortExpressions); + if (needSortHeaderPane()) { + SortHeader sortHeader = sortHeaderPane.updateBean(cellElement); + if (sortHeader != null) { + sortHeader.setSortArea(selfSortArea); + } + cellSortAttr.setSortHeader(sortHeader); + } + } + + protected void refresh() { + validate(); + repaint(); + revalidate(); + } + + public static UILabel createIntervalUILabel() { + return createIntervalUILabel(PANE_COMPONENT_H_GAP); + } + + public static UILabel createIntervalUILabel(int vGap) { + UILabel uiLabel = new UILabel(); + uiLabel.setPreferredSize(new Dimension(vGap, 10)); + return uiLabel; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/common/SortColumnRowPane.java b/designer-realize/src/main/java/com/fr/design/sort/common/SortColumnRowPane.java new file mode 100644 index 000000000..67a9aaff1 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/common/SortColumnRowPane.java @@ -0,0 +1,277 @@ +package com.fr.design.sort.common; + +import com.fr.base.Style; +import com.fr.base.background.ColorBackground; +import com.fr.base.svg.IconUtils; +import com.fr.design.designer.TargetComponent; +import com.fr.design.event.UIObserver; +import com.fr.design.event.UIObserverListener; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.mainframe.ElementCasePane; +import com.fr.design.selection.SelectionEvent; +import com.fr.design.selection.SelectionListener; +import com.fr.design.sort.header.HeaderAreaPane; +import com.fr.grid.selection.CellSelection; +import com.fr.grid.selection.Selection; +import com.fr.log.FineLoggerFactory; +import com.fr.report.cell.DefaultTemplateCellElement; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.cell.cellattr.CellExpandAttr; +import com.fr.report.cell.cellattr.core.group.DSColumn; +import com.fr.report.core.sort.common.CellSortable; +import com.fr.report.core.sort.header.SortHeader; +import com.fr.report.elementcase.TemplateElementCase; +import com.fr.stable.ColumnRow; +import com.fr.stable.EssentialUtils; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class SortColumnRowPane extends JPanel implements UIObserver { + int paneWidth; + int paneHeight; + int jTextFieldWidth; + JTextField colJTextField; + JTextField rowJTextField; + UIButton selectButton; + private boolean isAlreadyAddListener = false; + private CellSelection oldSelection; + private SelectionListener gridSelectionChangeListener; + UIObserverListener uiObserverListener; + private final static Icon DISABLED_ICON = IconUtils.readIcon("/com/fr/design/images/buttonicon/select_disabled.svg"); + private final static Icon ENABLE_ICON = IconUtils.readIcon("/com/fr/design/images/buttonicon/select_normal.svg"); + private boolean enabled; + + HeaderAreaPane.CellSelectionManager cellSelectionManager; + + public SortColumnRowPane(int paneWidth, int paneHeight) { + this.paneWidth = paneWidth; + this.paneHeight = paneHeight; + initComponents(); + } + + private void initComponents() { + initSize(); + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + intUILabel(); + initTextField(); + initSelectButton(); + this.setSize(new Dimension(paneWidth, paneHeight)); + } + + void initSize() { + jTextFieldWidth = (paneWidth - 40) / 2; + } + + void intUILabel() { + UILabel uiLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/buttonicon/propertiestab/cellelement_normal.png")); + this.add(uiLabel); + } + + public static boolean isAvailableColumnRow(ColumnRow columnRow) { + return columnRow != null && columnRow.getRow() != -1 && columnRow.getColumn() != -1; + } + + void initTextField() { + colJTextField = new JTextField(); + colJTextField.setEditable(false); + rowJTextField = new JTextField(); + rowJTextField.setEditable(false); + colJTextField.setPreferredSize(new Dimension(jTextFieldWidth, paneHeight)); + rowJTextField.setPreferredSize(new Dimension(jTextFieldWidth, paneHeight)); + this.add(colJTextField); + this.add(rowJTextField); + } + + void initSelectButton() { + selectButton = new UIButton(ENABLE_ICON); + selectButton.addMouseListener(new SelectActionListener(this)); + this.add(selectButton); + } + + public void populateBean(ColumnRow columnRow, boolean enabled, HeaderAreaPane.CellSelectionManager cellSelectionManager) { + this.cellSelectionManager = cellSelectionManager; + populateBean(columnRow, enabled); + } + + public void populateBean(ColumnRow columnRow) { + populateBean(columnRow, true); + } + + public void populateBean(ColumnRow columnRow, boolean enabled) { + this.enabled = enabled; + if (SortColumnRowPane.isAvailableColumnRow(columnRow)) { + colJTextField.setText(EssentialUtils.convertIntToABC(columnRow.column + 1)); + rowJTextField.setText(String.valueOf(columnRow.row + 1)); + } else { + colJTextField.setText(StringUtils.EMPTY); + rowJTextField.setText(StringUtils.EMPTY); + } + if (enabled) { + selectButton.setIcon(ENABLE_ICON); + } else { + selectButton.setIcon(DISABLED_ICON); + } + selectButton.setEnabled(false); + refresh(); + } + + public void setColumnRow(ColumnRow columnRow) { + populateBean(columnRow); + uiObserverListener.doChange(); + } + + public ColumnRow updateBean() { + if (StringUtils.isNotBlank(colJTextField.getText()) && StringUtils.isNotBlank(rowJTextField.getText())) { + return ColumnRow.valueOf(colJTextField.getText() + rowJTextField.getText()); + } + return ColumnRow.ERROR; + } + + @Override + public void registerChangeListener(UIObserverListener listener) { + this.uiObserverListener = listener; + } + + @Override + public boolean shouldResponseChangeListener() { + return true; + } + + class SelectActionListener extends MouseAdapter { + SortColumnRowPane columnRowPane; + ColumnRow oldColumnRow; + + Map disableHeaderCellsStyleMap = new HashMap<>(); + java.util.List tempHeaderCells = new ArrayList<>(); + + SelectActionListener(SortColumnRowPane columnRowPane) { + this.columnRowPane = columnRowPane; + } + + @Override + public void mouseClicked(MouseEvent e) { + if (enabled) { + ElementCasePane elementCasePane = getCurrentElementCase(); + if (elementCasePane == null || isAlreadyAddListener) { + return; + } + oldColumnRow = columnRowPane.updateBean(); + prepareSelectHeader(elementCasePane); + gridSelectionChangeListener = new SelectionListener() { + @Override + public void selectionChanged(SelectionEvent e) { + completeSelectHeader(elementCasePane); + } + }; + elementCasePane.addSelectionChangeListener(gridSelectionChangeListener); + isAlreadyAddListener = true; + } + } + + private void prepareSelectHeader(ElementCasePane elementCasePane) { + ashDisableHeaderCellsStyle(elementCasePane.getEditingElementCase()); + oldSelection = (CellSelection) elementCasePane.getSelection(); + elementCasePane.getGrid().setNotShowingTableSelectPane(false); + elementCasePane.setRepeatSelection(true); + elementCasePane.setEditable(false); + elementCasePane.repaint(10); + } + + private void completeSelectHeader(ElementCasePane elementCasePane) { + Selection selection = elementCasePane.getSelection(); + if (selection instanceof CellSelection) { + CellSelection cellselection = (CellSelection) selection; + ColumnRow columnRow = ColumnRow.valueOf(cellselection.getColumn(), cellselection.getRow()); + elementCasePane.setOldSelecton(oldSelection); + oldSelection.getQuickEditor(elementCasePane); + if (cellSelectionManager == null || !cellSelectionManager.isNotSelectables(columnRow)) { + if (cellSelectionManager != null) { + cellSelectionManager.removeNotSelectables(oldColumnRow); + cellSelectionManager.addNotSelectables(columnRow); + } + columnRowPane.setColumnRow(columnRow); + } + restoreDisableHeaderCellsStyle(elementCasePane.getEditingElementCase()); + } + elementCasePane.removeSelectionChangeListener(gridSelectionChangeListener); + isAlreadyAddListener = false; + elementCasePane.getGrid().setNotShowingTableSelectPane(true); + elementCasePane.setRepeatSelection(false); + elementCasePane.setEditable(true); + elementCasePane.repaint(); + oldColumnRow = null; + } + + private void ashDisableHeaderCellsStyle(TemplateElementCase elementCase) { + if (cellSelectionManager != null) { + java.util.List notSelectables = cellSelectionManager.getNotSelectables(); + disableHeaderCellsStyleMap = new HashMap<>(); + tempHeaderCells = new ArrayList<>(); + for (ColumnRow columnRow : notSelectables) { + TemplateCellElement templateCellElement + = elementCase.getTemplateCellElement(columnRow.column, columnRow.row); + if (templateCellElement == null) { + templateCellElement = new DefaultTemplateCellElement(columnRow.column, columnRow.row); + elementCase.addCellElement(templateCellElement); + tempHeaderCells.add(templateCellElement); + } + Style style = templateCellElement.getStyle(); + disableHeaderCellsStyleMap.put(columnRow, style); + style = style.deriveBackground(ColorBackground.getInstance(Color.gray)); + templateCellElement.setStyle(style); + } + } + + } + + private void restoreDisableHeaderCellsStyle(TemplateElementCase elementCase) { + if (cellSelectionManager != null) { + try { + for (ColumnRow headerColumnRow : disableHeaderCellsStyleMap.keySet()) { + TemplateCellElement headerTemplateCellElement + = elementCase.getTemplateCellElement(headerColumnRow.column, headerColumnRow.row); + headerTemplateCellElement.setStyle(disableHeaderCellsStyleMap.get(headerColumnRow)); + } + for (TemplateCellElement templateCellElement : tempHeaderCells) { + elementCase.removeCellElement(templateCellElement); + } + disableHeaderCellsStyleMap = new HashMap<>(); + tempHeaderCells = new ArrayList<>(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + } + + } + } + + + protected void refresh() { + validate(); + repaint(); + revalidate(); + } + + public static ElementCasePane getCurrentElementCase() { + try { + TargetComponent targetComponent + = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getCurrentElementCasePane(); + if (targetComponent instanceof ElementCasePane) { + return (ElementCasePane) targetComponent; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return null; + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/sort/common/SortUIExpandablePane.java b/designer-realize/src/main/java/com/fr/design/sort/common/SortUIExpandablePane.java new file mode 100644 index 000000000..6de6636f4 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/common/SortUIExpandablePane.java @@ -0,0 +1,119 @@ +package com.fr.design.sort.common; + +import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; +import com.fr.design.event.UIObserver; +import com.fr.design.event.UIObserverListener; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + + +public class SortUIExpandablePane extends JPanel { + private static final long serialVersionUID = 1L; + private HeaderPane headerPane; + private AbstractSortItemPane contentPane; + private AbstractSortGroupPane sortGroupPane; + + private JPanel wrapPane; + private SortUIExpandablePane self = this; + + public JPanel getContentPane() { + return contentPane; + } + + + public SortUIExpandablePane(AbstractSortItemPane contentPane, AbstractSortGroupPane sortGroupPane) { + super(); + this.sortGroupPane = sortGroupPane; + this.contentPane = contentPane; + initComponents(); + wrapPane.setBorder(BorderFactory.createLineBorder(new Color(217, 218, 221), 1)); + wrapPane.setBackground(Color.WHITE); + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 5)); + } + + + private void initComponents() { + wrapPane = new JPanel(); + wrapPane.setLayout(new BorderLayout()); + headerPane = new HeaderPane(sortGroupPane); + headerPane.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + setContentPanelShow(!contentPane.isVisible()); + } + }); + headerPane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, new Color(217, 218, 221))); + contentPane.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); + wrapPane.add(headerPane, BorderLayout.NORTH); + wrapPane.add(contentPane, BorderLayout.CENTER); + setContentPanelShow(true); + this.add(wrapPane); + } + + + private void setContentPanelShow(Boolean show) { + contentPane.setVisible(show); + headerPane.setShow(show); + } + + class HeaderPane extends JPanel implements UIObserver { + UILabel iconUiLabel; + UILabel closeButton; + AbstractSortGroupPane sortGroupPane; + UIObserverListener uiObserverListener; + + HeaderPane(AbstractSortGroupPane sortGroupPane) { + this.sortGroupPane = sortGroupPane; + this.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0)); + initComponents(); + } + + private void initComponents() { + iconUiLabel = new UILabel(); + this.add(iconUiLabel); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Sort_Second_Sort")); + this.add(uiLabel); + this.add(AbstractSortPane.createIntervalUILabel(108)); + + closeButton = new UILabel(IconUtils.readIcon("/com/fr/design/images/control/close.png")); + closeButton.setPreferredSize(new Dimension(16, 20)); + this.add(closeButton); + closeButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + sortGroupPane.removeSortItem(self); + if (uiObserverListener != null) { + uiObserverListener.doChange(); + } + } + }); + this.setPreferredSize(new Dimension(contentPane.sortItemPaneWidth + 7, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + } + + public void setShow(boolean show) { + if (show) { + iconUiLabel.setIcon(IconUtils.readIcon("/com/fr/design/images/sort/down_arrow.png")); + } else { + iconUiLabel.setIcon(IconUtils.readIcon("/com/fr/design/images/sort/left_arrow.png")); + } + } + + @Override + public void registerChangeListener(UIObserverListener uiObserverListener) { + this.uiObserverListener = uiObserverListener; + } + + @Override + public boolean shouldResponseChangeListener() { + return true; + } + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CellSortExpressionPane.java b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CellSortExpressionPane.java new file mode 100644 index 000000000..1381b92cf --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CellSortExpressionPane.java @@ -0,0 +1,32 @@ +package com.fr.design.sort.expressionpane; + +import com.fr.design.i18n.Toolkit; +import com.fr.locale.InterProviderFactory; +import com.fr.report.core.sort.sortexpression.CellSortExpression; + + +import java.awt.*; + + +public class CellSortExpressionPane extends SortExpressionPane { + public CellSortExpressionPane(int with) { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + } + + @Override + public String getSortName() { + return InterProviderFactory.getProvider().getLocText("Fine-Engine_Sort_Cell"); + } + + @Override + public void populateBean(CellSortExpression cellSortExpression) { + + } + + @Override + public CellSortExpression updateBean() { + return new CellSortExpression(); + } + + +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceEditPane.java b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceEditPane.java new file mode 100644 index 000000000..c65657836 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceEditPane.java @@ -0,0 +1,190 @@ +package com.fr.design.sort.expressionpane; + +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ilist.UIList; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.alphafine.listener.DocumentAdapter; +import com.fr.design.mainframe.dnd.SerializableTransferable; +import com.fr.design.mainframe.share.ui.base.PlaceholderTextArea; +import com.fr.locale.InterProviderFactory; +import com.fr.report.core.sort.sortexpression.CustomSequenceSortExpression; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.util.ArrayList; +import java.util.List; + +public class CustomSequenceEditPane extends BasicPane { + java.util.List customSequence; + JSplitPane jSplitPane; + JPanel referenceSequencePanel; + JPanel editSequencePanel; + JTextArea jTextArea; + + CustomSequenceEditPane(java.util.List customSequence) { + this.customSequence = customSequence; + initComponents(); + } + + void initComponents() { + this.setLayout(new BorderLayout()); + initReferenceSequencePanel(); + initEditSequencePanel(); + initSplitPane(); + } + + void initSplitPane() { + jSplitPane = new JSplitPane(); + this.add(jSplitPane); + jSplitPane.setOneTouchExpandable(true); + jSplitPane.setContinuousLayout(true); + jSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT); + jSplitPane.setLeftComponent(referenceSequencePanel); + jSplitPane.setRightComponent(editSequencePanel); + jSplitPane.setDividerSize(10); + jSplitPane.setDividerLocation(200); + } + + void initReferenceSequencePanel() { + referenceSequencePanel = new JPanel(); + referenceSequencePanel.setLayout(new BoxLayout(referenceSequencePanel, BoxLayout.Y_AXIS)); + JPanel titlePane = new JPanel(new FlowLayout(FlowLayout.LEFT)); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Sort_Reference_Sequence")); + titlePane.add(uiLabel); + referenceSequencePanel.add(titlePane); + UIScrollPane uiScrollPane = new UIScrollPane(getReferenceSequenceList()); + uiScrollPane.setPreferredSize(new Dimension(200, 300)); + referenceSequencePanel.add(uiScrollPane); + referenceSequencePanel.setSize(new Dimension(200, 400)); + } + + private UIList getReferenceSequenceList() { + UIList uiList = new UIList(getReferenceSequenceModel()); + new CustomSequenceEditDragSource(uiList, DnDConstants.ACTION_MOVE); + return uiList; + } + + private String[] getReferenceSequenceModel() { + List> customSequences = CustomSequenceSortExpression.getReferenceCustomSequences(); + String[] listModel = new String[customSequences.size()]; + for (int i = 0; i < customSequences.size(); i++) { + listModel[i] = CustomSequenceSortExpression.customSequenceToString(customSequences.get(i), ","); + } + return listModel; + } + + void initEditSequencePanel() { + editSequencePanel = new JPanel(); + editSequencePanel.setLayout(new BoxLayout(editSequencePanel, BoxLayout.Y_AXIS)); + JPanel titlePane = new JPanel(new FlowLayout(FlowLayout.LEFT)); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Sort_Input_Sequence")); + titlePane.add(uiLabel); + UILabel uiLabel2 = new UILabel(Toolkit.i18nText("Fine-Design_Sort_Please_Interlace_Sequence_Elements")); + uiLabel2.setForeground(Color.lightGray); + titlePane.add(uiLabel2); + editSequencePanel.add(titlePane); + jTextArea = getTextArea(); + UIScrollPane uiScrollPane = new UIScrollPane(jTextArea); + uiScrollPane.setPreferredSize(new Dimension(475, 300)); + editSequencePanel.add(uiScrollPane); + editSequencePanel.setSize(new Dimension(475, 300)); + } + + + JTextArea getTextArea() { + PlaceholderTextArea placeholderTextArea = new PlaceholderTextArea(10, 10, getPlaceholderText()); + new CustomSequenceEditDropTarget(placeholderTextArea, CustomSequenceSortExpression.getReferenceCustomSequences()); + placeholderTextArea.setText(CustomSequenceSortExpression.customSequenceToString(customSequence, "\n")); + placeholderTextArea.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + placeholderTextArea.repaint(); + } + }); + return placeholderTextArea; + } + + String getPlaceholderText() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(Toolkit.i18nText("Fine-Design_Sort_Please_Interlace_Sequence_Elements_Such_As") + "\n"); + stringBuilder.append(Toolkit.i18nText("Fine-Design_Sort_Department_One") + "\n"); + stringBuilder.append(Toolkit.i18nText("Fine-Design_Sort_Department_Two") + "\n"); + stringBuilder.append(Toolkit.i18nText("Fine-Design_Sort_Department_Three") + "\n"); + return stringBuilder.toString(); + } + + @Override + protected String title4PopupWindow() { + return InterProviderFactory.getProvider().getLocText("Fine-Engine_Sort_Custom_Sequence"); + } + + + class CustomSequenceEditDragSource extends DragSourceAdapter implements DragGestureListener { + private DragSource source; + + public CustomSequenceEditDragSource(UIList uiList, int actions) { + source = new DragSource(); + source.createDefaultDragGestureRecognizer(uiList, actions, this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + Component comp = dge.getComponent(); + if (comp instanceof UIList) { + UIList uiList = (UIList) comp; + source.startDrag(dge, DragSource.DefaultLinkDrop, new SerializableTransferable(uiList.getSelectedIndex()), this); + } + } + } + + + class CustomSequenceEditDropTarget extends DropTargetAdapter { + java.util.List> customSequences = new ArrayList<>(); + + public CustomSequenceEditDropTarget(PlaceholderTextArea jPanel, java.util.List> customSequences) { + new DropTarget(jPanel, this); + this.customSequences = customSequences; + } + + @Override + public void drop(DropTargetDropEvent dtde) { + try { + Transferable transferable = dtde.getTransferable(); + DataFlavor[] dataFlavors = transferable.getTransferDataFlavors(); + if (dataFlavors.length == 1) { + Integer index = (Integer) transferable.getTransferData(dataFlavors[0]); + JTextArea jTextArea = (JTextArea) dtde.getDropTargetContext().getComponent(); + String text = jTextArea.getText(); + if (StringUtils.isNotEmpty(text) && !text.endsWith("\n")) { + text += "\n"; + } + java.util.List customSequence = customSequences.get(index); + for (int i = 0; i < customSequence.size(); i++) { + text += customSequence.get(i) + "\n"; + } + jTextArea.setText(text); + } + } catch (Exception e) { + + } + } + } + + public List updateBean() { + return CustomSequenceSortExpression.stringToCustomSequence(jTextArea.getText(), "\n"); + } + +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequencePane.java b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequencePane.java new file mode 100644 index 000000000..34fca093b --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequencePane.java @@ -0,0 +1,66 @@ +package com.fr.design.sort.expressionpane; + +import com.fr.base.svg.IconUtils; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.report.core.sort.sortexpression.CustomSequenceSortExpression; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + + +public class CustomSequencePane extends JPanel { + protected UITextField textField; + protected UIButton button; + List customSequence; + + public CustomSequencePane(int width) { + this.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0)); + this.initComponents(width); + } + + protected void initComponents(int width) { + textField = new UITextField(); + textField.setEditable(false); + textField.setPreferredSize(new Dimension(width - 20, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + Icon icon = IconUtils.readIcon("/com/fr/design/images/sort/sequence.png"); + button = new UIButton(icon); + button.setBackground(Color.RED); + button.setOpaque(false); + button.setCursor(new Cursor(Cursor.HAND_CURSOR)); + button.setPreferredSize(new Dimension(20, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + CustomSequenceEditPane customSequenceEditPane = new CustomSequenceEditPane(customSequence); + customSequenceEditPane.showWindowWithCustomSize(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + @Override + public void doOk() { + customSequence = customSequenceEditPane.updateBean(); + textField.setText(CustomSequenceSortExpression.customSequenceToString(customSequence, ",")); + } + }, new Dimension(700, 400)).setVisible(true); + } + }; + button.addMouseListener(mouseAdapter); + textField.addMouseListener(mouseAdapter); + this.add(textField); + this.add(button); + } + + + public List updateBean() { + return customSequence; + } + + public void populateBean(List customSequence) { + this.customSequence = customSequence; + textField.setText(CustomSequenceSortExpression.customSequenceToString(customSequence, ",")); + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceSortExpressionPane.java b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceSortExpressionPane.java new file mode 100644 index 000000000..69dac2a2a --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequenceSortExpressionPane.java @@ -0,0 +1,37 @@ +package com.fr.design.sort.expressionpane; + +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.locale.InterProviderFactory; +import com.fr.report.core.sort.sortexpression.CustomSequenceSortExpression; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + + +public class CustomSequenceSortExpressionPane extends SortExpressionPane { + CustomSequencePane customSequencePane; + + public CustomSequenceSortExpressionPane(int width, int rightWidth) { + this.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 0)); + customSequencePane = new CustomSequencePane(rightWidth + 5); + this.add(customSequencePane); + } + + @Override + public String getSortName() { + return InterProviderFactory.getProvider().getLocText("Fine-Engine_Sort_Custom_Sequence"); + } + + @Override + public void populateBean(CustomSequenceSortExpression customSequenceSortExpression) { + List customSequence = customSequenceSortExpression.getCustomSequence(); + customSequencePane.populateBean(customSequence); + } + + @Override + public CustomSequenceSortExpression updateBean() { + List customSequence = customSequencePane.updateBean(); + return new CustomSequenceSortExpression(customSequence); + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/expressionpane/FormulaSortExpressionPane.java b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/FormulaSortExpressionPane.java new file mode 100644 index 000000000..3785a7e97 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/FormulaSortExpressionPane.java @@ -0,0 +1,42 @@ +package com.fr.design.sort.expressionpane; + +import com.fr.design.formula.TinyFormulaPane; +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.locale.InterProviderFactory; +import com.fr.report.core.sort.sortexpression.FormulaSortExpression; + +import java.awt.*; + +public class FormulaSortExpressionPane extends SortExpressionPane { + + TinyFormulaPane tinyFormulaPane; + + public FormulaSortExpressionPane(int width) { + this.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 0)); + tinyFormulaPane = new TinyFormulaPane(); + tinyFormulaPane.setPreferredSize(new Dimension(width + 5, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + this.add(tinyFormulaPane); + } + + @Override + public String getSortName() { + return InterProviderFactory.getProvider().getLocText("Fine-Engine_Sort_Formula"); + } + + @Override + public void populateBean(FormulaSortExpression formulaSortExpression) { + String formula = formulaSortExpression.getFormula(); + tinyFormulaPane.getUITextField().setText(formula); + } + + @Override + public FormulaSortExpression updateBean() { + String formula = tinyFormulaPane.getUITextField().getText(); + return new FormulaSortExpression(formula); + } + + public boolean needSortArea() { + return false; + } + +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/expressionpane/SortExpressionPane.java b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/SortExpressionPane.java new file mode 100644 index 000000000..69af8464c --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/SortExpressionPane.java @@ -0,0 +1,23 @@ +package com.fr.design.sort.expressionpane; + +import com.fr.report.core.sort.sortexpression.SortExpression; + +import javax.swing.*; + + +public abstract class SortExpressionPane extends JPanel { + + public abstract String getSortName(); + + public abstract void populateBean(T sortExpression); + + public abstract T updateBean(); + + public boolean needSortArea() { + return true; + } + + public boolean needSortRule() { + return true; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java new file mode 100644 index 000000000..5ae972dbc --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java @@ -0,0 +1,267 @@ +package com.fr.design.sort.header; + +import com.fr.design.designer.TargetComponent; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.ElementCasePane; +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.design.sort.common.SortColumnRowPane; +import com.fr.log.FineLoggerFactory; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.cell.cellattr.CellExpandAttr; +import com.fr.report.cell.cellattr.core.group.DSColumn; +import com.fr.report.core.sort.common.CellSortable; +import com.fr.report.core.sort.header.SortHeader; +import com.fr.report.elementcase.TemplateElementCase; +import com.fr.stable.ColumnRow; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + + +public class HeaderAreaPane extends JPanel { + protected int headerAreaPaneWidth; + protected int headerAreaPaneRightWidth; + private CellSelectionManager cellSelectionManager = new CellSelectionManager(); + + + AreaJLayeredPane areaJLayeredPane; + + HeaderAreaPane(int headerAreaPaneWidth, int headerAreaPaneRightWidth) { + this.headerAreaPaneWidth = headerAreaPaneWidth; + this.headerAreaPaneRightWidth = headerAreaPaneRightWidth; + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + initComponents(); + } + + void initComponents() { + initUILabel(); + initLayeredPane(); + } + + void initUILabel() { + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Sort_Header_Area"), SwingConstants.LEFT); + this.add(uiLabel); + this.add(AbstractSortPane.createIntervalUILabel()); + } + + void initLayeredPane() { + areaJLayeredPane = new AreaJLayeredPane(); + this.add(areaJLayeredPane); + } + + public void populateBean(ColumnRow columnRow, boolean showHeaderArea) { + boolean enabled = true; + ElementCasePane elementCasePane = getCurrentElementCase(); + if (elementCasePane != null) { + enabled = elementCasePane.isSelectedOneCell(); + } + areaJLayeredPane.populateBean(columnRow, showHeaderArea, enabled); + } + + public ColumnRow updateBean(TemplateCellElement cellElement) { + ElementCasePane elementCasePane = getCurrentElementCase(); + if (elementCasePane != null) { + if (!elementCasePane.isSelectedOneCell()) { + return getOldColumnRow(cellElement); + } + } + return areaJLayeredPane.updateBean(); + } + + private ColumnRow getOldColumnRow(TemplateCellElement cellElement) { + try { + SortHeader sortHeader + = cellElement.getCellExpandAttr().getCellSortAttr().getSortHeader(); + String headerArea = sortHeader.getHeaderArea(); + if (headerArea == null) { + return null; + } else { + return ColumnRow.valueOf(headerArea); + } + } catch (Exception ignore) { + return null; + } + } + + private ElementCasePane getCurrentElementCase() { + try { + TargetComponent targetComponent + = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getCurrentElementCasePane(); + if (targetComponent instanceof ElementCasePane) { + return (ElementCasePane) targetComponent; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return null; + } + + class AreaJLayeredPane extends JPanel { + SortColumnRowPane columnRowPane; + JLayeredPane jLayeredPane; + UIComboBox uiComboBox; + boolean populateBeaning; + + AreaJLayeredPane() { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + initComponents(); + } + + private void initComponents() { + initUIComboBox(); + initJLayeredPane(); + } + + + void initUIComboBox() { + uiComboBox = new UIComboBox(new String[]{Toolkit.i18nText("Fine-Design_Basic_None"), Toolkit.i18nText("Fine-Design_Basic_Custom")}); + uiComboBox.setSize(new Dimension(headerAreaPaneRightWidth, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + uiComboBox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() != uiComboBox.getSelectedIndex()) { + setSortColumnRowPaneShow(uiComboBox.getSelectedIndex() == 1); + } + + } + + + }); + uiComboBox.setEnabled(false); + } + + void setSortColumnRowPaneShow(boolean show) { + if (show) { + jLayeredPane.setLayer(columnRowPane, JLayeredPane.POPUP_LAYER); + jLayeredPane.setLayer(uiComboBox, JLayeredPane.MODAL_LAYER); + if (!populateBeaning) { + ColumnRow columnRow = columnRowPane.updateBean(); + if (cellSelectionManager.isNotSelectables(columnRow)) { + columnRowPane.setColumnRow(ColumnRow.ERROR); + } else { + cellSelectionManager.addNotSelectables(columnRow); + } + } + } else { + jLayeredPane.setLayer(uiComboBox, JLayeredPane.POPUP_LAYER); + jLayeredPane.setLayer(columnRowPane, JLayeredPane.MODAL_LAYER); + if (!populateBeaning) { + cellSelectionManager.removeNotSelectables(columnRowPane.updateBean()); + } + } + refresh(); + } + + void initJLayeredPane() { + jLayeredPane = new JLayeredPane(); + columnRowPane = new SortColumnRowPane(headerAreaPaneRightWidth - 18, AbstractSortPane.PANE_COMPONENT_HEIGHT); + jLayeredPane.setPreferredSize(new Dimension(headerAreaPaneRightWidth, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + jLayeredPane.add(columnRowPane, JLayeredPane.MODAL_LAYER); + jLayeredPane.add(uiComboBox, JLayeredPane.POPUP_LAYER); + this.add(jLayeredPane); + } + + public void populateBean(ColumnRow columnRow, boolean showHeaderArea, boolean enabled) { + populateBeaning = true; + cellSelectionManager.build(); + columnRowPane.populateBean(columnRow, enabled, cellSelectionManager); + if (showHeaderArea) { + uiComboBox.setSelectedIndex(1); + } else { + uiComboBox.setSelectedIndex(0); + } + uiComboBox.setEnabled(enabled); + populateBeaning = false; + } + + public ColumnRow updateBean() { + if (uiComboBox.getSelectedIndex() == 0) { + return null; + } else { + return columnRowPane.updateBean(); + } + } + + public void refresh() { + validate(); + repaint(); + revalidate(); + } + + } + + public static class CellSelectionManager { + ElementCasePane elementCase; + java.util.List notSelectables = new ArrayList<>(); + + void build() { + ElementCasePane elementCase = SortColumnRowPane.getCurrentElementCase(); + if (elementCase != null && this.elementCase != elementCase) { + this.elementCase = elementCase; + notSelectables = new ArrayList<>(); + buildNotSelectables(elementCase.getEditingElementCase()); + } + } + + public java.util.List getNotSelectables() { + return this.notSelectables; + } + + + public boolean isNotSelectables(ColumnRow columnRow) { + return notSelectables != null && notSelectables.contains(columnRow); + } + + public void addNotSelectables(ColumnRow columnRow) { + if (columnRow != null) { + removeNotSelectables(columnRow); + notSelectables.add(columnRow); + } + } + + public void removeNotSelectables(ColumnRow columnRow) { + notSelectables.remove(columnRow); + } + + private void buildNotSelectables(TemplateElementCase elementCase) { + Iterator iterator = elementCase.cellIterator(); + while (iterator.hasNext()) { + TemplateCellElement templateCellElement = (TemplateCellElement) iterator.next(); + CellExpandAttr cellExpandAttr = templateCellElement.getCellExpandAttr(); + if (cellExpandAttr != null) { + handleDisableHeaderCell(cellExpandAttr); + } + Object value = templateCellElement.getValue(); + if (value instanceof DSColumn) { + handleDisableHeaderCell((DSColumn) value); + } + } + } + + private void handleDisableHeaderCell(CellSortable cellSortable) { + if (cellSortable.getCellSortAttr() != null) { + SortHeader sortHeader = cellSortable.getCellSortAttr().getSortHeader(); + if (sortHeader != null) { + String headerArea = sortHeader.getHeaderArea(); + if (headerArea != null) { + ColumnRow headerColumnRow = ColumnRow.valueOf(headerArea); + addNotSelectables(headerColumnRow); + } + } + } + } + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/sort/header/HeaderSettingPane.java b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderSettingPane.java new file mode 100644 index 000000000..f31c40929 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderSettingPane.java @@ -0,0 +1,81 @@ +package com.fr.design.sort.header; + +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.sort.common.AbstractSortPane; +import com.fr.report.core.sort.header.SortHeader; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class HeaderSettingPane extends JPanel { + protected int headerSettingPaneWidth; + protected int headerSettingPaneRightWidth; + HeaderSortRulePane headerSortRulePane; + UICheckBox uiCheckBox; + + HeaderSettingPane(int headerSettingPaneWidth, int headerSettingPaneRightWidth) { + this.headerSettingPaneWidth = headerSettingPaneWidth; + this.headerSettingPaneRightWidth = headerSettingPaneRightWidth; + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + initComponents(); + } + + void initComponents() { + initUILabel(); + initHeaderSortRulePane(); + } + + void initUILabel() { + JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 2)); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Sort_Header_Setting")); + UILabel emptyUILabel = new UILabel(); + emptyUILabel.setPreferredSize(new Dimension(10, 10)); + + uiCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Sort_Allow_User_Click_Sort_Order")); + uiCheckBox.setPreferredSize(new Dimension(headerSettingPaneRightWidth - 10, AbstractSortPane.PANE_COMPONENT_HEIGHT)); + uiCheckBox.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + headerSortRulePane.setVisible(uiCheckBox.isSelected()); + } + }); + jPanel.add(uiLabel); + jPanel.add(emptyUILabel); + jPanel.add(uiCheckBox); + this.add(jPanel); + } + + void initHeaderSortRulePane() { + headerSortRulePane = new HeaderSortRulePane(); + this.add(headerSortRulePane); + headerSortRulePane.setVisible(false); + } + + protected void refresh() { + validate(); + repaint(); + revalidate(); + } + + public void populateBean(SortHeader.SortItem[] sortItems) { + if (sortItems == null) { + uiCheckBox.setSelected(false); + } else { + uiCheckBox.setSelected(true); + } + headerSortRulePane.populateBean(sortItems); + } + + public SortHeader.SortItem[] updateBean() { + if (uiCheckBox.isSelected()) { + return headerSortRulePane.updateBean(); + } else { + return null; + } + } + +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/header/HeaderSortRulePane.java b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderSortRulePane.java new file mode 100644 index 000000000..79f939639 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderSortRulePane.java @@ -0,0 +1,279 @@ +package com.fr.design.sort.header; + +import com.fr.base.svg.SVGIcon; +import com.fr.base.svg.SVGTranscoder; +import com.fr.design.event.UIObserver; +import com.fr.design.event.UIObserverListener; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.theme.edit.ui.ColorListPane; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.report.core.sort.header.SortHeader; +import com.fr.report.core.sort.common.SortRule; +import org.apache.batik.transcoder.TranscoderInput; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class HeaderSortRulePane extends JPanel { + private static final String ASC_ICON_TEMPLATE_PATH = "/com/fr/design/images/sort/asc.svg"; + private static final String DES_ICON_TEMPLATE_PATH = "/com/fr/design/images/sort/des.svg"; + private static final String NOSORT_ICON_TEMPLATE_PATH = "/com/fr/design/images/sort/nosort.svg"; + private static final double ICON_SCALE = SVGIcon.SYSTEM_SCALE * 1.25; + private static final int ICON_LENGTH = (int) Math.ceil(16 * ICON_SCALE); + IconButton ascIconButton; + IconButton desIconButton; + IconButton nosortIconButton; + UICheckBox ascUICheckBox; + UICheckBox desUICheckBox; + UICheckBox nosortUICheckBox; + static Map originalSvgTextMap = new HashMap<>(); + + HeaderSortRulePane() { + initComponents(); + initState(true); + this.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15)); + } + + void initComponents() { + this.setLayout(new BorderLayout()); + initUILabel(); + initSortRuleItem(); + this.setPreferredSize(new Dimension(160, 160)); + } + + void initUILabel() { + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Sort_Header_Sort_Basis"), SwingConstants.LEFT); + this.add(uiLabel, BorderLayout.NORTH); + } + + void initSortRuleItem() { + Component[][] components = new Component[][]{ + new Component[]{ascUICheckBox = new UICheckBox(SortRule.ASC.getDescription()), ascIconButton = new IconButton(ASC_ICON_TEMPLATE_PATH)}, + new Component[]{desUICheckBox = new UICheckBox(SortRule.DES.getDescription()), desIconButton = new IconButton(DES_ICON_TEMPLATE_PATH)}, + new Component[]{nosortUICheckBox = new UICheckBox(SortRule.NO_SORT.getDescription()), nosortIconButton = new IconButton(NOSORT_ICON_TEMPLATE_PATH)}, + }; + double[] rowSize = {ICON_LENGTH + 10, ICON_LENGTH + 10, ICON_LENGTH + 10}; + double[] columnSize = {80, ICON_LENGTH + 10}; + JPanel sortRuleItem = TableLayoutHelper.createCommonTableLayoutPane(components, rowSize, columnSize, 0); + this.add(sortRuleItem, BorderLayout.CENTER); + initUICheckBoxChange(ascUICheckBox, ascIconButton); + initUICheckBoxChange(desUICheckBox, desIconButton); + initUICheckBoxChange(nosortUICheckBox, nosortIconButton); + } + + void initUICheckBoxChange(UICheckBox uiCheckBox, IconButton iconButton) { + uiCheckBox.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + iconButton.setActiveState(uiCheckBox.isSelected()); + } + }); + } + + void initState(boolean selected) { + ascUICheckBox.setSelected(selected); + desUICheckBox.setSelected(selected); + nosortUICheckBox.setSelected(selected); + ascIconButton.refreshIconLabelColor(new Color(33, 33, 34)); + desIconButton.refreshIconLabelColor(new Color(33, 33, 34)); + nosortIconButton.refreshIconLabelColor(new Color(33, 33, 34)); + } + + class IconButton extends JPanel implements UIObserver { + JLayeredPane jLayeredPane; + String iconTemplatePath; + UILabel iconLabel; + ColorListPane.ColorButton colorButton; + Color color; + BufferedImage bufferedImage; + UIObserverListener uiObserverListener; + boolean activeState; + UILabel borderUiLabel; + + IconButton(String iconTemplatePath) { + this.iconTemplatePath = iconTemplatePath; + initComponents(); + } + + public boolean isActiveState() { + return activeState; + } + + public void setActiveState(boolean activeState) { + if (activeState) { + borderUiLabel.setBorder(BorderFactory.createLineBorder(Color.gray, 1)); + colorButton.setVisible(true); + } else { + borderUiLabel.setBorder(null); + colorButton.setVisible(false); + } + this.activeState = activeState; + } + + void initComponents() { + jLayeredPane = new JLayeredPane(); + iconLabel = getIconLabel(iconTemplatePath); + borderUiLabel = new UILabel(); + borderUiLabel.setSize(ICON_LENGTH, ICON_LENGTH); + borderUiLabel.setOpaque(true); + borderUiLabel.setBackground(Color.WHITE); + iconLabel.setSize(ICON_LENGTH, ICON_LENGTH); + colorButton = new ColorListPane.ColorButton(Color.CYAN); + colorButton.setSize(ICON_LENGTH, ICON_LENGTH); + colorButton.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + color = colorButton.getSelectObject(); + refreshIconLabelColor(color); + uiObserverListener.doChange(); + } + }); + jLayeredPane.setPreferredSize(new Dimension(ICON_LENGTH, ICON_LENGTH)); + + jLayeredPane.add(iconLabel, JLayeredPane.POPUP_LAYER); + jLayeredPane.add(borderUiLabel, JLayeredPane.MODAL_LAYER); + jLayeredPane.add(colorButton, JLayeredPane.PALETTE_LAYER); + this.add(jLayeredPane); + } + + void refreshIconLabelColor(Color color) { + Icon icon = getIcon(iconTemplatePath, color); + refreshIconLabel(icon); + } + + void refreshIconLabel(BufferedImage bufferedImage) { + if (bufferedImage != null) { + this.bufferedImage = bufferedImage; + Icon icon = new SVGIcon(bufferedImage); + refreshIconLabel(icon); + } + } + + void refreshIconLabel(Icon icon) { + if (icon != null) { + iconLabel.removeAll(); + iconLabel.setIcon(icon); + iconLabel.repaint(); + } + } + + UILabel getIconLabel(String iconPath) { + return getIconLabel(iconPath, new Color(33, 33, 34)); + } + + UILabel getIconLabel(String iconPath, Color color) { + Icon svgIcon = getIcon(iconPath, color); + return new UILabel(svgIcon); + } + + Icon getIcon(String iconPath, Color color) { + try { + String originalSvgText = getOriginalSvgText(iconPath); + String svgText = originalSvgText.replaceAll("\\{fillColor\\}", shiftColor(color)); + InputStream svgInputStream = new ByteArrayInputStream(svgText.getBytes(StandardCharsets.UTF_8)); + TranscoderInput input = new TranscoderInput(svgInputStream); + bufferedImage = SVGTranscoder.createImage(ICON_SCALE, input).getImage(); + SVGIcon svgIcon = new SVGIcon(bufferedImage); + return svgIcon; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return null; + } + + String getOriginalSvgText(String iconPath) throws Exception { + String originalSvgText = originalSvgTextMap.get(iconPath); + if (originalSvgText == null) { + InputStream inputStream = IOUtils.getResourceAsStream(iconPath, HeaderSortRulePane.class); + originalSvgText = getSvgText(inputStream); + originalSvgTextMap.put(iconPath, originalSvgText); + } + return originalSvgText; + } + + String shiftColor(Color color) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(shiftValue(color.getRed())); + stringBuilder.append(shiftValue(color.getGreen())); + stringBuilder.append(shiftValue(color.getBlue())); + return stringBuilder.toString(); + } + + String shiftValue(int value) { + String resultValue = Integer.toHexString(value); + if (resultValue.length() == 1) { + resultValue = "0" + resultValue; + } + return resultValue; + } + + private String getSvgText(InputStream inputStream) throws Exception { + StringBuffer stringBuffer = new StringBuffer(); + byte[] b = new byte[1024]; + for (int n; (n = inputStream.read(b)) != -1; ) { + stringBuffer.append(new String(b, 0, n)); + } + return stringBuffer.toString(); + } + + @Override + public void registerChangeListener(UIObserverListener uiObserverListener) { + this.uiObserverListener = uiObserverListener; + } + + @Override + public boolean shouldResponseChangeListener() { + return true; + } + } + + public void populateBean(SortHeader.SortItem[] sortItems) { + initState(sortItems == null); + if (sortItems != null) { + for (SortHeader.SortItem sortItem : sortItems) { + SortRule sortRule = sortItem.getSortRule(); + BufferedImage bufferedImage = sortItem.getBufferedImage(); + if (sortRule == SortRule.ASC) { + ascIconButton.refreshIconLabel(bufferedImage); + ascUICheckBox.setSelected(true); + } else if (sortRule == SortRule.DES) { + desIconButton.refreshIconLabel(bufferedImage); + desUICheckBox.setSelected(true); + } else if (sortRule == SortRule.NO_SORT) { + nosortIconButton.refreshIconLabel(bufferedImage); + nosortUICheckBox.setSelected(true); + } + + } + } + } + + public SortHeader.SortItem[] updateBean() { + java.util.List items = new ArrayList<>(); + if (ascUICheckBox.isSelected()) { + items.add(new SortHeader.SortItem(SortRule.ASC, ascIconButton.bufferedImage)); + } + if (desUICheckBox.isSelected()) { + items.add(new SortHeader.SortItem(SortRule.DES, desIconButton.bufferedImage)); + } + if (nosortUICheckBox.isSelected()) { + items.add(new SortHeader.SortItem(SortRule.NO_SORT, nosortIconButton.bufferedImage)); + } + SortHeader.SortItem[] resultItems = new SortHeader.SortItem[items.size()]; + return items.toArray(resultItems); + } + +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/header/SortHeaderPane.java b/designer-realize/src/main/java/com/fr/design/sort/header/SortHeaderPane.java new file mode 100644 index 000000000..a68d0eebe --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/header/SortHeaderPane.java @@ -0,0 +1,65 @@ +package com.fr.design.sort.header; + +import com.fr.design.sort.common.SortColumnRowPane; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.core.sort.header.SortHeader; +import com.fr.stable.ColumnRow; + +import javax.swing.*; + +public class SortHeaderPane extends JPanel { + int sortHeaderPaneWidth; + int sortHeaderPaneRightWidth; + SortHeader sortHeader; + HeaderAreaPane headerAreaPane; + HeaderSettingPane headerSettingPane; + TemplateCellElement cellElement; + + public SortHeaderPane(int sortHeaderPaneWidth, int sortHeaderPaneRightWidth) { + this.sortHeaderPaneWidth = sortHeaderPaneWidth; + this.sortHeaderPaneRightWidth = sortHeaderPaneRightWidth; + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + initHeaderArea(); + initHeaderSetting(); + this.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + } + + void initHeaderArea() { + this.headerAreaPane = new HeaderAreaPane(sortHeaderPaneWidth, sortHeaderPaneRightWidth); + this.add(headerAreaPane); + } + + void initHeaderSetting() { + this.headerSettingPane = new HeaderSettingPane(sortHeaderPaneWidth, sortHeaderPaneRightWidth); + this.add(headerSettingPane); + } + + public void populateBean(SortHeader sortHeader, String defaultHeaderArea) { + this.sortHeader = sortHeader; + boolean showHeaderArea = false; + SortHeader.SortItem[] sortItems = null; + String headerArea = defaultHeaderArea; + ColumnRow columnRow = ColumnRow.valueOf(headerArea); + if (sortHeader != null) { + headerArea = sortHeader.getHeaderArea(); + sortItems = sortHeader.getSortItems(); + if (headerArea != null) { + showHeaderArea = true; + columnRow = ColumnRow.valueOf(headerArea); + } + } + headerAreaPane.populateBean(columnRow, showHeaderArea); + headerSettingPane.populateBean(sortItems); + } + + public SortHeader updateBean(TemplateCellElement cellElement) { + ColumnRow columnRow = headerAreaPane.updateBean( cellElement); + SortHeader.SortItem[] items = headerSettingPane.updateBean(); + String headerArea = null; + if (columnRow != null) { + headerArea = columnRow.toString(); + } + SortHeader sortHeader = new SortHeader(headerArea, null, items); + return sortHeader; + } +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java b/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java index 0ede5114f..2a4852ee8 100644 --- a/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java +++ b/designer-realize/src/main/java/com/fr/quickeditor/cellquick/CellDSColumnEditor.java @@ -11,6 +11,7 @@ import com.fr.design.dscolumn.DSColumnAdvancedPane; import com.fr.design.dscolumn.ResultSetGroupDockingPane; import com.fr.design.dscolumn.SelectedDataColumnPane; import com.fr.design.event.UIObserverListener; +import com.fr.design.foldablepane.UIExpandablePane; import com.fr.design.formula.CustomVariableResolver; import com.fr.design.formula.FormulaFactory; import com.fr.design.formula.UIFormula; @@ -31,6 +32,7 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.cell.AbstractDSCellEditorPane; +import com.fr.design.sort.celldscolumn.CellDSColumnSortPane; import com.fr.design.utils.gui.UIComponentUtils; import com.fr.design.widget.FRWidgetFactory; import com.fr.general.IOUtils; @@ -221,62 +223,6 @@ public class CellDSColumnEditor extends CellQuickEditor { */ private UIButton conditionUIButton; - /** - * 分组设置监听器 - */ - private ItemListener groupListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e == null) { - //分组-高级-自定义点确定的时候传进来null的e,但是这时候应该触发保存 - groupPane.update(); - fireTargetModified(); - return; - } - if (e.getStateChange() == ItemEvent.DESELECTED) { - groupPane.update(); - fireTargetModified(); - } - } - }; - /** - * 数据集列设置监听器 - */ - private ItemListener dataListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - dataPane.update(cellElement); - fireTargetModified(); - } - } - }; - - DSColumnBasicEditorPane() { - dataPane = new SelectedDataColumnPane(true, true); - groupPane = new ResultSetGroupDockingPane(); - dataPane.setListener(dataListener); - groupPane.setListener(groupListener); - - double[] rowSize = {P}, columnSize = {60, F}; - UILabel uiLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Report_Filter_Conditions")); - condition = new DSColumnConditionAction(); - if (tc != null) { - condition.setEditingComponent(tc); - } - //丢掉icon,修改按钮名称为编辑 - condition.setSmallIcon(UIConstants.EMPTY_ICON); - condition.setName(Toolkit.i18nText("Fine-Design_Basic_Edit")); - conditionUIButton = new UIButton(condition); - Component[][] components = new Component[][]{ - new Component[]{uiLabel, UIComponentUtils.wrapWithBorderLayoutPane(conditionUIButton)} - }; - conditionPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, HGAP, VGAP); - this.createScrollPane(); - this.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - - } - @Override public String getIconPath() { @@ -297,11 +243,13 @@ public class CellDSColumnEditor extends CellQuickEditor { @Override public void populate() { + this.removeAttributeChangeListener(); dataPane.populate(DesignTableDataManager.getEditingTableDataSource(), cellElement, tc); groupPane.populate(cellElement); if (tc != null) { condition.setEditingComponent(tc); } + this.addAttributeChangeListener(); } @Override @@ -318,7 +266,7 @@ public class CellDSColumnEditor extends CellQuickEditor { */ @Override protected JPanel createContentPane() { - + initComponents(); double[] columnSize = {F}; double[] rowSize = {P, P, P}; Component[][] components = new Component[][]{ @@ -331,16 +279,43 @@ public class CellDSColumnEditor extends CellQuickEditor { }; return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, HGAP, VGAP); } + + private void initComponents(){ + dataPane = new SelectedDataColumnPane(true, true); + groupPane = new ResultSetGroupDockingPane(); + + double[] rowSize = {P}, columnSize = {60, F}; + UILabel uiLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Report_Filter_Conditions")); + condition = new DSColumnConditionAction(); + if (tc != null) { + condition.setEditingComponent(tc); + } + //丢掉icon,修改按钮名称为编辑 + condition.setSmallIcon(UIConstants.EMPTY_ICON); + condition.setName(Toolkit.i18nText("Fine-Design_Basic_Edit")); + conditionUIButton = new UIButton(condition); + Component[][] components = new Component[][]{ + new Component[]{uiLabel, UIComponentUtils.wrapWithBorderLayoutPane(conditionUIButton)} + }; + conditionPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, HGAP, VGAP); + this.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + } + @Override + protected AttributeChangeListener getAttributeChangeListener() { + return new AttributeChangeListener() { + @Override + public void attributeChange() { + update(); + fireTargetModified(); + } + }; + } } class DSColumnAdvancedEditorPane extends AbstractDSCellEditorPane { /*pane begin*/ - /** - * 排列顺序 - */ - private ResultSetSortConfigPane sortPane; /** * 结果集筛选 */ @@ -373,88 +348,13 @@ public class CellDSColumnEditor extends CellQuickEditor { * 补充空白数据数目面板 可隐藏 */ private JPanel multiPane; - /*pane end*/ - - /*listeners begin*/ - private UIObserverListener sortPaneFormulaChangeListener = new UIObserverListener() { - @Override - public void doChange() { - sortPane.update(cellElement); - fireTargetModified(); - } - }; - - private ChangeListener sortTypeBtnGroupChangeListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - sortPane.update(cellElement); - fireTargetModified(); - } - }; - - private UIObserverListener filterPaneChangeListener = new UIObserverListener() { - @Override - public void doChange() { - filterPane.update(cellElement); - fireTargetModified(); - } - }; - - private UIObserverListener customValuePaneChangeListener = new UIObserverListener() { - @Override - public void doChange() { - valuePane.update(cellElement); - fireTargetModified(); - } - }; - - private AttributeChangeListener formatChangeListener = new AttributeChangeListener() { - @Override - public void attributeChange() { - formatAttrPane.update(cellElement); - fireTargetModified(); - } - }; - - private ChangeListener heCheckBoxChangeListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - cellDSColumnAdvancedPane.updateExtendConfig(); - fireTargetModified(); - } - }; - - private ChangeListener veCheckBoxChangeListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - cellDSColumnAdvancedPane.updateExtendConfig(); - fireTargetModified(); - } - }; - - private ActionListener useMultiNumCheckBoxChangeListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - checkButtonEnabled(); - cellDSColumnAdvancedPane.updateMultipleConfig(); - fireTargetModified(); - } - }; - - private ChangeListener multiNumSpinnerChangeListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - cellDSColumnAdvancedPane.updateMultipleConfig(); - fireTargetModified(); - } - }; - /*listeners end*/ + private CellDSColumnSortPane cellDSColumnSortPane; + /*pane end*/ public DSColumnAdvancedEditorPane() { this.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - this.createScrollPane(); } @@ -469,10 +369,10 @@ public class CellDSColumnEditor extends CellQuickEditor { } + @Override public void update() { if (cellElement != null) { - sortPane.update(cellElement); valuePane.update(cellElement); formatAttrPane.update(cellElement); filterPane.update(cellElement); @@ -480,14 +380,14 @@ public class CellDSColumnEditor extends CellQuickEditor { updateExtendConfig(); //更新补充空白设置 updateMultipleConfig(); + cellDSColumnSortPane.updateBean(cellElement); } } @Override public void populate() { if (cellElement != null) { - disableListener(); - sortPane.populate(cellElement); + this.removeAttributeChangeListener(); valuePane.populate(cellElement); formatAttrPane.populate(cellElement); filterPane.populate(cellElement); @@ -524,8 +424,11 @@ public class CellDSColumnEditor extends CellQuickEditor { useMultiNumCheckBox.setSelected(true); multiNumSpinner.setValue(cellExpandAttr.getMultipleNumber()); } + if (cellDSColumnSortPane != null) { + cellDSColumnSortPane.populateBean(cellElement); + } this.checkButtonEnabled(); - enableListener(); + this.addAttributeChangeListener(); } } @@ -534,6 +437,17 @@ public class CellDSColumnEditor extends CellQuickEditor { } + @Override + protected AttributeChangeListener getAttributeChangeListener() { + return new AttributeChangeListener() { + @Override + public void attributeChange() { + update(); + fireTargetModified(); + } + }; + } + /** * 更新单元格扩展属性 */ @@ -578,11 +492,8 @@ public class CellDSColumnEditor extends CellQuickEditor { */ @Override protected JPanel createContentPane() { + JPanel contentPane = new JPanel(new BorderLayout()); this.setLayout(FRGUIPaneFactory.createBorderLayout()); - - //结果集排序 - sortPane = new ResultSetSortConfigPane(); - //结果筛选 filterPane = new ResultSetFilterConfigPane(); @@ -616,10 +527,7 @@ public class CellDSColumnEditor extends CellQuickEditor { multiPane.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); multiNumPane.add(multiPane); - enableListener(); - Component[][] components = new Component[][]{ - {sortPane}, {filterPane}, {valuePane}, {formatAttrPane}, @@ -630,32 +538,15 @@ public class CellDSColumnEditor extends CellQuickEditor { double[] rowSize = new double[components.length]; Arrays.fill(rowSize, P); double[] columnSize = {F}; - - return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, HGAP, VGAP); - } - - public void enableListener() { - sortPane.addListener(sortPaneFormulaChangeListener, sortTypeBtnGroupChangeListener); - filterPane.addListener(filterPaneChangeListener); - valuePane.addListener(customValuePaneChangeListener); - formatAttrPane.addAttributeChangeListener(formatChangeListener); - heCheckBox.addChangeListener(heCheckBoxChangeListener); - veCheckBox.addChangeListener(veCheckBoxChangeListener); - useMultiNumCheckBox.addActionListener(useMultiNumCheckBoxChangeListener); - multiNumSpinner.addChangeListener(multiNumSpinnerChangeListener); - } - - public void disableListener() { - sortPane.removeListener(sortTypeBtnGroupChangeListener); - filterPane.removeListener(); - valuePane.removeListener(); - heCheckBox.removeChangeListener(heCheckBoxChangeListener); - veCheckBox.removeChangeListener(veCheckBoxChangeListener); - useMultiNumCheckBox.removeActionListener(useMultiNumCheckBoxChangeListener); - multiNumSpinner.removeChangeListener(multiNumSpinnerChangeListener); + JPanel advancePropertyPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, HGAP, VGAP); + contentPane.add(advancePropertyPane, BorderLayout.NORTH); + UIExpandablePane sortUIExpandablePane = + new UIExpandablePane(Toolkit.i18nText("Fine-Design_Sort_Data_Column_Sort"), + 223, 24, cellDSColumnSortPane = new CellDSColumnSortPane()); + contentPane.add(sortUIExpandablePane, BorderLayout.CENTER); + return contentPane; } - private void checkButtonEnabled() { if (useMultiNumCheckBox.isSelected()) { multiNumSpinner.setEnabled(true); @@ -666,136 +557,6 @@ public class CellDSColumnEditor extends CellQuickEditor { } } - /** - * 单元格元素>数据集>高级设置>结果排序设置面板 - * - * @see com.fr.design.expand.SortExpandAttrPane - * @see DSColumnAdvancedPane.SortPane - */ - public class ResultSetSortConfigPane extends JPanel { - private static final String DEFAULT_VALUE = "="; - private JPanel contentPane; - private UIButtonGroup sortTypePane; - private JFormulaField formulaField; - private CardLayout cardLayout; - private JPanel centerPane; - - - public ResultSetSortConfigPane() { - this.setLayout(new BorderLayout()); - Icon[] iconArray = { - IOUtils.readIcon("/com/fr/design/images/expand/none16x16.png"), - IOUtils.readIcon("/com/fr/design/images/expand/asc.png"), - IOUtils.readIcon("/com/fr/design/images/expand/des.png") - }; - String[] nameArray = {Toolkit.i18nText("Fine-Design_Report_Sort_Original"), Toolkit.i18nText("Fine-Design_Report_Sort_Ascending"), Toolkit.i18nText("Fine-Design_Report_Sort_Descending")}; - sortTypePane = new UIButtonGroup(iconArray); - sortTypePane.setAllToolTips(nameArray); - sortTypePane.setGlobalName(Toolkit.i18nText("Fine-Design_Basic_ExpandD_Sort_After_Expand")); - - cardLayout = new CardLayout(); - centerPane = new JPanel(cardLayout); - formulaField = new JFormulaField(DEFAULT_VALUE); - centerPane.add(new JPanel(), "none"); - centerPane.add(formulaField, "content"); - UILabel sortLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Sort_Sort_Order")); - sortLabel.setPreferredSize(LABEL_DIMENSION); - sortTypePane.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - boolean noContent = sortTypePane.getSelectedIndex() == 0; - cardLayout.show(centerPane, noContent ? "none" : "content"); - if (noContent) { - centerPane.setPreferredSize(new Dimension(0, 0)); - TableLayoutHelper.modifyTableLayoutIndexVGap(contentPane, 2, 0); - } else { - centerPane.setPreferredSize(new Dimension(165, 20)); - TableLayoutHelper.modifyTableLayoutIndexVGap(contentPane, 2, VGAP); - } - } - }); - - Component[][] components = new Component[][]{ - new Component[]{sortLabel, sortTypePane}, - new Component[]{null, centerPane} - }; - - double[] rowSize = {P, P}, columnSize = {P, F}; - contentPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, HGAP, VGAP); - this.add(contentPane, BorderLayout.CENTER); - } - - - /** - * 刷新面板信息 - * - * @param cellElement 单元格 - */ - public void populate(TemplateCellElement cellElement) { - if (cellElement != null) { - Object value = cellElement.getValue(); - if (value instanceof DSColumn) { - this.formulaField.populateElement(cellElement); - DSColumn dSColumn = (DSColumn) value; - int sort = dSColumn.getOrder(); - this.sortTypePane.setSelectedIndex(sort); - boolean noContent = sortTypePane.getSelectedIndex() == 0; - cardLayout.show(centerPane, noContent ? "none" : "content"); - if (noContent) { - centerPane.setPreferredSize(new Dimension(0, 0)); - TableLayoutHelper.modifyTableLayoutIndexVGap(contentPane, 2, 0); - } else { - centerPane.setPreferredSize(new Dimension(156, 20)); - TableLayoutHelper.modifyTableLayoutIndexVGap(contentPane, 2, VGAP); - } - String sortFormula = dSColumn.getSortFormula(); - if (sortFormula != null && sortFormula.length() >= 1) { - this.formulaField.populate(sortFormula); - } else { - this.formulaField.populate(DEFAULT_VALUE); - } - } - } - } - - /** - * 保存面板配置信息 - * - * @param cellElement 单元格 - */ - public void update(CellElement cellElement) { - if (cellElement != null) { - Object value = cellElement.getValue(); - if (value instanceof DSColumn) { - DSColumn dSColumn = (DSColumn) value; - dSColumn.setOrder(this.sortTypePane.getSelectedIndex()); - dSColumn.setSortFormula(this.formulaField.getFormulaText()); - } - } - } - - /** - * 添加事件监听器 - * - * @param formulaChangeListener 公式输入框改动事件监听器 - * @param changeListener 排序类型下拉框改动事件监听器 - */ - public void addListener(UIObserverListener formulaChangeListener, ChangeListener changeListener) { - formulaField.addListener(formulaChangeListener); - sortTypePane.addChangeListener(changeListener); - } - - /** - * 去除事件监听器 - * - * @param changeListener 排序类型下拉框改动事件监听器 - */ - public void removeListener(ChangeListener changeListener) { - formulaField.removeListener(); - sortTypePane.removeChangeListener(changeListener); - } - } - /** * 单元格元素>数据集>高级设置>结果集筛选设置面板 *