diff --git a/designer-base/src/main/java/com/fr/base/svg/IconUtils.java b/designer-base/src/main/java/com/fr/base/svg/IconUtils.java index 79d3cef76b..fd99f0e994 100644 --- a/designer-base/src/main/java/com/fr/base/svg/IconUtils.java +++ b/designer-base/src/main/java/com/fr/base/svg/IconUtils.java @@ -6,8 +6,7 @@ import com.fr.stable.bridge.StableFactory; import com.fr.stable.fun.ResourcePathTransformer; import com.fr.stable.plugin.ExtraClassManagerProvider; -import javax.swing.Icon; -import javax.swing.ImageIcon; +import javax.swing.*; import java.util.Arrays; import java.util.HashSet; import java.util.Set; diff --git a/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java b/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java index 9667895eec..172b10dac5 100644 --- a/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java +++ b/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java @@ -2,10 +2,8 @@ package com.fr.base.svg; import com.fr.general.IOUtils; -import javax.swing.Icon; -import java.awt.Component; -import java.awt.Graphics; -import java.awt.Graphics2D; +import javax.swing.*; +import java.awt.*; import java.awt.image.BufferedImage; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/designer-base/src/main/java/com/fr/base/svg/SVGLoader.java b/designer-base/src/main/java/com/fr/base/svg/SVGLoader.java deleted file mode 100644 index 3c0b7a0363..0000000000 --- a/designer-base/src/main/java/com/fr/base/svg/SVGLoader.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.fr.base.svg; - -import com.fr.general.IOUtils; -import org.apache.batik.transcoder.TranscoderException; -import org.apache.batik.transcoder.TranscoderInput; -import org.apache.xmlgraphics.java2d.Dimension2DDouble; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.Image; -import java.io.IOException; -import java.net.URL; - -/** - * SVG图标加载器 - * @author Yvan - * @version 10.0 - * Created by Yvan on 2020/12/17 - */ -public class SVGLoader { - public static final int ICON_DEFAULT_SIZE = 16; - - public SVGLoader() { - } - - @Nullable - public static Image load(@NotNull String url) { - try { - URL resource = IOUtils.getResource(url, SVGLoader.class); - if (resource == null) { - return null; - } - return load(resource, SVGIcon.SYSTEM_SCALE); - } catch (IOException ignore) { - return null; - } - } - - @Nullable - public static Image load(@NotNull URL url) throws IOException { - return load(url, SVGIcon.SYSTEM_SCALE); - } - - @Nullable - public static Image load(@NotNull URL url, double scale) throws IOException { - try { - String svgUri = url.toString(); - TranscoderInput input = new TranscoderInput(svgUri); - return SVGTranscoder.createImage(scale, input).getImage(); - } catch (TranscoderException ignore) { - return null; - } - } - - @Nullable - public static Image load(@NotNull URL url, double scale, Dimension2DDouble dimension) throws IOException { - try { - String svgUri = url.toString(); - TranscoderInput input = new TranscoderInput(svgUri); - return SVGTranscoder.createImage(scale, input, - (float) (dimension.getWidth() * scale), (float) (dimension.getHeight() * scale)).getImage(); - } catch (TranscoderException ignore) { - return null; - } - } - - - @Nullable - public static Image load(@NotNull URL url, double scale, double overriddenWidth, double overriddenHeight) throws IOException { - try { - String svgUri = url.toString(); - TranscoderInput input = new TranscoderInput(svgUri); - return SVGTranscoder.createImage(scale, input, (float) (overriddenWidth * scale), (float) (overriddenHeight * scale)).getImage(); - } catch (TranscoderException ignore) { - return null; - } - } - - @Nullable - public static Image load(@NotNull String url, float width, float height) { - try { - URL resource = IOUtils.getResource(url, SVGLoader.class); - if (resource == null) { - return null; - } - TranscoderInput input = new TranscoderInput(resource.toString()); - return SVGTranscoder.createImage(SVGIcon.SYSTEM_SCALE, input, -1, -1, width, height).getImage(); - } catch (TranscoderException ignore) { - return null; - } - } -} diff --git a/designer-base/src/main/java/com/fr/base/svg/SVGTranscoder.java b/designer-base/src/main/java/com/fr/base/svg/SVGTranscoder.java deleted file mode 100644 index dd47bc5757..0000000000 --- a/designer-base/src/main/java/com/fr/base/svg/SVGTranscoder.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.fr.base.svg; - -import com.fr.stable.AssistUtils; -import com.fr.value.AtomicNotNullLazyValue; -import org.apache.batik.anim.dom.SAXSVGDocumentFactory; -import org.apache.batik.anim.dom.SVGOMDocument; -import org.apache.batik.bridge.BridgeContext; -import org.apache.batik.bridge.UserAgent; -import org.apache.batik.transcoder.SVGAbstractTranscoder; -import org.apache.batik.transcoder.TranscoderException; -import org.apache.batik.transcoder.TranscoderInput; -import org.apache.batik.transcoder.TranscoderOutput; -import org.apache.batik.transcoder.image.ImageTranscoder; -import org.apache.batik.util.XMLResourceDescriptor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.w3c.dom.Element; -import org.w3c.dom.svg.SVGDocument; - -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.StringReader; - -/** - * 可以根据某个缩放倍数scale,将SVG图片转化为Image对象 - * @author Yvan - * @version 10.0 - * Created by Yvan on 2020/12/17 - */ -public class SVGTranscoder extends ImageTranscoder { - - private static final float DEFAULT_VALUE = -1.0F; - public static final float ICON_DEFAULT_SIZE = 16F; - private float origDocWidth; - private float origDocHeight; - @Nullable - private BufferedImage image; - private final double scale; - - @NotNull - private static AtomicNotNullLazyValue iconMaxSize = new AtomicNotNullLazyValue() { - @NotNull - @Override - protected Double compute() { - double maxSize = Double.MAX_VALUE; - if (!GraphicsEnvironment.isHeadless()) { - GraphicsDevice defaultScreenDevice = GraphicsEnvironment - .getLocalGraphicsEnvironment() - .getDefaultScreenDevice(); - Rectangle bounds = defaultScreenDevice.getDefaultConfiguration().getBounds(); - AffineTransform tx = defaultScreenDevice - .getDefaultConfiguration() - .getDefaultTransform(); - maxSize = Math.max(bounds.width * tx.getScaleX(), bounds.height * tx.getScaleY()); - } - return maxSize; - } - }; - - public SVGTranscoder(double scale) { - this.scale = scale; - this.width = ICON_DEFAULT_SIZE; - this.height = ICON_DEFAULT_SIZE; - } - - public SVGTranscoder(double scale, float width, float height) { - this.scale = scale; - this.width = width; - this.height = height; - } - - public final float getOrigDocWidth() { - return this.origDocWidth; - } - - public final void setOrigDocWidth(float origDocWidth) { - this.origDocWidth = origDocWidth; - } - - public final float getOrigDocHeight() { - return this.origDocHeight; - } - - public final void setOrigDocHeight(float origDocHeight) { - this.origDocHeight = origDocHeight; - } - - public static double getIconMaxSize() { - return iconMaxSize.getValue(); - } - - @Nullable - public final BufferedImage getImage() { - return this.image; - } - - @NotNull - public static SVGTranscoder createImage(double scale, @NotNull TranscoderInput input) throws TranscoderException { - return createImage(scale, input, -1, -1); - } - - @NotNull - public static SVGTranscoder createImage(double scale, @NotNull TranscoderInput input, float overriddenWidth, float overriddenHeight) throws TranscoderException { - return createImage(scale, input, overriddenWidth, overriddenHeight, ICON_DEFAULT_SIZE, ICON_DEFAULT_SIZE); - } - - @NotNull - public static SVGTranscoder createImage(double scale, @NotNull TranscoderInput input, float overriddenWidth, float overriddenHeight, float width, float height) throws TranscoderException { - SVGTranscoder transcoder = new SVGTranscoder(scale, width, height); - if (!AssistUtils.equals(overriddenWidth, DEFAULT_VALUE)) { - transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, overriddenWidth); - } - - if (!AssistUtils.equals(overriddenHeight, DEFAULT_VALUE)) { - transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, overriddenHeight); - } - - double iconMaxSize = SVGTranscoder.iconMaxSize.getValue(); - transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_WIDTH, (float) iconMaxSize); - transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_HEIGHT, (float) iconMaxSize); - transcoder.transcode(input, null); - return transcoder; - } - - private static SVGDocument createFallbackPlaceholder() { - try { - String fallbackIcon = "\n" + - " \n" + - " \n" + - " \n" + - "\n"; - - SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName()); - return (SVGDocument) factory.createDocument(null, new StringReader(fallbackIcon)); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - @Override - protected void setImageSize(float docWidth, float docHeight) { - super.setImageSize((float) (docWidth * this.scale), (float) (docHeight * this.scale)); - this.origDocWidth = docWidth; - this.origDocHeight = docHeight; - } - - @Override - @NotNull - public BufferedImage createImage(int width, int height) { - return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - } - - @Override - public void writeImage(@NotNull BufferedImage image, @Nullable TranscoderOutput output) { - this.image = image; - } - - @Override - @NotNull - protected UserAgent createUserAgent() { - return new SVGAbstractTranscoderUserAgent() { - @Override - @NotNull - public SVGDocument getBrokenLinkDocument(@NotNull Element e, @NotNull String url, @NotNull String message) { - return createFallbackPlaceholder(); - } - }; - } - - /** - * 开放访问权限 - */ - @Override - public BridgeContext createBridgeContext(SVGOMDocument doc) { - return super.createBridgeContext(doc); - } -} diff --git a/designer-base/src/main/java/com/fr/base/svg/SystemScaleUtils.java b/designer-base/src/main/java/com/fr/base/svg/SystemScaleUtils.java deleted file mode 100644 index 4b79748065..0000000000 --- a/designer-base/src/main/java/com/fr/base/svg/SystemScaleUtils.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.fr.base.svg; - -import com.bulenkov.iconloader.util.UIUtil; -import com.fr.log.FineLoggerFactory; -import com.fr.stable.StableUtils; -import com.fr.stable.os.OperatingSystem; -import org.jetbrains.annotations.NotNull; - -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.lang.reflect.Method; -import java.util.concurrent.atomic.AtomicReference; - -/** - * 获取系统Scale相关的工具类 - * @author Yvan - * @version 10.0 - * Created by Yvan on 2020/12/17 - */ -public class SystemScaleUtils { - - private static final AtomicReference JRE_HIDPI = new AtomicReference<>(); - - private static final String HI_DPI = "hidpi"; - - /** - * 判断是否支持高清 - * @return - */ - public static boolean isJreHiDPIEnabled() { - if (JRE_HIDPI.get() != null) { - return JRE_HIDPI.get(); - } - if (OperatingSystem.isMacos()) { - // 如果是mac os系统,直接返回true - return true; - } - if (OperatingSystem.isWindows() && StableUtils.getMajorJavaVersion() <= 8) { - // 如果是jdk8 + Windows系统,直接返回false - return false; - } - synchronized (JRE_HIDPI) { - if (JRE_HIDPI.get() != null) { - return JRE_HIDPI.get(); - } - boolean result = false; - if (getBooleanProperty(HI_DPI, true)) { - try { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - Class sunGraphicsEnvironmentClass = Class.forName("sun.java2d.SunGraphicsEnvironment"); - if (sunGraphicsEnvironmentClass.isInstance(ge)) { - try { - Method method = sunGraphicsEnvironmentClass.getDeclaredMethod("isUIScaleEnabled"); - method.setAccessible(true); - result = (Boolean)method.invoke(ge); - } - catch (NoSuchMethodException e) { - FineLoggerFactory.getLogger().error(e.getMessage()); - } - } - } - catch (Throwable ignore) { - } - } - JRE_HIDPI.set(result); - return result; - } - } - - public static boolean getBooleanProperty(@NotNull final String key, final boolean defaultValue) { - final String value = System.getProperty(key); - return value == null ? defaultValue : Boolean.parseBoolean(value); - } - - /** - * 获取系统Scale - * @return - */ - public static float sysScale() { - // 如果检测到是retina,直接返回2 - if (UIUtil.isRetina()) { - return 2.0f; - } - float scale = 1.0f; - // 先判断是否支持高清,不支持代表此时是Windows + jdk8 的设计器,返回的scale值为1.0 - if (isJreHiDPIEnabled()) { - // 获取屏幕图形设备对象 - GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); - if (graphicsDevice != null) { - // 获取图形配置对象 - GraphicsConfiguration configuration = graphicsDevice.getDefaultConfiguration(); - if (configuration != null && configuration.getDevice().getType() != GraphicsDevice.TYPE_PRINTER) { - // 获取屏幕缩放率,Windows+jdk11环境下会得到用户设置的dpi值 - scale = (float) configuration.getDefaultTransform().getScaleX(); - } - } - } - return scale; - } -} 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 80f217a31a..5a777b895d 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 @@ -809,7 +809,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()); 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 b4b382af5b..eb3c2cd7b5 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 diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java index 07d7abfb72..87e322b266 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java @@ -17,9 +17,12 @@ import com.fr.event.EventDispatcher; import com.fr.file.ProcedureConfig; import com.fr.file.TableDataConfig; import com.fr.file.TableDataOperator; +import com.fr.file.TableDataOperatorImpl; import com.fr.general.ComparatorUtils; import com.fr.general.NameObject; import com.fr.log.FineLoggerFactory; +import com.fr.rpc.ExceptionHandler; +import com.fr.rpc.RPCInvokerExceptionInfo; import com.fr.stable.ArrayUtils; import com.fr.stable.Nameable; import com.fr.stable.StringUtils; @@ -246,7 +249,13 @@ public class TableDataPaneListPane extends JListControlPane implements TableData tableDataBeans.add(new TableDataBean(nameObject.getName(), oldName, (TableData) nameObject.getObject())); } try { - WorkContext.getCurrent().get(TableDataOperator.class).saveTableData(tableDataBeans); + WorkContext.getCurrent().get(TableDataOperator.class, new ExceptionHandler() { + @Override + public Object callHandler(RPCInvokerExceptionInfo exceptionInfo) { + // 走老的方式 + return saveByOldWay(tableDataBeans); + } + }).saveTableData(new ArrayList<>(tableDataConfig.getTableDatas().keySet()), tableDataBeans); if (!WorkContext.getCurrent().isLocal()) { EventDispatcher.fire(RemoteConfigEvent.EDIT, TableDataConfig.getInstance().getNameSpace()); } @@ -255,6 +264,15 @@ public class TableDataPaneListPane extends JListControlPane implements TableData } } + private boolean saveByOldWay(List tableDataBean) { + try { + return TableDataOperatorImpl.getInstance().saveTableData(tableDataBean); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + return false; + } + } + @Override public void update(TableDataSource tds) { tds.clearAllTableData(); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java index 0c1967ef96..1566395edb 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java @@ -16,8 +16,11 @@ import com.fr.design.i18n.Toolkit; import com.fr.event.EventDispatcher; import com.fr.file.ConnectionConfig; import com.fr.file.ConnectionOperator; +import com.fr.file.ConnectionOperatorImpl; import com.fr.general.NameObject; import com.fr.log.FineLoggerFactory; +import com.fr.rpc.ExceptionHandler; +import com.fr.rpc.RPCInvokerExceptionInfo; import com.fr.stable.ArrayUtils; import com.fr.stable.Nameable; import com.fr.stable.StringUtils; @@ -170,7 +173,12 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh connectionBeans.add(new ConnectionBean(nameObject.getName(), oldName, (Connection) nameObject.getObject())); } try { - WorkContext.getCurrent().get(ConnectionOperator.class).saveConnection(connectionBeans); + WorkContext.getCurrent().get(ConnectionOperator.class, new ExceptionHandler() { + @Override + public Object callHandler(RPCInvokerExceptionInfo exceptionInfo) { + return saveByOldWay(connectionBeans); + } + }).saveConnection(new ArrayList<>(connectionConfig.getConnections().keySet()), connectionBeans); if (!WorkContext.getCurrent().isLocal()) { EventDispatcher.fire(RemoteConfigEvent.EDIT, ConnectionConfig.getInstance().getNameSpace()); } @@ -179,6 +187,15 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh } } + private boolean saveByOldWay(List connectionBeans) { + try { + return ConnectionOperatorImpl.getInstance().saveConnection(connectionBeans); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + return false; + } + } + public static void showDialog(Window parent) { final ConnectionConfig connectionConfig = ConnectionConfig.getInstance(); final ConnectionManagerPane connectionManagerPane = new ConnectionManagerPane() { diff --git a/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java b/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java index 920ecb78c8..443a55671d 100644 --- a/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java +++ b/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java @@ -15,7 +15,6 @@ import com.fr.design.mainframe.JVirtualTemplate; import com.fr.design.ui.util.UIUtil; import com.fr.file.FILE; import com.fr.file.FileNodeFILE; -import com.fr.file.StashedFILE; import com.fr.general.ComparatorUtils; import com.fr.invoke.ClassHelper; import com.fr.log.FineLoggerFactory; @@ -25,7 +24,7 @@ import com.fr.stable.CoreConstants; import com.fr.stable.StringUtils; import com.fr.third.org.apache.commons.io.FilenameUtils; -import java.io.ByteArrayOutputStream; +import javax.swing.SwingWorker; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -33,7 +32,6 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; -import javax.swing.SwingWorker; /** * 历史模板缓存 @@ -364,7 +362,7 @@ public class HistoryTemplateListCache implements CallbackEvent { int size = historyList.size(); for (int i = 0; i < size; i++) { JTemplate template = historyList.get(i); - FILE file = templateToStashFile(template); + FILE file = template.templateToStashFile(); if (file != null) { stashFILEMap.put(i, file); } @@ -372,21 +370,6 @@ public class HistoryTemplateListCache implements CallbackEvent { FineLoggerFactory.getLogger().info("Env Change Template Stashed."); } - private FILE templateToStashFile(JTemplate template) { - FILE file = template.getEditingFILE(); - try { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - BaseBook target = template.getTarget(); - if (target != null) { - target.export(outputStream); - return new StashedFILE(file, outputStream.toByteArray(), template.suffix()); - } - // 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return null; - } private boolean checkStash() { try { @@ -469,7 +452,7 @@ public class HistoryTemplateListCache implements CallbackEvent { FILE file = template.getEditingFILE(); boolean needReload = context == null || needReloadTemplate(context, template); if (needReload) { - FILE stashFile = templateToStashFile(template); + FILE stashFile = template.templateToStashFile(); if (stashFile != null) { FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName()); template.refreshResource(stashFile); 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 904cdf00b0..c1be964145 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); } @@ -555,6 +556,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void fixFunctionNameList(String functionName) { int signOfContinue = 1; int indexOfFunction = 0; + boolean found = false; for (int i = 0; i < functionTypeListModel.size(); i++) { int signOfType = 0; FunctionGroup functionType = (FunctionGroup) functionTypeListModel.getElementAt(i); @@ -568,6 +570,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { signOfType = 1; signOfContinue = 0; indexOfFunction = k; + found = true; } } @@ -577,8 +580,12 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { } } } - functionNameList.setSelectedIndex(indexOfFunction); - functionNameList.ensureIndexIsVisible(indexOfFunction); + if (found) { + functionNameList.setSelectedIndex(indexOfFunction); + functionNameList.ensureIndexIsVisible(indexOfFunction); + } else { + functionTypeList.setSelectedIndex(0); + } } private int getBeginPosition() { @@ -1036,7 +1043,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 +1284,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 0000000000..ff6b7faef3 --- /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 0000000000..3f4f191777 --- /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 0000000000..4def5370d0 --- /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 0e1c7c6ac2..daed7cd4c5 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 8168c767d5..cd37fd9bc4 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 0000000000..80a26bf965 --- /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 0000000000..0c534bf723 --- /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/gui/ilable/UIAutoChangeLineLabel.java b/designer-base/src/main/java/com/fr/design/gui/ilable/UIAutoChangeLineLabel.java new file mode 100644 index 0000000000..d2bb0450b1 --- /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/gui/style/BorderPane.java b/designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java index dcead1c878..3c917ea456 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) { 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 10e11c8fbb..10bee69d27 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 0000000000..b1516fe366 --- /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 158c05d1e1..6a83ad3d24 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 0000000000..23226c6dde --- /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 0000000000..7b568eff73 --- /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 0000000000..a5def05965 --- /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 0000000000..6790ec71e6 --- /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 0000000000..c33d7fe0ee --- /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 0000000000..b812d8b875 --- /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/java/com/fr/design/lock/LockInfoDialog.java b/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java index 71c9549248..a0fd544d53 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 f903912115..9c33534c7b 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/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java index 499898bbff..f1a40ccdc7 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java @@ -65,6 +65,7 @@ import com.fr.event.EventDispatcher; import com.fr.file.FILE; import com.fr.file.FILEChooserPane; import com.fr.file.MemFILE; +import com.fr.file.StashedFILE; import com.fr.form.ui.NoneWidget; import com.fr.form.ui.Widget; import com.fr.general.ComparatorUtils; @@ -104,6 +105,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingConstants; import javax.swing.undo.UndoManager; import java.awt.BorderLayout; +import java.io.ByteArrayOutputStream; import java.awt.Dimension; import java.awt.FontMetrics; import java.util.Set; @@ -438,6 +440,22 @@ public abstract class JTemplate> stopListenThemeConfig(); } + public FILE templateToStashFile() { + FILE file = this.getEditingFILE(); + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + BaseBook target = this.getTarget(); + if (target != null) { + target.export(outputStream); + return new StashedFILE(file, outputStream.toByteArray(), template.suffix()); + } + // 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return null; + } + /** * 刷新内部资源 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 8efbb1eee5..846da26491 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 @@ -88,13 +88,13 @@ public class CellStyleEditPane extends MultiTabPane { @Override public ThemedCellStyle updateBean() { - AbstractBasicStylePane basicStylePane = (AbstractBasicStylePane) paneList.get(tabPane.getSelectedIndex()); - Style style = basicStylePane.update(this.cellStyle.getStyle()); + Style style = this.cellStyle.getStyle(); CellBorderStyle borderStyle = createDefaultBorderStyleFromStyle(style); - - - if (ThemedFeatureController.isCellStyleSupportInnerBorder() && basicStylePane instanceof BorderPane) { - borderStyle = ((BorderPane) basicStylePane).update(); + for (BasicPane basicPane : paneList) { + style = ((AbstractBasicStylePane) basicPane).update(style); + if (ThemedFeatureController.isCellStyleSupportInnerBorder() && basicPane instanceof BorderPane) { + borderStyle = ((BorderPane) basicPane).update(); + } } this.cellStyle.setStyle(style); @@ -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)); } } } 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 e79bfcf6b8..f3de6eef96 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; } 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 9e60c6cc84..8c5e8858ac 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 2c38d597c4..48d6a5686e 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 1d1ac02f0d..2a834eebd8 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 00aceb6eb1..dd4888b4e5 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 0000000000..a77566442d --- /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 0000000000..d88a3a16eb --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/report/fit/FormFitConfigPane.java @@ -0,0 +1,163 @@ +package com.fr.design.report.fit; + +import com.fr.base.svg.SVGLoader; +import com.fr.design.gui.ibutton.UIRadioButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.imenu.UIPopupMenu; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.report.fit.menupane.FitRadioGroup; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.ComparatorUtils; +import com.fr.report.fit.ReportFitAttr; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class FormFitConfigPane extends ReportFitConfigPane { + private static final int ICON_OFFSET_X = 25; + private static final int ICON_OFFSET_Y = 3; + private static final int ICON_SIZE = 16; + private static final Image HOVER_IMAGE = SVGLoader.load("/com/fr/design/icon/icon_ec_default_fit.svg"); + 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; + } + + 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 = ComparatorUtils.equals(options[i], Toolkit.i18nText("Fine-Designer_Fit-Default")) ? new UIRadioButtonWithIcon(options[i]) : new UIRadioButton(options[i]); + fitRadioGroup.add(fontFitRadio); + components[i + 1] = fontFitRadio; + } else { + components[i + 1] = null; + } + } + fitRadioGroup.addActionListener(getPreviewActionListener()); + } + + private class UIRadioButtonWithIcon extends UIRadioButton { + private final JPopupMenu popupMenu; + private NewFitPreviewPane ecFitPreviewPane; + + public UIRadioButtonWithIcon(String text) { + super(text); + popupMenu = this.createPopupMenu(); + initMouseListener(); + } + + private JPopupMenu createPopupMenu() { + UIPopupMenu uiPopupMenu = new UIPopupMenu() { + @Override + protected void paintBorder(Graphics g) { + + } + }; + uiPopupMenu.setLayout(new BorderLayout(0, 0)); + uiPopupMenu.setOpaque(false); + uiPopupMenu.add(ecFitPreviewPane = new NewFitPreviewPane(FitType.HORIZONTAL_FIT), BorderLayout.CENTER); + ecFitPreviewPane.setPreferredSize(new Dimension(300, 204)); + return uiPopupMenu; + } + + private void initMouseListener() { + this.addMouseListener(new MouseAdapter() { + @Override + public void mouseExited(MouseEvent e) { + super.mouseExited(e); + hidePreviewPane(); + } + }); + int defaultTextWidth = calculateStartX(); + this.addMouseMotionListener(new MouseAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + super.mouseMoved(e); + if (new Rectangle(ICON_OFFSET_X + defaultTextWidth, ICON_OFFSET_Y, ICON_SIZE, ICON_SIZE).contains(e.getPoint())) { + showPreviewPane(e); + } else { + hidePreviewPane(); + } + + } + }); + } + + public void showPreviewPane(MouseEvent e) { + popupMenu.setVisible(true); + ecFitPreviewPane.refreshPreview(fontRadioGroup.isFontFit()); + GUICoreUtils.showPopupMenu(popupMenu, this, e.getX() + 10, e.getY() + 10); + } + + public void hidePreviewPane() { + if (popupMenu != null && popupMenu.isVisible()) { + popupMenu.setVisible(false); + } + } + + + @Override + public void paint(Graphics g) { + super.paint(g); + g.drawImage(HOVER_IMAGE, calculateStartX() + ICON_OFFSET_X, ICON_OFFSET_Y, null); + } + + private int calculateStartX() { + FontMetrics metrics = this.getFontMetrics(this.getFont()); + return metrics.stringWidth(this.getText()); + } + } + + 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 c4bdaf6de2..81ee474de1 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 0000000000..2bc69cedc7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/report/fit/NewFitPreviewPane.java @@ -0,0 +1,79 @@ +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 = 10; + private static final Dimension NO_FIT_CONTAINER_DIMENSION = new Dimension(230, 80); + + public NewFitPreviewPane(){ + + } + + public NewFitPreviewPane(FitType fitType){ + this.fitType = fitType; + } + + @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 0000000000..158089602f --- /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()); + } + + protected 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-base/src/main/java/com/fr/design/web/CustomIconPane.java b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java index 9e03dcc9dc..564b09d467 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; @@ -30,23 +30,35 @@ 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 java.awt.Window; +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编辑 @@ -414,7 +426,7 @@ public class CustomIconPane extends BasicPane { browseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - onBrowseButtonClicked(); + onBrowseButtonClicked(SwingUtilities.getWindowAncestor(EditIconDialog.this)); } }); @@ -449,12 +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 = new JavaFxNativeFileChooser.Builder(). - filter("Icon Image File", "*.jpg", "*.jpeg", "*.png", "*.gif"). - build(); - if (JFileChooser.APPROVE_OPTION == fileChooserProvider.showDialog(DesignerContext.getDesignerFrame())) { + FileChooserProvider fileChooserProvider = FileChooserFactory.createFileChooser(FileChooserArgs.newBuilder(). + setFilter("Icon Image File", "*.jpg", "*.jpeg", "*.png", "*.gif").build()); + if (JFileChooser.APPROVE_OPTION == fileChooserProvider.showDialog(parent)) { String path = fileChooserProvider.getSelectedFile().getAbsolutePath(); // 图片存储有最大值48*48限制,没有超过最大值时,按原图大小存储,超过最大值后,压缩至最大值存储 Image image = BaseUtils.readImage(path); 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 f8a0f5d4fa..ed2597f1d7 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-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 786fe2ad0c..aa4a83f3e4 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 0956fa79d7..96558262fd 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 17031793ff..05e20c7aa8 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 931b79b44f..a4b2993e60 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 8ea7fd7c26..5813cd96cc 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 diff --git a/designer-base/src/main/resources/com/fr/design/icon/icon_ec_default_fit.svg b/designer-base/src/main/resources/com/fr/design/icon/icon_ec_default_fit.svg new file mode 100644 index 0000000000..4deb67b0dd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/icon/icon_ec_default_fit.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/sort/asc.svg b/designer-base/src/main/resources/com/fr/design/images/sort/asc.svg deleted file mode 100644 index 67dd9e829e..0000000000 --- a/designer-base/src/main/resources/com/fr/design/images/sort/asc.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - 升序备份 - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/sort/des.svg b/designer-base/src/main/resources/com/fr/design/images/sort/des.svg deleted file mode 100644 index 2fcef077e6..0000000000 --- a/designer-base/src/main/resources/com/fr/design/images/sort/des.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - 降序 - - - - - - - - - - - - - - \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/sort/nosort.svg b/designer-base/src/main/resources/com/fr/design/images/sort/nosort.svg deleted file mode 100644 index ca04928fc8..0000000000 --- a/designer-base/src/main/resources/com/fr/design/images/sort/nosort.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - 不排序 - - - - - - - - - - - - - - - - - - - - \ No newline at end of file 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 0000000000..ad17929765 --- /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 0000000000..e268f70e18 --- /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-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 0000000000..e0d5ae7c9e --- /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 0000000000..2d0e50ba02 --- /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 0000000000..4ff0a321ed --- /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 diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChangeConfigPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChangeConfigPane.java index 3de9aaa09a..bbc923f4d8 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChangeConfigPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChangeConfigPane.java @@ -4,29 +4,42 @@ package com.fr.design.mainframe.chart.gui; * Created by hufan on 2016/10/20. */ +import com.fr.base.BaseFormula; +import com.fr.base.Utils; import com.fr.chart.base.AttrChangeConfig; import com.fr.chart.base.AttrChangeType; +import com.fr.chart.chartattr.Chart; import com.fr.chart.chartattr.ChartCollection; import com.fr.design.beans.BasicBeanPane; +import com.fr.design.foldablepane.UIExpandablePane; +import com.fr.design.formula.TinyFormulaPane; import com.fr.design.gui.ibutton.UIButtonGroup; +import com.fr.design.gui.ibutton.UIToggleButton; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ispinner.UISpinner; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; -import com.fr.design.i18n.Toolkit; - +import com.fr.stable.StableUtils; import com.fr.van.chart.designer.TableLayout4VanChartHelper; import javax.swing.BorderFactory; +import javax.swing.BoxLayout; import javax.swing.JPanel; import javax.swing.SwingConstants; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.List; /** * 图表切换设置面板 @@ -40,6 +53,7 @@ public class ChangeConfigPane extends BasicBeanPane { private static final int CONSTANT_TEN = 10; private static final int CONSTANT_THIRTY = 30; private static final int CONSTANT_ZERO = 0; + private static final int COL_COUNT = 4; private JPanel contentPane; //配置方式按钮 private UIButtonGroup configStyleButton; @@ -56,6 +70,11 @@ public class ChangeConfigPane extends BasicBeanPane { private ColorSelectBoxWithOutTransparent colorSelectBox4carousel; private UIButtonGroup switchStyleGroup; + private JPanel chartTypesPane; + private List switchTitles = new ArrayList<>(); + private JPanel switchTitlePane = new JPanel(); + private List changeChartButtons = new ArrayList<>(); + private int selectedChart; // 设置面板里面选取的图表,不是真正切换的图表 public ChangeConfigPane(){ initButtonGroup(); @@ -69,10 +88,11 @@ public class ChangeConfigPane extends BasicBeanPane { double p = TableLayout.PREFERRED; double f = TableLayout.FILL; double[] columnSize = {p, f}; - double[] rowSize = {p,p}; + double[] rowSize = {p, p, p}; Component[][] components = new Component[][]{ new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Change_Style")),configStyleButton}, new Component[]{configPane, null}, + new Component[]{createButtonContentPane(), null} }; return TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize); } @@ -147,14 +167,84 @@ public class ChangeConfigPane extends BasicBeanPane { return TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Basic_Background"), colorSelectBox4button, EDIT_AREA_WIDTH); } + private JPanel createButtonContentPane() { + JPanel buttonContentPane = new JPanel(new BorderLayout()); + + chartTypesPane = new JPanel(); + chartTypesPane.setLayout(new BoxLayout(chartTypesPane, BoxLayout.Y_AXIS)); + switchTitlePane.setLayout(new CardLayout()); + + buttonContentPane.add(chartTypesPane, BorderLayout.NORTH); + buttonContentPane.add( + TableLayout4VanChartHelper.createGapTableLayoutPane( + Toolkit.i18nText("Fine-Design_Chart_Switch_Title_Label"), + switchTitlePane, + EDIT_AREA_WIDTH + ), + BorderLayout.CENTER + ); + + UIExpandablePane expandablePane = new UIExpandablePane(Toolkit.i18nText("Fine-Design_Chart_Button_Content"), 20, buttonContentPane) { + protected void setcontentPanelontentPanelBorder() { + + } + }; + expandablePane.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0)); + return expandablePane; + } + + private void populateButtonContentPane(ChartCollection collection) { + int count = collection.getChartCount(); + int select = collection.getSelectedIndex(); + + JPanel pane = null; + for (int i = 0; i < count; i++) { + if (i % COL_COUNT == 0) { + pane = new JPanel(new FlowLayout(FlowLayout.LEFT)); + chartTypesPane.add(pane); + } + + ChangeChartButton button = new ChangeChartButton(i, collection); + changeChartButtons.add(button); + button.setSelected(i == select); + pane.add(button); + + populateSwitchTitlePane(i, collection); + } + + chartTypesPane.revalidate(); + switchTitlePane.revalidate(); + selectedChart = select; + } + + private void populateSwitchTitlePane(int chartIndex, ChartCollection collection) { + Chart chart = collection.getChart(chartIndex, Chart.class); + Object switchTitle = chart.getSwitchTitle(); + String result; + if (switchTitle != null) { + if (switchTitle instanceof BaseFormula) { + result = ((BaseFormula) switchTitle).getContent(); + } else { + result = Utils.objectToString(switchTitle); + } + } else { + result = collection.getChartName(chartIndex); + } + + TinyFormulaPane title = new TinyFormulaPane(); + title.populateBean(result); + switchTitles.add(title); + switchTitlePane.add(title, collection.getChartName(chartIndex)); + } + private JPanel createButtonConfigPane() { double p = TableLayout.PREFERRED; double f = TableLayout.FILL; double[] columnSize = {p, f}; - double[] rowSize = {p,p}; + double[] rowSize = {p, p, p}; Component[][] components = new Component[][]{ - new Component[]{createTitleStylePane(),null}, - new Component[]{createButtonBackgroundColorPane(),null}, + new Component[]{createTitleStylePane(), null}, + new Component[]{createButtonBackgroundColorPane(), null}, }; return TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize); @@ -195,6 +285,7 @@ public class ChangeConfigPane extends BasicBeanPane { //按钮切换界面 styleAttrPane.populate(changeConfigAttr.getStyleAttr()); colorSelectBox4button.setSelectObject(changeConfigAttr.getButtonColor()); + populateButtonContentPane(ob); //轮播切换界面 timeInterval.setValue(changeConfigAttr.getTimeInterval()); @@ -224,10 +315,64 @@ public class ChangeConfigPane extends BasicBeanPane { changeConfigAttr.setTimeInterval((int) timeInterval.getValue()); changeConfigAttr.setCarouselColor(colorSelectBox4carousel.getSelectObject()); changeConfigAttr.setShowArrow(switchStyleGroup.getSelectedIndex() == 0); + + updateSwitchTitle(ob); + } + + private void updateSwitchTitle(ChartCollection collection) { + int count = collection.getChartCount(); + for (int i = 0; i < count; i++) { + String titleString = switchTitles.get(i).updateBean(); + Object titleObj; + if (StableUtils.maybeFormula(titleString)) { + titleObj = BaseFormula.createFormulaBuilder().build(titleString); + } else { + titleObj = titleString; + } + collection.getChart(i, Chart.class).setSwitchTitle(titleObj); + } } @Override protected String title4PopupWindow() { return Toolkit.i18nText("Fine-Design_Chart_Change_Config_Attributes"); } + + private class ChangeChartButton extends UIToggleButton { + private static final int BUTTON_WIDTH = 52; + private static final int BUTTON_HEIGHT = 20; + + private ChartCollection collection; + private int buttonIndex; + + public ChangeChartButton(int i, ChartCollection collection) { + super(collection.getChartName(i)); + this.collection = collection; + this.buttonIndex = i; + } + + @Override + protected MouseListener getMouseListener() { + return new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + resetChangeChartButtons(); + CardLayout cardLayout = (CardLayout) switchTitlePane.getLayout(); + cardLayout.show(switchTitlePane, collection.getChartName(buttonIndex)); + ChangeChartButton.this.setSelected(true); + selectedChart = buttonIndex; + } + }; + } + + public Dimension getPreferredSize() { + return new Dimension(BUTTON_WIDTH, BUTTON_HEIGHT); + } + } + + private void resetChangeChartButtons() { + for (ChangeChartButton changeChartButton : changeChartButtons) { + changeChartButton.setSelected(false); + } + } } diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartGanttTimeLinePane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartGanttTimeLinePane.java new file mode 100644 index 0000000000..0af3a24b13 --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartGanttTimeLinePane.java @@ -0,0 +1,117 @@ +package com.fr.van.chart.designer.component; + +import com.fr.chart.chartattr.Plot; +import com.fr.design.gui.frpane.UINumberDragPaneWithPercent; +import com.fr.design.gui.ibutton.UIButtonGroup; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.TableLayout; +import com.fr.design.mainframe.chart.gui.ColorSelectBoxWithOutTransparent; +import com.fr.plugin.chart.gantt.VanChartGanttPlot; +import com.fr.van.chart.designer.TableLayout4VanChartHelper; + +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; + +public class VanChartGanttTimeLinePane extends JPanel { + private UIButtonGroup switchButton; + private ColorSelectBoxWithOutTransparent colorSelect; + private UINumberDragPaneWithPercent opacity; + + private JPanel centerPane; + + public VanChartGanttTimeLinePane() { + this.setLayout(new BorderLayout()); + this.add(createSwitchButtonPane(), BorderLayout.NORTH); + this.add(createCenterPane(), BorderLayout.CENTER); + } + + private JPanel createSwitchButtonPane() { + double[] columnSize = {TableLayout.PREFERRED, TableLayout.FILL}; + double[] rowSize = {TableLayout.PREFERRED, TableLayout.PREFERRED}; + String[] array = new String[]{Toolkit.i18nText("Fine-Design_Chart_Guide_Line_Not_Show"), Toolkit.i18nText("Fine-Design_Chart_Guide_Line_Show")}; + switchButton = new UIButtonGroup<>(array); + switchButton.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + setCenterPaneVisibility(); + } + }); + UILabel text = new UILabel(Toolkit.i18nText("Fine-Design_Chart_Guide_Line_Current_Line"), SwingConstants.LEFT); + return TableLayout4VanChartHelper.createGapTableLayoutPane(new Component[][] { + new Component[]{null, null}, + new Component[] {text, switchButton} + }, rowSize, columnSize); + } + + private JPanel createCenterPane() { + double[] columnSize = {TableLayout.FILL, TableLayout4VanChartHelper.EDIT_AREA_WIDTH}; + double[] rowSize = {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}; + + colorSelect = new ColorSelectBoxWithOutTransparent(100); + opacity = new UINumberDragPaneWithPercent(0, 100); + + centerPane = TableLayout4VanChartHelper.createGapTableLayoutPane(new Component[][] { + new Component[]{null, null}, + new Component[] {new UILabel(Toolkit.i18nText("Fine-Design_Chart_Color")), colorSelect}, + new Component[] {new UILabel(Toolkit.i18nText("Fine-Design_Report_Alpha")), opacity} + }, rowSize, columnSize); + + centerPane.setVisible(false); + + return centerPane; + } + + public void populateBean(Plot plot) { + if (plot instanceof VanChartGanttPlot) { + VanChartGanttPlot ganttPlot = (VanChartGanttPlot) plot; + setShowTimeLine(ganttPlot.isShowTimeLine()); + setTimeLineColor(ganttPlot.getTimeLineColor()); + setTimeLineOpacity(ganttPlot.getTimeLineOpacity()); + + centerPane.setVisible(ganttPlot.isShowTimeLine()); + } + } + + public void updateBean(Plot plot) { + if (plot instanceof VanChartGanttPlot) { + VanChartGanttPlot ganttPlot = (VanChartGanttPlot) plot; + ganttPlot.setShowTimeLine(isShowTimeLine()); + ganttPlot.setTimeLineColor(getTimeLineColor()); + ganttPlot.setTimeLineOpacity(getTimeLineOpacity()); + } + } + + private void setCenterPaneVisibility() { + centerPane.setVisible(switchButton.getSelectedIndex() == 1); + } + + public boolean isShowTimeLine() { + return switchButton.getSelectedIndex() == 1; + } + + public void setShowTimeLine(boolean showTimeLine) { + switchButton.setSelectedIndex(showTimeLine ? 1 : 0); + } + + public Color getTimeLineColor() { + return colorSelect.getSelectObject(); + } + + public void setTimeLineColor(Color timeLineColor) { + colorSelect.setSelectObject(timeLineColor); + } + + public double getTimeLineOpacity() { + return opacity.updateBean(); + } + + public void setTimeLineOpacity(double timeLineOpacity) { + opacity.populateBean(timeLineOpacity); + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartGantAreaPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartGantAreaPane.java new file mode 100644 index 0000000000..382a918270 --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartGantAreaPane.java @@ -0,0 +1,15 @@ +package com.fr.van.chart.designer.style.background; + +import com.fr.chart.chartattr.Plot; +import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; +import com.fr.van.chart.designer.style.VanChartStylePane; + +public class VanChartGantAreaPane extends VanChartAreaPane { + public VanChartGantAreaPane(Plot plot, VanChartStylePane parent) { + super(plot, parent); + } + + protected void initPlotPane(boolean b, AbstractAttrNoScrollPane parent) { + plotPane = new VanChartGantPlotAreaBackgroundPane(parent); + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartGantPlotAreaBackgroundPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartGantPlotAreaBackgroundPane.java new file mode 100644 index 0000000000..fbea849909 --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartGantPlotAreaBackgroundPane.java @@ -0,0 +1,102 @@ +package com.fr.van.chart.designer.style.background; + +import com.fr.chart.chartattr.Chart; +import com.fr.chart.chartattr.Plot; +import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.chart.gui.ColorSelectBoxWithOutTransparent; +import com.fr.plugin.chart.gantt.VanChartGanttPlot; +import com.fr.van.chart.designer.TableLayout4VanChartHelper; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; + +public class VanChartGantPlotAreaBackgroundPane extends VanChartAreaBackgroundPane { + private ColorSelectBoxWithOutTransparent axisColorPane; + private ColorSelectBoxWithOutTransparent contentColorPane; + + public VanChartGantPlotAreaBackgroundPane(AbstractAttrNoScrollPane parent) { + super(true, parent); + } + + @Override + protected JPanel createContentPane() { + JPanel contentPane = new JPanel(new BorderLayout()); + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + double[] columnSize = {f}; + double[] rowSize = {p, p}; + Component[][] components = new Component[][]{ + new Component[]{createAxisBorderPane()}, + new Component[]{createContentBorderPane()} + }; + + contentPane.add(TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize), BorderLayout.CENTER); + return contentPane; + } + + @Override + public void updateBean(Chart chart) { + if (chart == null) { + chart = new Chart(); + } + + Plot plot = chart.getPlot(); + if (plot instanceof VanChartGanttPlot) { + VanChartGanttPlot ganttPlot = (VanChartGanttPlot) plot; + ganttPlot.setAxisBorderColor(axisColorPane.getSelectObject()); + ganttPlot.setContentBorderColor(contentColorPane.getSelectObject()); + } + } + + @Override + public void populateBean(Chart chart) { + if (chart == null) { + chart = new Chart(); + } + + Plot plot = chart.getPlot(); + if (plot instanceof VanChartGanttPlot) { + VanChartGanttPlot ganttPlot = (VanChartGanttPlot) plot; + axisColorPane.setSelectObject(ganttPlot.getAxisBorderColor()); + contentColorPane.setSelectObject(ganttPlot.getContentBorderColor()); + } + } + + private JPanel createAxisBorderPane() { + axisColorPane = new ColorSelectBoxWithOutTransparent(100); + return TableLayout4VanChartHelper.createExpandablePaneWithTitle( + Toolkit.i18nText("Fine-Design_Chart_Gant_Axis_Border"), + createBorderPane(axisColorPane) + ); + } + + private JPanel createContentBorderPane() { + contentColorPane = new ColorSelectBoxWithOutTransparent(100); + return TableLayout4VanChartHelper.createExpandablePaneWithTitle( + Toolkit.i18nText("Fine-Design_Chart_Gant_Content_Border"), + createBorderPane(contentColorPane) + ); + } + + private JPanel createBorderPane(ColorSelectBoxWithOutTransparent colorPane) { + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + double[] columnSize = {f, TableLayout4VanChartHelper.EDIT_AREA_WIDTH}; + double[] rowSize = {p, p}; + + Component[][] components = new Component[][]{ + new Component[]{null, null}, + new Component[]{ + new UILabel(Toolkit.i18nText("Fine-Design_Chart_Color")), + colorPane + } + }; + + return TableLayout4VanChartHelper.createGapTableLayoutPane(components, rowSize, columnSize); + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/VanChartGanttStylePane.java b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/VanChartGanttStylePane.java index b12e0579fa..7d1de704fc 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/VanChartGanttStylePane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/VanChartGanttStylePane.java @@ -4,6 +4,8 @@ import com.fr.chart.chartattr.Plot; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.frpane.AttributeChangeListener; import com.fr.van.chart.designer.style.VanChartStylePane; +import com.fr.van.chart.designer.style.background.VanChartAreaPane; +import com.fr.van.chart.designer.style.background.VanChartGantAreaPane; import com.fr.van.chart.gantt.designer.style.axis.GanttProcessAxisPane; import com.fr.van.chart.gantt.designer.style.axis.GanttTimeAxisPane; @@ -31,4 +33,8 @@ public class VanChartGanttStylePane extends VanChartStylePane { private void addProjectAxisPane(List paneList, Plot plot) { paneList.add(new GanttProcessAxisPane()); } + + protected VanChartAreaPane createVanChartAreaPane() { + return new VanChartGantAreaPane(getChart().getPlot(), VanChartGanttStylePane.this); + } } diff --git a/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/series/VanChartGanttSeriesPane.java b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/series/VanChartGanttSeriesPane.java index 9236773e71..a62f054e7f 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/series/VanChartGanttSeriesPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/series/VanChartGanttSeriesPane.java @@ -5,6 +5,7 @@ import com.fr.design.beans.BasicBeanPane; import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.icombobox.LineComboBox; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.chart.gui.ChartStylePane; @@ -14,6 +15,7 @@ import com.fr.plugin.chart.gantt.VanChartGanttPlot; import com.fr.stable.CoreConstants; import com.fr.van.chart.designer.TableLayout4VanChartHelper; import com.fr.van.chart.designer.component.VanChartBeautyPane; +import com.fr.van.chart.designer.component.VanChartGanttTimeLinePane; import com.fr.van.chart.designer.component.VanChartMarkerPane; import com.fr.van.chart.designer.component.marker.VanChartCommonMarkerPane; import com.fr.van.chart.designer.style.series.VanChartAbstractPlotSeriesPane; @@ -30,6 +32,8 @@ public class VanChartGanttSeriesPane extends VanChartAbstractPlotSeriesPane { private LineComboBox lineWidth;//线型 private ColorSelectBoxWithOutTransparent colorSelect;//颜色 + private VanChartGanttTimeLinePane timeLinePane; + public VanChartGanttSeriesPane(ChartStylePane parent, Plot plot) { super(parent, plot); } @@ -45,7 +49,8 @@ public class VanChartGanttSeriesPane extends VanChartAbstractPlotSeriesPane { new Component[]{createGanntStylePane()}, new Component[]{createLinkLinePane()}, new Component[]{createMarkerPane()}, - new Component[]{createLargeDataModelPane()} + new Component[]{createLargeDataModelPane()}, + new Component[]{createGuideLinePane()} }; contentPane = TableLayoutHelper.createTableLayoutPane(components, row, col); @@ -96,6 +101,11 @@ public class VanChartGanttSeriesPane extends VanChartAbstractPlotSeriesPane { return TableLayout4VanChartHelper.createExpandablePaneWithTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Gannt_Marker"), markerPane); } + protected JPanel createGuideLinePane() { + timeLinePane = new VanChartGanttTimeLinePane(); + return TableLayout4VanChartHelper.createExpandablePaneWithTitle(Toolkit.i18nText("Fine-Design_Chart_Guide_Line_Identify"), timeLinePane); + } + @Override public void populateBean(Plot plot) { super.populateBean(plot); @@ -104,10 +114,10 @@ public class VanChartGanttSeriesPane extends VanChartAbstractPlotSeriesPane { VanChartGanttPlot ganttPlot = (VanChartGanttPlot)plot; seriesNewLine.setSelectedIndex(ganttPlot.isSeriesNewLineEnable() ? 0 : 1); - lineWidth.setSelectedLineStyle(ganttPlot.getLineWidth()); colorSelect.setSelectObject(ganttPlot.getLineColor()); + timeLinePane.populateBean(plot); } } @@ -121,6 +131,7 @@ public class VanChartGanttSeriesPane extends VanChartAbstractPlotSeriesPane { ganttPlot.setLineWidth(lineWidth.getSelectedLineStyle()); ganttPlot.setLineColor(colorSelect.getSelectObject()); + timeLinePane.updateBean(plot); } } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/ComponentAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/ComponentAdapter.java index 174f56ea2d..b296da48b5 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/ComponentAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/ComponentAdapter.java @@ -1,35 +1,24 @@ package com.fr.design.designer.beans; -import java.awt.Graphics; -import java.awt.event.MouseEvent; -import java.util.ArrayList; - -import javax.swing.JComponent; -import javax.swing.JPopupMenu; - import com.fr.design.beans.GroupModel; import com.fr.design.designer.beans.events.DesignerEditor; import com.fr.design.designer.creator.PropertyGroupPane; +import javax.swing.JComponent; +import javax.swing.JPopupMenu; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + /** * 组件适配器接口 * 主要目的是为具体组件提供特殊设计行为 */ public interface ComponentAdapter { - /** - * 在组件选择面板上选择了组件类型后,在设计界面上跟随鼠标移动用来代表当前要添加组件的图形 - * 一般使用组件自身的图形代替。 - * - * @param component 要添加的组件 - * @param g 当前设计器的图形上下文对象 - */ - void paintComponentMascot(Graphics g); - /** * 当鼠标在此设计组件上右键点击时,该方法根据上下文和组件类型提供弹出响应的菜单 * - * @param 引发弹出菜单的鼠标事件 + * @param e 引发弹出菜单的鼠标事件 * * @return 弹出菜单 */ @@ -49,7 +38,7 @@ public interface ComponentAdapter { /** * 提供双击设计器的编辑器 - * @param bean 鼠标双击的被设计组件 + * * @return 被设计的编辑器 */ public DesignerEditor getDesignerEditor(); @@ -57,5 +46,5 @@ public interface ComponentAdapter { /** * 实例化组件的适配器后,在这儿进行初始化 */ - void initialize(); + void initialize(); } \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/LayoutAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/LayoutAdapter.java index 3c0c2bd5f2..bbc7670a45 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/LayoutAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/LayoutAdapter.java @@ -3,11 +3,15 @@ package com.fr.design.designer.beans; import com.fr.design.beans.GroupModel; import com.fr.design.designer.beans.adapters.layout.DefaultDesignerBaseOperate; import com.fr.design.designer.beans.adapters.layout.DesignerBaseOperate; +import com.fr.design.designer.beans.models.DraggingModel; import com.fr.design.designer.beans.models.SelectionModel; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.treeview.DefaultXCreatorTreeCellRender; import com.fr.design.designer.treeview.XCreatorTreeCellRender; +import java.awt.Dimension; +import java.awt.Graphics; + /** * 该接口是LayoutManager的BeanInfo类。标准Java平台没有提供布局管理器的BeanInfo类, * 对于界面设计工具来说还需一些特殊的行为。 @@ -135,9 +139,46 @@ public interface LayoutAdapter { return true; } + /** + * 拖拽开始 + * + * @param xCreator + * @param selectionModel + */ void dragStart(XCreator xCreator, SelectionModel selectionModel); + /** + * 拖拽经过 + * + * @param xCreator + * @param selectionModel + * @param x + * @param y + */ default void dragOver(XCreator xCreator, SelectionModel selectionModel, int x, int y) { }; + + /** + * 组件正在被拖拽时的处理逻辑 + * + * @param model + */ + void dragging(DraggingModel model); + + /** + * 绘制组件拖拽阴影 + * + * @param g 当前设计器的图形上下文对象 + * @param xCreator 被拖拽的组件 + */ + void paintComponentMascot(Graphics g, XCreator xCreator); + + /** + * 描述组件被拖拽的时候应该显示的尺寸 + * + * @param creator 被拖拽的组件 + * @return 组件大小 + */ + Dimension getDragSize(XCreator creator); } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/component/CompositeComponentAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/component/CompositeComponentAdapter.java index cb7a7a6207..d97b85c5ae 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/component/CompositeComponentAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/component/CompositeComponentAdapter.java @@ -23,13 +23,9 @@ import com.fr.stable.core.PropertyChangeAdapter; import javax.swing.Action; import javax.swing.JComponent; import javax.swing.JPopupMenu; -import java.awt.AlphaComposite; import java.awt.Component; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; import java.beans.IntrospectionException; import java.util.ArrayList; import java.util.Collections; @@ -63,19 +59,6 @@ public class CompositeComponentAdapter implements ComponentAdapter { } } - @Override - public void paintComponentMascot(Graphics g) { - //自适应交叉点渲染有点问题,拖拽的控件设置成半透明 - Graphics2D g2d = (Graphics2D) g; - AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f); - g2d.setComposite(composite); - BufferedImage im = new BufferedImage(xCreator.getWidth(), xCreator.getHeight(), BufferedImage.TYPE_INT_ARGB); - xCreator.paint(im.getGraphics()); - g.drawImage(im, 0, 0, xCreator.initEditorSize().width - 1, xCreator.initEditorSize().height - 1, null); - g.setColor(XCreatorConstants.RESIZE_BOX_BORDER_COLOR); - g.drawRect(0, 0, xCreator.initEditorSize().width - 1, xCreator.initEditorSize().height - 1); - } - @Override public JPopupMenu getContextPopupMenu(MouseEvent e) { JPopupMenu popupMenu = new JPopupMenu(); diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/AbstractLayoutAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/AbstractLayoutAdapter.java index 7d287e5a5a..e0f79e65ed 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/AbstractLayoutAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/AbstractLayoutAdapter.java @@ -4,16 +4,23 @@ import com.fr.design.beans.GroupModel; import com.fr.design.designer.beans.ConstraintsGroupModel; import com.fr.design.designer.beans.HoverPainter; import com.fr.design.designer.beans.LayoutAdapter; +import com.fr.design.designer.beans.models.DraggingModel; import com.fr.design.designer.beans.models.SelectionModel; import com.fr.design.designer.beans.painters.NullPainter; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.creator.XWidgetCreator; +import com.fr.design.form.util.XCreatorConstants; import com.fr.design.utils.ComponentUtils; import com.fr.design.utils.gui.LayoutUtils; import com.fr.general.ComparatorUtils; +import java.awt.AlphaComposite; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.LayoutManager; +import java.awt.image.BufferedImage; public abstract class AbstractLayoutAdapter implements LayoutAdapter { @@ -209,4 +216,28 @@ public abstract class AbstractLayoutAdapter implements LayoutAdapter { selectionModel.removeCreator(xCreator, xCreator.getWidth(), xCreator.getHeight()); selectionModel.setSelectedCreator(container); } + + @Override + public void dragging(DraggingModel model) { + + } + + @Override + public void paintComponentMascot(Graphics g, XCreator xCreator) { + //自适应交叉点渲染有点问题,拖拽的控件设置成半透明 + int dragWidth = this.getDragSize(xCreator).width, dragHeight = this.getDragSize(xCreator).height; + Graphics2D g2d = (Graphics2D) g; + AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f); + g2d.setComposite(composite); + BufferedImage im = new BufferedImage(xCreator.getWidth(), xCreator.getHeight(), BufferedImage.TYPE_INT_ARGB); + xCreator.paint(im.getGraphics()); + g.drawImage(im, 0, 0, dragWidth - 1, dragHeight - 1, null); + g.setColor(XCreatorConstants.RESIZE_BOX_BORDER_COLOR); + g.drawRect(0, 0, dragWidth - 1, dragHeight - 1); + } + + @Override + public Dimension getDragSize(XCreator xCreator) { + return xCreator.initEditorSize(); + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRAbsoluteLayoutAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRAbsoluteLayoutAdapter.java index e4426f61ad..5bdfe3c298 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRAbsoluteLayoutAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRAbsoluteLayoutAdapter.java @@ -3,10 +3,12 @@ package com.fr.design.designer.beans.adapters.layout; import com.fr.design.beans.GroupModel; import com.fr.design.designer.beans.ConstraintsGroupModel; import com.fr.design.designer.beans.HoverPainter; +import com.fr.design.designer.beans.models.DraggingModel; import com.fr.design.designer.beans.painters.FRAbsoluteLayoutPainter; import com.fr.design.designer.creator.*; import com.fr.design.designer.properties.BoundsGroupModel; import com.fr.design.designer.properties.FRAbsoluteLayoutPropertiesGroupModel; +import com.fr.design.mainframe.FormDesigner; import com.fr.design.utils.ComponentUtils; import com.fr.design.utils.gui.LayoutUtils; import com.fr.form.ui.Widget; @@ -15,6 +17,7 @@ import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import java.awt.*; +import java.awt.event.MouseEvent; public class FRAbsoluteLayoutAdapter extends FRBodyLayoutAdapter { //是不是添加到父容器上 @@ -345,4 +348,16 @@ public class FRAbsoluteLayoutAdapter extends FRBodyLayoutAdapter { XWAbsoluteLayout xwAbsoluteLayout = (XWAbsoluteLayout) container; return new FRAbsoluteLayoutPropertiesGroupModel(xwAbsoluteLayout); } + + @Override + public void dragging(DraggingModel model) { + FormDesigner designer = model.getDesigner(); + MouseEvent dragEvent = model.getCurrentDragEvent(); + designer.getStateModel().dragging(dragEvent); + } + + @Override + public Dimension getDragSize(XCreator xCreator) { + return xCreator.getSize(); + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRBodyLayoutAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRBodyLayoutAdapter.java index 5a31bab40d..f4c0458611 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRBodyLayoutAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRBodyLayoutAdapter.java @@ -6,12 +6,13 @@ import com.fr.design.designer.creator.XWParameterLayout; import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout; import com.fr.design.utils.ComponentUtils; import com.fr.form.ui.PaddingMargin; -import com.fr.form.ui.container.WBorderLayout; import com.fr.form.ui.container.cardlayout.WCardMainBorderLayout; import com.fr.general.ComparatorUtils; -import java.awt.*; -import java.util.*; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.util.ArrayList; /** * 这个类用作fit和absolute的父类,存放公共的方法 @@ -1182,5 +1183,4 @@ public class FRBodyLayoutAdapter extends AbstractLayoutAdapter { this.isCalculateChildPos = false; return childPosition; } - } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java index 9871d1b32f..3814dc6006 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/adapters/layout/FRFitLayoutAdapter.java @@ -8,6 +8,7 @@ import com.fr.design.beans.GroupModel; import com.fr.design.designer.beans.ConstraintsGroupModel; import com.fr.design.designer.beans.HoverPainter; import com.fr.design.designer.beans.LayoutAdapter; +import com.fr.design.designer.beans.models.DraggingModel; import com.fr.design.designer.beans.models.SelectionModel; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XCreatorUtils; @@ -22,6 +23,8 @@ import com.fr.design.designer.properties.FRFitLayoutConstraints; import com.fr.design.designer.properties.FRFitLayoutPropertiesGroupModel; import com.fr.design.designer.treeview.XCreatorTreeCellRender; import com.fr.design.fun.FormWidgetOptionProvider; +import com.fr.design.mainframe.FormCreatorDropTarget; +import com.fr.design.mainframe.FormDesigner; import com.fr.design.utils.ComponentUtils; import com.fr.form.ui.LayoutBorderStyle; import com.fr.form.ui.container.WAbsoluteLayout; @@ -34,6 +37,7 @@ import com.fr.general.act.BorderPacker; import java.awt.Component; import java.awt.Dimension; import java.awt.Rectangle; +import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -1244,4 +1248,26 @@ public class FRFitLayoutAdapter extends FRBodyLayoutAdapter { public void dragOver(XCreator xCreator, SelectionModel selectionModel,int x, int y) { frLayoutState.dragOver(xCreator, selectionModel,x,y); } + + @Override + public void dragging(DraggingModel model) { + FormDesigner designer = model.getDesigner(); + MouseEvent lastPressEvent = model.getStartDragEvent(); + MouseEvent dragEvent = model.getCurrentDragEvent(); + XCreator creator = model.getCreator(); + if ((lastPressEvent == null) || (creator == null)) { + return; + } + + if (dragEvent.getPoint().distance(lastPressEvent.getPoint()) > 5) { + if (creator.isSupportDrag()) { + designer.bindTransferHandler(lastPressEvent); + designer.fireParentLayoutDragStart(creator); + designer.setDropTarget(new FormCreatorDropTarget(designer, creator)); + // 触发状态添加模式事件 + designer.repaint(); + } + dragEvent.consume(); + } + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/events/AddingWidgetListener.java b/designer-form/src/main/java/com/fr/design/designer/beans/events/AddingWidgetListener.java new file mode 100644 index 0000000000..04d6cd72c3 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/designer/beans/events/AddingWidgetListener.java @@ -0,0 +1,9 @@ +package com.fr.design.designer.beans.events; + +import java.util.EventListener; + +public interface AddingWidgetListener extends EventListener { + void beforeAdded(); + + void afterAdded(boolean addResult); +} diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/events/AddingWidgetListenerTable.java b/designer-form/src/main/java/com/fr/design/designer/beans/events/AddingWidgetListenerTable.java new file mode 100644 index 0000000000..4825e88883 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/designer/beans/events/AddingWidgetListenerTable.java @@ -0,0 +1,54 @@ +package com.fr.design.designer.beans.events; + +import com.fr.general.ComparatorUtils; + +import javax.swing.SwingUtilities; +import java.util.ArrayList; +import java.util.List; + +public class AddingWidgetListenerTable { + protected List listeners = new ArrayList<>(); + + public AddingWidgetListenerTable() { + + } + + public void addListener(AddingWidgetListener listener) { + if (listener == null) { + return; + } + for (int i = 0; i < listeners.size(); i++) { + if (ComparatorUtils.equals(listener, listeners.get(i))) { + listeners.set(i, listener); + return; + } + } + listeners.add(listener); + } + + public void beforeAdded() { + for (final AddingWidgetListener listener : listeners) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + listener.beforeAdded(); + } + }); + } + } + + public void afterAdded(boolean addResult) { + for (final AddingWidgetListener listener : listeners) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + listener.afterAdded(addResult); + } + }); + } + } + + public void clearListeners() { + listeners.clear(); + } +} diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java index ba0cf5dd05..c47188d4ee 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/AddingModel.java @@ -1,17 +1,6 @@ package com.fr.design.designer.beans.models; -import com.fr.design.designer.beans.AdapterBus; -import com.fr.design.designer.beans.ComponentAdapter; -import com.fr.design.designer.beans.adapters.component.CompositeComponentAdapter; import com.fr.design.designer.creator.XCreator; -import com.fr.design.designer.creator.XCreatorUtils; -import com.fr.design.designer.creator.XLayoutContainer; -import com.fr.design.designer.creator.XWParameterLayout; -import com.fr.design.mainframe.FormDesigner; -import com.fr.design.utils.ComponentUtils; -import com.fr.general.ComparatorUtils; - -import java.awt.Rectangle; /** * 添加状态下的model @@ -20,128 +9,16 @@ public class AddingModel { // 当前要添加的组件 private XCreator creator; - // 记录当前鼠标的位置信息 - private int currentX; - private int currentY; - private boolean added; private boolean addedIllegal = false; // 有时候是添加完成了,但是添加会造成某些控件size不合法,例如tab - public AddingModel(FormDesigner designer, XCreator xCreator) { - this.creator = xCreator; - instantiateCreator(designer); - // 初始的时候隐藏该组件的图标 - currentY = -this.creator.getWidth(); - currentX = -this.creator.getHeight(); - } - - /** - * 待说明 - * - * @param designer 设计器 - */ - public void instantiateCreator(FormDesigner designer) { - - ModelUtil.renameWidgetName(designer.getTarget(), creator); - ComponentAdapter adapter = new CompositeComponentAdapter(designer, creator); - adapter.initialize(); - creator.addNotify(); - creator.putClientProperty(AdapterBus.CLIENT_PROPERTIES, adapter); - } - - public AddingModel(XCreator xCreator, int x, int y) { + public AddingModel(XCreator xCreator) { this.creator = xCreator; - this.creator.backupCurrentSize(); - this.creator.backupParent(); - currentX = x - (xCreator.initEditorSize().width / 2); - currentY = y - (xCreator.initEditorSize().height / 2); - } - - /** - * 隐藏当前组件的图标 - */ - public void reset() { - currentX = -this.creator.getWidth(); - currentY = -this.creator.getHeight(); - } - - public String getXCreatorName(FormDesigner designer, XCreator x) { - String def = x.createDefaultName(); - if (x.acceptType(XWParameterLayout.class)) { - return def; - } - int i = 0; - while (designer.getTarget().isNameExist(def + i)) { - i++; - } - return def + i; - } - - - public int getCurrentX() { - return currentX; - } - - public int getCurrentY() { - return currentY; - } - - - /** - * 移动组件图标到鼠标事件发生的位置 - * - * @param x 坐标 - * @param y 坐标 - */ - public void moveTo(int x, int y) { - currentX = x - (this.creator.initEditorSize().width / 2); - currentY = y - (this.creator.initEditorSize().height / 2); } public XCreator getXCreator() { return this.creator; } - public boolean need2paint(){ - return currentX + this.creator.getWidth() > 0 && currentY + this.creator.getHeight() > 0; - } - - /** - * 当前组件是否已经添加到某个容器中 - * - * @return 是返回true - */ - public boolean isCreatorAdded() { - return added; - } - - /** - * 加入容器 - * - * @param designer 设计器 - * @param container 容器 - * @param x 坐标 - * @param y 坐标 - * @return 成功返回true - */ - public boolean add2Container(FormDesigner designer, XLayoutContainer container, int x, int y) { - //考虑不同布局嵌套的情况,获取顶层容器 - XLayoutContainer xLayoutContainer = XCreatorUtils.getTopEditableContainer(container); - if (xLayoutContainer != null) { - container = xLayoutContainer; - } - Rectangle rect = ComponentUtils.getRelativeBounds(container); - if (!ComparatorUtils.equals(container.getOuterLayout(), container.getBackupParent())) { - added = container.getLayoutAdapter().addBean(creator, - x + designer.getHorizontalScaleValue(), - y + designer.getVerticalScaleValue() ); - return added; - } - added = container.getLayoutAdapter().addBean(creator, - x + designer.getHorizontalScaleValue() - rect.x, - y + designer.getVerticalScaleValue() - rect.y); - return added; - } - public boolean isAddedIllegal() { return addedIllegal; } diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/DraggingModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/DraggingModel.java new file mode 100644 index 0000000000..6308ff70b5 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/DraggingModel.java @@ -0,0 +1,98 @@ +package com.fr.design.designer.beans.models; + +import com.fr.design.designer.beans.LayoutAdapter; +import com.fr.design.designer.creator.XCreator; +import com.fr.design.designer.creator.XLayoutContainer; +import com.fr.design.mainframe.FormDesigner; + +import java.awt.event.MouseEvent; + +public class DraggingModel { + private FormDesigner designer; + private XCreator creator; + private MouseEvent startDragEvent; + private MouseEvent currentDragEvent; + private int creatorLeftTopX = -999; // 隐藏 + private int creatorLeftTopY = -999; // 隐藏 + private boolean dragNewWidget; // 是否正在拖拽一个新的组件下来 + + public DraggingModel() { + + } + + public DraggingModel designer(FormDesigner designer) { + this.designer = designer; + return this; + } + + public DraggingModel startDragEvent(MouseEvent startDragEvent) { + this.startDragEvent = startDragEvent; + return this; + } + + public DraggingModel currentDragEvent(MouseEvent dragEvent) { + this.currentDragEvent = dragEvent; + return this; + } + + public DraggingModel creator(XCreator creator) { + this.creator = creator; + return this; + } + + public DraggingModel dragNewWidget(boolean dragNewWidget) { + this.dragNewWidget = dragNewWidget; + return this; + } + + public FormDesigner getDesigner() { + return designer; + } + + public MouseEvent getStartDragEvent() { + return startDragEvent; + } + + public MouseEvent getCurrentDragEvent() { + return currentDragEvent; + } + + public XCreator getCreator() { + return creator; + } + + /** + * 获取被拖拽组件当前随着鼠标移动时应当所在的左上角横坐标 + * + * @return + */ + public int getCreatorLeftTopX() { + return creatorLeftTopX; + } + + /** + * 获取被拖拽组件当前随着鼠标移动时应当所在的左上角纵坐标 + * + * @return + */ + public int getCreatorLeftTopY() { + return creatorLeftTopY; + } + + public boolean isDragNewWidget() { + return dragNewWidget; + } + + public void moveTo(int x, int y) { + XLayoutContainer container = designer.getDraggingHotspotLayout(); + LayoutAdapter adapter = container.getLayoutAdapter(); + + creatorLeftTopX = x - adapter.getDragSize(creator).width / 2; + creatorLeftTopY = y - adapter.getDragSize(creator).height / 2; + } + + public void reset() { + creatorLeftTopX = -creator.getWidth(); + creatorLeftTopY = -creator.getHeight(); + } +} diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java index 3b676921b1..390c45825d 100644 --- a/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java +++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java @@ -36,7 +36,7 @@ public class StateModel { private SelectionModel selectionModel; // 当前鼠标进入拖拽区域的位置类型 - private Direction driection; + private Direction direction; // 当前拖拽的起始位置 private int currentX; @@ -74,7 +74,7 @@ public class StateModel { * @return direction方向 */ public Direction getDirection() { - return driection; + return direction; } /** @@ -96,7 +96,7 @@ public class StateModel { * @return 非outer且选中为空 */ public boolean dragable() { - return ((driection != Location.outer) && !selecting); + return ((direction != Location.outer) && !selecting); } /** @@ -108,7 +108,7 @@ public class StateModel { addable = false; designer.setPainter(null); - if (driection != Location.inner) { + if (direction != Location.inner) { return; } @@ -283,7 +283,7 @@ public class StateModel { */ public void startResizing(MouseEvent e) { if (!selectionModel.getSelection().isEmpty()) { - driection.backupBounds(designer); + direction.backupBounds(designer); } currentX = getMouseXY(e).x; currentY = getMouseXY(e).y; @@ -409,7 +409,7 @@ public class StateModel { * 重置 */ public void reset() { - driection = Location.outer; + direction = Location.outer; aspectRatioLocked = false; dragging = false; selecting = false; @@ -429,9 +429,9 @@ public class StateModel { * @param dir 拉伸方向 */ public void setDirection(Direction dir) { - if (driection != dir) { - this.driection = dir; - driection.updateCursor(designer); + if (direction != dir) { + this.direction = dir; + direction.updateCursor(designer); } } @@ -495,7 +495,7 @@ public class StateModel { FormSelection selection = this.selectionModel.getSelection(); this.aspectRatioLocked = selection.isCreatorAspectRatioLockedInAbsLayout(designer) || (this.selectionModel.getSelection().isCreatorInAbsLayout(designer) && e.isShiftDown()); - driection.drag(getMouseXY(e).x - currentX, getMouseXY(e).y - currentY, designer); + direction.drag(getMouseXY(e).x - currentX, getMouseXY(e).y - currentY, designer); this.dragging = true; } @@ -552,4 +552,15 @@ public class StateModel { + designer.getArea().getVerticalValue()); } + public boolean isDraggingSize() { + return direction == Location.left + || direction == Location.left_top + || direction == Location.left_bottom + || direction == Location.right + || direction == Location.right_top + || direction == Location.right_bottom + || direction == Location.top + || direction == Location.bottom; + } + } \ No newline at end of file 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 01d09fe4cc..83a4c01b02 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 @@ -13,9 +13,11 @@ import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.widget.editors.PaddingMarginEditor; import com.fr.design.mainframe.widget.editors.WLayoutBorderStyleEditor; import com.fr.design.parameter.ParameterBridge; +import com.fr.design.utils.ComponentUtils; import com.fr.form.ui.Widget; import com.fr.form.ui.container.WLayout; import com.fr.general.Background; +import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.ArrayUtils; import com.fr.stable.core.PropertyChangeAdapter; @@ -24,6 +26,7 @@ import javax.swing.JComponent; import java.awt.Component; import java.awt.Dimension; import java.awt.LayoutManager; +import java.awt.Rectangle; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import java.beans.IntrospectionException; @@ -474,14 +477,6 @@ public abstract class XLayoutContainer extends XBorderStyleWidgetCreator impleme return 0; } - /** - * 切换到非添加状态 - * - * @param designer 表单设计器 - */ - public void stopAddingState(FormDesigner designer) { - } - /** * 寻找最近的为自适应布局的父容器 * @@ -617,4 +612,15 @@ public abstract class XLayoutContainer extends XBorderStyleWidgetCreator impleme public boolean isComponent() { return true; } + + public boolean addWidgetToContainer(XCreator creator, int x, int y) { + //考虑不同布局嵌套的情况,获取顶层容器 + XLayoutContainer xLayoutContainer = XCreatorUtils.getTopEditableContainer(this); + XLayoutContainer container = xLayoutContainer != null ? xLayoutContainer : this; + Rectangle rect = ComponentUtils.getRelativeBounds(container); + if (!ComparatorUtils.equals(container.getOuterLayout(), container.getBackupParent())) { + return container.getLayoutAdapter().addBean(creator, x, y); + } + return container.getLayoutAdapter().addBean(creator, x - rect.x, y - rect.y); + } } 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 fdc01be1e9..e09b31fb09 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 ceb334028a..850378af21 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 7cdca0a0bc..9695eee18a 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 边框 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 0000000000..dad6e9be9c --- /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 0000000000..51eda6d36e --- /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/DesignerTransferHandler.java b/designer-form/src/main/java/com/fr/design/mainframe/DesignerTransferHandler.java deleted file mode 100644 index e5b11dd9a4..0000000000 --- a/designer-form/src/main/java/com/fr/design/mainframe/DesignerTransferHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.fr.design.mainframe; - -import com.fr.design.designer.beans.models.AddingModel; -import com.fr.design.file.HistoryTemplateListPane; - -import javax.swing.JComponent; -import javax.swing.TransferHandler; -import java.awt.datatransfer.Transferable; - -public class DesignerTransferHandler extends TransferHandler { - - private FormDesigner designer; - private AddingModel addingModel; - - public DesignerTransferHandler(FormDesigner designer, AddingModel addingModel) { - super("rootComponent"); - this.designer = designer; - this.addingModel = addingModel; - } - - protected void exportDone(JComponent source, Transferable data, int action) { - if (!addingModel.isCreatorAdded()) { - undoWhenAddingFailed(); - } - } - - private void undoWhenAddingFailed() { - JTemplate jt = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); - if (jt != null) { - jt.undoToCurrent(); - } - } -} \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java index b0463a685a..f48b60320d 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java @@ -1,6 +1,5 @@ package com.fr.design.mainframe; -import com.fr.base.BaseUtils; import com.fr.base.vcs.DesignerMode; import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.designer.beans.AdapterBus; @@ -25,25 +24,18 @@ import com.fr.design.designer.creator.cardlayout.XCardAddButton; import com.fr.design.designer.creator.cardlayout.XCardSwitchButton; import com.fr.design.designer.creator.cardlayout.XWCardLayout; import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout; -import com.fr.design.form.util.XCreatorConstants; -import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.gui.xpane.ToolTipEditor; -import com.fr.design.icon.IconPathConstants; import com.fr.design.utils.ComponentUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.LayoutUtils; import com.fr.general.ComparatorUtils; import com.fr.stable.ArrayUtils; -import com.fr.stable.Constants; -import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JPopupMenu; -import javax.swing.JWindow; import javax.swing.SwingUtilities; import javax.swing.event.MouseInputAdapter; -import java.awt.Color; import java.awt.Container; import java.awt.Cursor; import java.awt.Insets; @@ -95,9 +87,6 @@ public class EditingMouseListener extends MouseInputAdapter { private DesignerEditor currentEditor; private XCreator currentXCreator; - //备份开始拖动的位置和大小 - private Rectangle dragBackupBounds; - private int pressX; private int pressY; @@ -121,40 +110,12 @@ public class EditingMouseListener extends MouseInputAdapter { private XElementCase xElementCase; private XChartEditor xChartEditor; - private JWindow promptWindow = new JWindow(); - public EditingMouseListener(FormDesigner designer) { this.designer = designer; stateModel = designer.getStateModel(); selectionModel = designer.getSelectionModel(); - UIButton promptButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Forbid_Drag_Into_Adapt_Pane"), BaseUtils.readIcon(IconPathConstants.FORBID_ICON_PATH)); - this.promptWindow.add(promptButton); } - private void promptUser(int x, int y, XLayoutContainer container) { - if (!selectionModel.getSelection().getSelectedCreator().canEnterIntoAdaptPane() && container.acceptType(XWFitLayout.class)) { - promptWidgetForbidEnter(x, y, container); - } else { - cancelPromptWidgetForbidEnter(); - } - } - - private void promptWidgetForbidEnter(int x, int y, XLayoutContainer container) { - container.setBorder(BorderFactory.createLineBorder(Color.RED, Constants.LINE_MEDIUM)); - int screenX = (int) designer.getArea().getLocationOnScreen().getX(); - int screenY = (int) designer.getArea().getLocationOnScreen().getY(); - this.promptWindow.setSize(promptWindow.getPreferredSize()); - this.promptWindow.setPreferredSize(promptWindow.getPreferredSize()); - promptWindow.setLocation(screenX + x + GAP, screenY + y + GAP); - promptWindow.setVisible(true); - } - - private void cancelPromptWidgetForbidEnter() { - designer.getRootComponent().setBorder(BorderFactory.createLineBorder(XCreatorConstants.LAYOUT_SEP_COLOR, Constants.LINE_THIN)); - promptWindow.setVisible(false); - } - - /** * 按下 * @@ -181,18 +142,14 @@ public class EditingMouseListener extends MouseInputAdapter { } if (dir == Location.outer) { - if (designer.isDrawLineMode()) { - designer.updateDrawLineMode(e); + if (selectionModel.hasSelectionComponent() + && selectionModel.getSelection().getRelativeBounds().contains( + designer.getHorizontalScaleValue() + e.getX(), + designer.getVerticalScaleValue() + e.getY())) { + lastPressEvent = e; + lastXCreator = selectionModel.getSelection().getSelectedCreator(); } else { - if (selectionModel.hasSelectionComponent() - && selectionModel.getSelection().getRelativeBounds().contains( - designer.getHorizontalScaleValue() + e.getX(), - designer.getVerticalScaleValue() + e.getY())) { - lastPressEvent = e; - lastXCreator = selectionModel.getSelection().getSelectedCreator(); - } else { - stateModel.startSelecting(e); - } + stateModel.startSelecting(e); } } else { stateModel.startResizing(e); @@ -258,13 +215,6 @@ public class EditingMouseListener extends MouseInputAdapter { private void mouseDraggingRelease(MouseEvent e) { // 当前鼠标所在的组件 XCreator hoveredComponent = designer.getComponentAt(e.getX(), e.getY()); - if (designer.isWidgetsIntersect() && dragBackupBounds != null && hoveredComponent != null) { - XCreator selectionXCreator = designer.getSelectionModel().getSelection().getSelectedCreator(); - if (selectionXCreator != null) { - selectionXCreator.setBounds(dragBackupBounds.x, dragBackupBounds.y, dragBackupBounds.width, dragBackupBounds.height); - } - } - dragBackupBounds = null; // 拉伸时鼠标拖动过快,导致所在组件获取会为空 if (hoveredComponent == null && e.getY() < 0) { // bug63538 @@ -285,7 +235,6 @@ public class EditingMouseListener extends MouseInputAdapter { selectionModel.deleteSelection(); designer.setPainter(null); } - cancelPromptWidgetForbidEnter(); } } @@ -499,61 +448,53 @@ public class EditingMouseListener extends MouseInputAdapter { if (DesignerMode.isAuthorityEditing()) { return; } - boolean shiftSelecting = e.isShiftDown(); - boolean ctrlSelecting = InputEventBaseOnOS.isControlDown(e); - int currentCursorType = this.designer.getCursor().getType(); - boolean shiftResizing = e.isShiftDown() && ( Cursor.SW_RESIZE_CURSOR <= currentCursorType && currentCursorType <= Cursor.E_RESIZE_CURSOR); - if ((shiftSelecting || ctrlSelecting) && !shiftResizing && !stateModel.isSelecting()) { + if (SwingUtilities.isRightMouseButton(e)) { + return; + } + + if (isMultiKeySelectingDrag(e)) { stateModel.startSelecting(e); } - // 如果当前是左键拖拽状态,拖拽组件 - if (stateModel.dragable()) { - if (SwingUtilities.isRightMouseButton(e)) { - return; - } else { - stateModel.dragging(e); - // 获取e所在的焦点组件 - XCreator hotspot = designer.getComponentAt(e.getX(), e.getY()); - if (dragBackupBounds == null) { - XCreator selectingXCreator = designer.getSelectionModel().getSelection().getSelectedCreator(); - if (selectingXCreator != null) { - dragBackupBounds = new Rectangle(selectingXCreator.getX(), selectingXCreator.getY(), selectingXCreator.getWidth(), selectingXCreator.getHeight()); - } - } - // 拉伸时鼠标拖动过快,导致所在组件获取会为空 - if (hotspot == null) { - return; - } - // 获取焦点组件所在的焦点容器 - XLayoutContainer container = XCreatorUtils.getHotspotContainer(hotspot); - //提示组件是否可以拖入 - promptUser(e.getX(), e.getY(), container); - } - } else if (designer.isDrawLineMode()) { - if (stateModel.prepareForDrawLining()) { - stateModel.drawLine(e); - } - } else if (stateModel.isSelecting() && (selectionModel.getHotspotBounds() != null)) { - // 如果是拖拽选择区域状态,则更新选择区域 + + if (isSelectionDrag()) { stateModel.changeSelection(e); - } else { - if ((lastPressEvent == null) || (lastXCreator == null)) { - return; - } - if (e.getPoint().distance(lastPressEvent.getPoint()) > minDragSize) { - //参数面板和自适应布局不支持拖拽 - if (lastXCreator.isSupportDrag()) { - designer.startDraggingComponent(lastXCreator, lastPressEvent, e.getX(), e.getY()); - } - e.consume(); - lastPressEvent = null; - } + return; + } + + // 调整大小这边单独提出来,不跟后面拖组件混在一起,实在不好管理 + if (stateModel.isDraggingSize()) { + stateModel.dragging(e); + return; } + + designer.startDraggingFormWidget(lastXCreator, lastPressEvent, e); e.translatePoint(oldX - e.getX(), oldY - e.getY()); designer.repaint(); } + /** + * 当前拖拽是否是正在shift或者control拖拽一个选择框 + * @param e + * @return + */ + private boolean isMultiKeySelectingDrag(MouseEvent e) { + boolean shiftSelecting = e.isShiftDown(); + boolean ctrlSelecting = InputEventBaseOnOS.isControlDown(e); + int currentCursorType = this.designer.getCursor().getType(); + boolean shiftResizing = e.isShiftDown() && ( Cursor.SW_RESIZE_CURSOR <= currentCursorType && currentCursorType <= Cursor.E_RESIZE_CURSOR); + return (shiftSelecting || ctrlSelecting) && !shiftResizing && !stateModel.isSelecting(); + } + + /** + * 是否正在拖拽选择框 + * + * @return + */ + private boolean isSelectionDrag() { + return stateModel.isSelecting() && selectionModel.getHotspotBounds() != null; + } + //当前编辑的组件是在布局中,鼠标点击布局外部,需要一次性将布局及其父布局都置为不可编辑 private void setTopLayoutUnEditable(XLayoutContainer clickedTopLayout, XLayoutContainer clickingTopLayout) { //双击的前后点击click为相同对象,过滤掉 @@ -718,7 +659,6 @@ public class EditingMouseListener extends MouseInputAdapter { if (designer.getCursor().getType() != Cursor.DEFAULT_CURSOR && !(e.isShiftDown() || InputEventBaseOnOS.isControlDown(e))) { designer.setCursor(Cursor.getDefaultCursor()); } - cancelPromptWidgetForbidEnter(); e.translatePoint(oldX - e.getX(), oldY - e.getY()); } 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 5eb354c6cb..aa58d713e5 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 @@ -1,40 +1,24 @@ package com.fr.design.mainframe; import com.fr.base.BaseUtils; -import com.fr.base.chart.BaseChartCollection; -import com.fr.chart.chartattr.ChartCollection; -import com.fr.chartx.attr.ChartProvider; -import com.fr.design.DesignModelAdapter; -import com.fr.design.data.DesignTableDataManager; -import com.fr.design.data.datapane.TableDataTreePane; import com.fr.design.designer.beans.AdapterBus; import com.fr.design.designer.beans.HoverPainter; import com.fr.design.designer.beans.Painter; -import com.fr.design.designer.beans.events.DesignerEvent; -import com.fr.design.designer.beans.models.AddingModel; +import com.fr.design.designer.beans.events.AddingWidgetListener; +import com.fr.design.designer.beans.models.DraggingModel; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XCreatorUtils; import com.fr.design.designer.creator.XLayoutContainer; -import com.fr.design.designer.creator.XWAbsoluteLayout; import com.fr.design.designer.creator.XWFitLayout; import com.fr.design.designer.creator.XWParameterLayout; import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.form.util.XCreatorConstants; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.icon.IconPathConstants; -import com.fr.design.mainframe.chart.info.ChartInfoCollector; -import com.fr.design.mod.bean.ChangeItem; -import com.fr.design.mod.bean.ContentChangeItem; -import com.fr.design.mod.event.TableDataModifyEvent; import com.fr.design.utils.ComponentUtils; -import com.fr.event.EventDispatcher; -import com.fr.form.share.SharableWidgetProvider; -import com.fr.form.share.ShareLoader; -import com.fr.form.share.editor.SharableEditorProvider; -import com.fr.form.ui.Widget; import com.fr.log.FineLoggerFactory; import com.fr.stable.Constants; -import com.fr.stable.StringUtils; import javax.swing.BorderFactory; import javax.swing.JOptionPane; @@ -45,15 +29,10 @@ import java.awt.Color; import java.awt.Component; import java.awt.Point; import java.awt.Rectangle; -import java.awt.Toolkit; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; /** * 添加模式下鼠标事件处理器。 @@ -65,124 +44,56 @@ public class FormCreatorDropTarget extends DropTarget { * 当前鼠标的设计组件 */ private Component current; - /** - * 当前添加模式对应的model - */ - private AddingModel addingModel; private static final int GAP = 30; private TabDragInner tabDragInner; - + private XCreator creator; private JWindow promptWindow = new JWindow(); private UIButton promptButton = new UIButton("", BaseUtils.readIcon(IconPathConstants.FORBID_ICON_PATH)); - public FormCreatorDropTarget(FormDesigner designer) { + public FormCreatorDropTarget(FormDesigner designer, XCreator creator) { this.designer = designer; - this.addingModel = designer.getAddingModel(); + this.creator = creator; this.promptWindow.add(promptButton); this.tabDragInner = new TabDragInner(designer); + initAddingListener(); } - public void adding(int x, int y) { - // 当前鼠标所在的组件 - XCreator hoveredComponent = designer.getComponentAt(x, y); - // 获取该组件所在的焦点容器 - XLayoutContainer container = XCreatorUtils.getHotspotContainer(hoveredComponent); - boolean success = false; - if (container != null) { - //XWCardTagLayout 切换添加状态到普通状态 - container.stopAddingState(designer); - - // 如果是容器,则调用其acceptComponent接受组件 - AddingModel model = designer.getAddingModel(); - - boolean chartEnter2Para = !addingModel.getXCreator().canEnterIntoParaPane() && container.acceptType(XWParameterLayout.class); - boolean formSubmit2Adapt = !addingModel.getXCreator().canEnterIntoAdaptPane() && container.acceptType(XWFitLayout.class); - - if (model != null && !chartEnter2Para && !formSubmit2Adapt) { - tabDragInner.tryDragIn(); - success = model.add2Container(designer, container, x, y); + private void initAddingListener() { + designer.getAddingWidgetListeners().addListener(new AddingWidgetListener() { + @Override + public void beforeAdded() { + tabDragInner.setTabEditable(); } - cancelPromptWidgetForbidEnter(); - } - if (success) { - tabDragInner.reset(); - // 如果添加成功,则触发相应事件 - XCreator xCreator = container.acceptType(XWParameterLayout.class) ? designer.getParaComponent() : designer.getRootComponent(); - //SetSelection时要确保选中的是最顶层的布局 - //tab布局添加的时候是初始化了XWCardLayout,实际上最顶层的布局是XWCardMainBorderLayout - XCreator addingXCreator = addingModel.getXCreator(); - Widget widget = (addingXCreator.getBackupParent() != null && addingXCreator.getTopLayout() != null) ? (addingXCreator.getTopLayout().toData()) : addingXCreator.toData(); - //图表埋点 - dealChartBuryingPoint(widget); - if (addingXCreator.isShared()) { - if (container.acceptType(XWAbsoluteLayout.class)) { - // 绝对布局中新添加的共享组件默认锁定尺寸比例 - Rectangle bounds = new Rectangle(addingXCreator.getBounds()); - Widget addingWidget = addingXCreator.toData(); - if (addingWidget != null && bounds.width > 0 && bounds.height > 0) { - addingXCreator.toData().setAspectRatioLocked(true); - addingXCreator.toData().setAspectRatioBackup(1.0 * bounds.width / bounds.height); - } - } - String shareId = addingXCreator.getShareId(); - SharableEditorProvider sharableEditor = ShareLoader.getLoader().getSharedElCaseEditorById(shareId); - SharableWidgetProvider bindInfo = ShareLoader.getLoader().getElCaseBindInfoById(shareId); - Map tdNameMap = Collections.emptyMap(); - if (sharableEditor != null && bindInfo != null) { - tdNameMap = TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).addTableData(bindInfo.getName(), sharableEditor.getTableDataSource(), true); - //合并数据集之后,可能会有数据集名称变化,做一下联动 - //共享的组件拿的时候都是克隆的,这边改拖拽中克隆的对象而非新克隆对象,上面这个新克隆的对象只是为了拿数据集 - Map map = new HashMap<>(); - for (Map.Entry entry : tdNameMap.entrySet()) { - designer.getTarget().renameTableData(widget, entry.getKey(), entry.getValue()); - map.put(entry.getKey(), entry.getValue()); - } - if (!map.isEmpty()) { - DesignTableDataManager.fireDSChanged(map); - } + @Override + public void afterAdded(boolean addResult) { + if (addResult) { + tabDragInner.reset(); + } else { + undoWhenAddingFailed(); } - EventDispatcher.fire(TableDataModifyEvent.INSTANCE, new ContentChangeItem(tdNameMap, widget, ChangeItem.TABLE_DATA_NAME)); } - - designer.getSelectionModel().setSelectedCreators( - FormSelectionUtils.rebuildSelection(xCreator, new Widget[]{widget})); - if (!addingModel.isAddedIllegal()) { - designer.getEditListenerTable().fireCreatorModified(addingModel.getXCreator(), DesignerEvent.CREATOR_ADDED); - } - tabDragInner.tryDragIn(); - } else { - Toolkit.getDefaultToolkit().beep(); - // 拖入失败 取消选中 - XCreator creator = addingModel.getXCreator(); - if (creator != null) { - creator.setSelected(false); - } - } - // 取消提示 - designer.setPainter(null); - // 切换添加状态到普通状态 - designer.stopAddingState(); + }); } private void entering(int x, int y) { // 将要添加的组件图标移动到鼠标下的位置 - addingModel.moveTo(x, y); + designer.updateDraggingPosition(x, y); designer.repaint(); } private void exiting() { cancelPromptWidgetForbidEnter(); // 隐藏组件图标 - addingModel.reset(); + designer.resetDraggingPosition(); designer.setPainter(null); designer.repaint(); } private void hovering(int x, int y) { // 当前位置移植鼠标e所在的位置 - addingModel.moveTo(x, y); + designer.updateDraggingPosition(x, y); // 获取e所在的焦点组件 XCreator hotspot = designer.getComponentAt(x, y); // 获取焦点组件所在的焦点容器 @@ -235,15 +146,15 @@ public class FormCreatorDropTarget extends DropTarget { rect.y -= designer.getArea().getVerticalValue(); painter.setRenderingBounds(rect); painter.setHotspot(new Point(x, y)); - painter.setCreator(addingModel.getXCreator()); + painter.setCreator(creator); } } private void promptUser(int x, int y, XLayoutContainer container) { - if (!addingModel.getXCreator().canEnterIntoParaPane() && container.acceptType(XWParameterLayout.class)) { + if (!creator.canEnterIntoParaPane() && container.acceptType(XWParameterLayout.class)) { promptButton.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Forbid_Drag_Into_Para_Pane")); promptWidgetForbidEnter(x, y, container); - } else if (!addingModel.getXCreator().canEnterIntoAdaptPane() && container.acceptType(XWFitLayout.class)) { + } else if (!creator.canEnterIntoAdaptPane() && container.acceptType(XWFitLayout.class)) { promptButton.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Forbid_Drag_Into_Adapt_Pane")); promptWidgetForbidEnter(x, y, container); } else { @@ -289,8 +200,15 @@ public class FormCreatorDropTarget extends DropTarget { int x = designer.getRelativeX(loc.x); int y = designer.getRelativeY(loc.y); hovering(x, y); - tabDragInner.canDragIn(designer.getComponentAt(x, y), x, y); - designer.draggingComponent(x, y); + tabDragInner.setTabDragInAble(designer.getComponentAt(x, y), x, y); + + XLayoutContainer parent = XCreatorUtils.getParentXLayoutContainer(creator); + if (parent!= null && parent.getLayoutAdapter()!=null){ + parent.getLayoutAdapter().dragOver(creator, designer.getSelectionModel(), x, y); + } + + // 触发状态添加模式事件 + designer.repaint(); } /** @@ -320,12 +238,11 @@ public class FormCreatorDropTarget extends DropTarget { */ @Override public synchronized void drop(DropTargetDropEvent dtde) { - try { dropXCreator(dtde); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); - if (addingModel.getXCreator().isShared()) { + if (creator.isShared()) { FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share_Drag_Component_Error_Info"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Error"), @@ -335,40 +252,46 @@ public class FormCreatorDropTarget extends DropTarget { } dtde.rejectDrop(); } + designer.stopDragging(); + designer.clearDropTarget(); } private void dropXCreator(DropTargetDropEvent dtde) { - Point loc = dtde.getLocation(); - this.adding(designer.getRelativeX(loc.x), designer.getRelativeY(loc.y)); - // 放到事件末尾执行 - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - // 拖拽释放后标记未选中 - for (XCreator xCreator : designer.getSelectionModel().getSelection().getSelectedCreators()) { - xCreator.setSelected(true); - } - } - }); - //针对在表单中拖入一个控件直接ctrl+s无反应 - designer.requestFocus(); - } + DraggingModel model = designer.getDraggingModel(); - private void dealChartBuryingPoint(Widget widget) { - List chartCollections = widget.getChartCollections(); - for (BaseChartCollection baseChartCollection : chartCollections) { - ChartCollection chartCollection = (ChartCollection) baseChartCollection; - for (int i = 0, size = chartCollection.getChartCount(); i < size; i++) { - ChartProvider chart = chartCollection.getChart(i, ChartProvider.class); - //是否是共享的复用组件 - boolean isReuse = StringUtils.isNotEmpty(this.addingModel.getXCreator().getShareId()); - ChartInfoCollector.getInstance().collection(chart, null, isReuse); - ChartInfoCollector.getInstance().checkTestChart(chart); + if (model != null) { + cancelPromptWidgetForbidEnter(); + Point loc = dtde.getLocation(); + int x = designer.getRelativeX(loc.x); + int y = designer.getRelativeY(loc.y); + if (model.isDragNewWidget()) { + designer.addNewWidget(creator, x, y); + } else { + designer.changeWidgetPlace(creator, x, y); } + // 放到事件末尾执行 + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + // 拖拽释放后标记未选中 + for (XCreator xCreator : designer.getSelectionModel().getSelection().getSelectedCreators()) { + xCreator.setSelected(true); + } + } + }); + //针对在表单中拖入一个控件直接ctrl+s无反应 + designer.requestFocus(); } } public TabDragInner getTabDragInner() { return this.tabDragInner; } + + private void undoWhenAddingFailed() { + JTemplate jt = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); + if (jt != null) { + jt.undoToCurrent(); + } + } } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java index adc59581ac..ef1177ece9 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java @@ -1,14 +1,21 @@ package com.fr.design.mainframe; import com.fr.base.Parameter; +import com.fr.base.chart.BaseChartCollection; import com.fr.base.vcs.DesignerMode; +import com.fr.chart.chartattr.ChartCollection; +import com.fr.chartx.attr.ChartProvider; import com.fr.design.DesignModelAdapter; import com.fr.design.DesignState; import com.fr.design.ExtraDesignClassManager; import com.fr.design.actions.UpdateAction; import com.fr.design.base.mode.DesignModeContext; +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.datapane.TableDataTreePane; import com.fr.design.designer.TargetComponent; import com.fr.design.designer.beans.AdapterBus; +import com.fr.design.designer.beans.ComponentAdapter; +import com.fr.design.designer.beans.LayoutAdapter; import com.fr.design.designer.beans.Painter; import com.fr.design.designer.beans.actions.CopyAction; import com.fr.design.designer.beans.actions.CutAction; @@ -18,9 +25,11 @@ import com.fr.design.designer.beans.actions.MoveToBottomAction; import com.fr.design.designer.beans.actions.MoveToTopAction; import com.fr.design.designer.beans.actions.MoveUpAction; import com.fr.design.designer.beans.actions.PasteAction; +import com.fr.design.designer.beans.adapters.component.CompositeComponentAdapter; import com.fr.design.designer.beans.adapters.layout.DefaultDesignerBaseOperate; -import com.fr.design.designer.beans.adapters.layout.FRParameterLayoutAdapter; import com.fr.design.designer.beans.adapters.layout.DesignerBaseOperate; +import com.fr.design.designer.beans.adapters.layout.FRParameterLayoutAdapter; +import com.fr.design.designer.beans.events.AddingWidgetListenerTable; import com.fr.design.designer.beans.events.CreatorEventListenerTable; import com.fr.design.designer.beans.events.DesignerEditListener; import com.fr.design.designer.beans.events.DesignerEvent; @@ -28,6 +37,8 @@ import com.fr.design.designer.beans.location.Direction; import com.fr.design.designer.beans.location.Location; import com.fr.design.designer.beans.location.RootResizeDirection; import com.fr.design.designer.beans.models.AddingModel; +import com.fr.design.designer.beans.models.DraggingModel; +import com.fr.design.designer.beans.models.ModelUtil; import com.fr.design.designer.beans.models.SelectionModel; import com.fr.design.designer.beans.models.StateModel; import com.fr.design.designer.creator.XChartEditor; @@ -37,6 +48,7 @@ import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.creator.XWAbsoluteBodyLayout; import com.fr.design.designer.creator.XWAbsoluteLayout; import com.fr.design.designer.creator.XWBorderLayout; +import com.fr.design.designer.creator.XWFitLayout; import com.fr.design.designer.creator.XWParameterLayout; import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout; import com.fr.design.designer.properties.FormWidgetAuthorityEditPane; @@ -45,19 +57,27 @@ import com.fr.design.event.DesignerOpenedListener; import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.form.util.XCreatorConstants; import com.fr.design.fun.RightSelectionHandlerProvider; +import com.fr.design.mainframe.chart.info.ChartInfoCollector; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; import com.fr.design.menu.MenuDef; import com.fr.design.menu.ShortCut; import com.fr.design.menu.ToolBarDef; +import com.fr.design.mod.bean.ChangeItem; +import com.fr.design.mod.bean.ContentChangeItem; +import com.fr.design.mod.event.TableDataModifyEvent; import com.fr.design.parameter.ParaDefinitePane; import com.fr.design.parameter.ParameterPropertyPane; import com.fr.design.roleAuthority.RolesAlreadyEditedPane; import com.fr.design.utils.ComponentUtils; import com.fr.design.utils.gui.LayoutUtils; +import com.fr.event.EventDispatcher; import com.fr.form.FormElementCaseContainerProvider; import com.fr.form.FormElementCaseProvider; import com.fr.form.main.Form; import com.fr.form.parameter.FormSubmitButton; +import com.fr.form.share.SharableWidgetProvider; +import com.fr.form.share.ShareLoader; +import com.fr.form.share.editor.SharableEditorProvider; import com.fr.form.ui.EditorHolder; import com.fr.form.ui.PaddingMargin; import com.fr.form.ui.Widget; @@ -91,6 +111,7 @@ import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; +import java.awt.Toolkit; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; @@ -99,7 +120,10 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -144,6 +168,7 @@ public class FormDesigner extends TargetComponent
implements TreeSelection private transient StateModel stateModel; // 添加状态下的model,存储添加状态下的临时状态,比如要添加的组件、当前鼠标位置等等 private transient AddingModel addingModel; + private transient DraggingModel draggingModel; // 当前负责额外渲染的painter,主要目的用来渲染添加组件的位置提示,它通常由外部类设置,在 // 设计器渲染时被调用渲染这些位置提示。 private transient Painter painter; @@ -170,6 +195,8 @@ public class FormDesigner extends TargetComponent implements TreeSelection private static final int H_GAP = 105; private static final int SUBMIT_BUTTON_H_LOCATION = 270; + private AddingWidgetListenerTable addingWidgetListeners; + public FormDesigner(Form form) { this(form, null); } @@ -184,6 +211,7 @@ public class FormDesigner extends TargetComponent implements TreeSelection this.setBackground(Color.WHITE); // 初始化 edit = new CreatorEventListenerTable(); + addingWidgetListeners = new AddingWidgetListenerTable(); selectionModel = new SelectionModel(this); stateModel = new StateModel(this); desigerMode = createFormDesignerTargetMode(); @@ -201,6 +229,7 @@ public class FormDesigner extends TargetComponent implements TreeSelection populateParameterPropertyPane(); spacingLineDrawer = new FormSpacingLineDrawer(this); + clearDropTarget(); } @@ -603,6 +632,10 @@ public class FormDesigner extends TargetComponent implements TreeSelection return edit; } + public AddingWidgetListenerTable getAddingWidgetListeners() { + return addingWidgetListeners; + } + /** * 增加监听事件 * @@ -783,6 +816,35 @@ public class FormDesigner extends TargetComponent implements TreeSelection repaint(); } + /** + * 停止拖拽 + */ + public void stopDragging() { + draggingModel = null; + } + + public void clearDropTarget() { + this.setDropTarget(null); + } + + /** + * 更新拖拽model的位置 + */ + public void updateDraggingPosition(int x, int y) { + if (draggingModel != null) { + draggingModel.moveTo(x, y); + } + } + + /** + * 重置拖拽model的位置 + */ + public void resetDraggingPosition() { + if (draggingModel != null) { + draggingModel.reset(); + } + } + /** * 设置其UI类为DesignerUI,负责渲染 */ @@ -1109,8 +1171,8 @@ public class FormDesigner extends TargetComponent implements TreeSelection return addingModel; } - public void setAddingModel(AddingModel addingModel) { - this.addingModel = addingModel; + public DraggingModel getDraggingModel() { + return draggingModel; } public XCreator getComponentAt(MouseEvent e) { @@ -1179,50 +1241,84 @@ public class FormDesigner extends TargetComponent implements TreeSelection } /** - * 拖拽准备 + * 拖入新的组件 * - * @param xCreator 组件 + * @param xCreator + * @param startDragEvent + * @param currentDragEvent */ - public void startDraggingBean(XCreator xCreator) { - // 根据所选择的组件的BeanInfo生成相应的AddingModel - // AddingModel和StateModel不一样,适合当前选择的组件相关的 - addingModel = new AddingModel(this, xCreator); - this.setDropTarget(new FormCreatorDropTarget(this)); - // 触发状态添加模式事件 + public void startDraggingNewWidget(XCreator xCreator, MouseEvent startDragEvent, MouseEvent currentDragEvent) { + if (currentDragEvent == null || this.getDropTarget() != null) { + return; + } + + draggingModel = new DraggingModel() + .designer(this) + .creator(xCreator) + .startDragEvent(startDragEvent) + .currentDragEvent(currentDragEvent) + .dragNewWidget(true); + this.setDropTarget(new FormCreatorDropTarget(this, xCreator)); repaint(); } /** - * 拖拽时相关处理 + * 拖拽表单上的组件 * - * @param xCreator 组件 - * @param lastPressEvent 鼠标事件 - * @param x 坐标x - * @param y 坐标y - */ - public void startDraggingComponent(XCreator xCreator, MouseEvent lastPressEvent, int x, int y) { - // 根据所选择的组件的BeanInfo生成相应的AddingModel - // AddingModel和StateModel不一样,适合当前选择的组件相关的 - this.addingModel = new AddingModel(xCreator, x, y); - TransferHandler handler = new DesignerTransferHandler(this, addingModel); - setTransferHandler(handler); - handler.exportAsDrag(this, lastPressEvent, TransferHandler.COPY); - XLayoutContainer parent = XCreatorUtils.getParentXLayoutContainer(xCreator); - parent.getLayoutAdapter().dragStart(xCreator, selectionModel); - this.setDropTarget(new FormCreatorDropTarget(this)); - // 触发状态添加模式事件 + * @param xCreator + * @param startDragEvent + * @param currentDragEvent + */ + public void startDraggingFormWidget(XCreator xCreator, MouseEvent startDragEvent, MouseEvent currentDragEvent) { + if (currentDragEvent == null || this.getDropTarget() != null) { + return; + } + draggingModel = new DraggingModel() + .designer(this) + .creator(xCreator) + .startDragEvent(startDragEvent) + .currentDragEvent(currentDragEvent) + .dragNewWidget(false); + XLayoutContainer container = this.getDraggingHotspotLayout(); + LayoutAdapter adapter = container.getLayoutAdapter(); + adapter.dragging(this.getDraggingModel()); repaint(); } - public void draggingComponent(int x, int y){ - XCreator xCreator = this.addingModel.getXCreator(); + /** + * 绑定transferHandler,貌似这边用的还是低级的DND方式绑定的鼠标手势,高级的可参考ToolBarButton那边,"rootComponent"常量是 + * 从原来的DesignerTransferHandler里面直接搬来的,目前意义还不明确 + * + * @param e + */ + public void bindTransferHandler(MouseEvent e) { + TransferHandler handler = new TransferHandler("rootComponent"); + this.setTransferHandler(handler); + handler.exportAsDrag(this, e, TransferHandler.COPY); + } + + /** + * 触发父组件布局的dragStart事件,目前只在非固定布局下有用,用来删除占位块 + * + * @param xCreator + */ + public void fireParentLayoutDragStart(XCreator xCreator) { XLayoutContainer parent = XCreatorUtils.getParentXLayoutContainer(xCreator); - if (parent!= null && parent.getLayoutAdapter()!=null){ - parent.getLayoutAdapter().dragOver(xCreator, selectionModel, x, y); + if (parent != null) { + parent.getLayoutAdapter().dragStart(xCreator, selectionModel); } + } - // 触发状态添加模式事件 - repaint(); + /** + * 获取拖拽当前鼠标所在位置的布局 + * + * @return + */ + public XLayoutContainer getDraggingHotspotLayout() { + DraggingModel model = this.draggingModel; + MouseEvent dragEvent = model.getCurrentDragEvent(); + XCreator hotspot = this.getComponentAt(dragEvent.getX(), dragEvent.getY()); + return XCreatorUtils.getHotspotContainer(hotspot); } /** @@ -1890,4 +1986,131 @@ public class FormDesigner extends TargetComponent implements TreeSelection public FormSpacingLineDrawer getSpacingLineDrawer() { return spacingLineDrawer; } + + private void instantiateCreator(XCreator creator) { + ModelUtil.renameWidgetName(this.getTarget(), creator); + creator.addNotify(); + + ComponentAdapter adapter = new CompositeComponentAdapter(this, creator); + adapter.initialize(); + creator.putClientProperty(AdapterBus.CLIENT_PROPERTIES, adapter); + } + + public void addNewWidget(XCreator creator, int x, int y) { + instantiateCreator(creator); + addWidgetToForm(creator, x, y); + } + + public void changeWidgetPlace(XCreator creator, int x, int y) { + creator.backupCurrentSize(); + creator.backupParent(); + addWidgetToForm(creator, x, y); + } + + private void addWidgetToForm(XCreator creator, int x, int y) { + if(creator == null) { + return; + } + + addingModel = new AddingModel(creator); + // 当前鼠标所在的组件 + XCreator hoveredComponent = this.getComponentAt(x, y); + // 获取该组件所在的焦点容器 + XLayoutContainer container = XCreatorUtils.getHotspotContainer(hoveredComponent); + boolean success = false; + if (container != null) { + // 如果是容器,则调用其acceptComponent接受组件 + boolean chartEnter2Para = !addingModel.getXCreator().canEnterIntoParaPane() && container.acceptType(XWParameterLayout.class); + boolean formSubmit2Adapt = !addingModel.getXCreator().canEnterIntoAdaptPane() && container.acceptType(XWFitLayout.class); + + if (!chartEnter2Para && !formSubmit2Adapt) { + getAddingWidgetListeners().beforeAdded(); + success = container.addWidgetToContainer( + creator, + x + this.getHorizontalScaleValue(), + y + this.getVerticalScaleValue() + ); + } + getAddingWidgetListeners().afterAdded(success); + defaultAfterWidgetAdded(success, container); + } + + // 取消提示 + this.setPainter(null); + // 切换添加状态到普通状态 + this.stopAddingState(); + getAddingWidgetListeners().clearListeners(); + } + + private void dealChartBuryingPoint(Widget widget) { + List chartCollections = widget.getChartCollections(); + for (BaseChartCollection baseChartCollection : chartCollections) { + ChartCollection chartCollection = (ChartCollection) baseChartCollection; + for (int i = 0, size = chartCollection.getChartCount(); i < size; i++) { + ChartProvider chart = chartCollection.getChart(i, ChartProvider.class); + //是否是共享的复用组件 + boolean isReuse = StringUtils.isNotEmpty(this.addingModel.getXCreator().getShareId()); + ChartInfoCollector.getInstance().collection(chart, null, isReuse); + ChartInfoCollector.getInstance().checkTestChart(chart); + } + } + } + + + + private void defaultAfterWidgetAdded(boolean addResult, XLayoutContainer container) { + if (addResult) { + // 如果添加成功,则触发相应事件 + XCreator xCreator = container.acceptType(XWParameterLayout.class) ? this.getParaComponent() : this.getRootComponent(); + //SetSelection时要确保选中的是最顶层的布局 + //tab布局添加的时候是初始化了XWCardLayout,实际上最顶层的布局是XWCardMainBorderLayout + XCreator addingXCreator = addingModel.getXCreator(); + Widget widget = (addingXCreator.getBackupParent() != null && addingXCreator.getTopLayout() != null) ? (addingXCreator.getTopLayout().toData()) : addingXCreator.toData(); + //图表埋点 + dealChartBuryingPoint(widget); + if (addingXCreator.isShared()) { + if (container.acceptType(XWAbsoluteLayout.class)) { + // 绝对布局中新添加的共享组件默认锁定尺寸比例 + Rectangle bounds = new Rectangle(addingXCreator.getBounds()); + Widget addingWidget = addingXCreator.toData(); + if (addingWidget != null && bounds.width > 0 && bounds.height > 0) { + addingXCreator.toData().setAspectRatioLocked(true); + addingXCreator.toData().setAspectRatioBackup(1.0 * bounds.width / bounds.height); + } + } + + String shareId = addingXCreator.getShareId(); + SharableEditorProvider sharableEditor = ShareLoader.getLoader().getSharedElCaseEditorById(shareId); + SharableWidgetProvider bindInfo = ShareLoader.getLoader().getElCaseBindInfoById(shareId); + Map tdNameMap = Collections.emptyMap(); + if (sharableEditor != null && bindInfo != null) { + tdNameMap = TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).addTableData(bindInfo.getName(), sharableEditor.getTableDataSource(), true); + //合并数据集之后,可能会有数据集名称变化,做一下联动 + //共享的组件拿的时候都是克隆的,这边改拖拽中克隆的对象而非新克隆对象,上面这个新克隆的对象只是为了拿数据集 + Map map = new HashMap<>(); + for (Map.Entry entry : tdNameMap.entrySet()) { + this.getTarget().renameTableData(widget, entry.getKey(), entry.getValue()); + map.put(entry.getKey(), entry.getValue()); + } + if (!map.isEmpty()) { + DesignTableDataManager.fireDSChanged(map); + } + } + EventDispatcher.fire(TableDataModifyEvent.INSTANCE, new ContentChangeItem(tdNameMap, widget, ChangeItem.TABLE_DATA_NAME)); + } + + this.getSelectionModel().setSelectedCreators( + FormSelectionUtils.rebuildSelection(xCreator, new Widget[]{widget})); + if (!addingModel.isAddedIllegal()) { + this.getEditListenerTable().fireCreatorModified(addingModel.getXCreator(), DesignerEvent.CREATOR_ADDED); + } + } else { + Toolkit.getDefaultToolkit().beep(); + // 拖入失败 取消选中 + XCreator creator = addingModel.getXCreator(); + if (creator != null) { + creator.setSelected(false); + } + } + } } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java index aab1b27b72..1d641decef 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java @@ -6,10 +6,9 @@ import com.fr.base.Utils; import com.fr.base.iofile.attr.WatermarkAttr; import com.fr.base.vcs.DesignerMode; import com.fr.design.constants.UIConstants; -import com.fr.design.designer.beans.AdapterBus; -import com.fr.design.designer.beans.ComponentAdapter; +import com.fr.design.designer.beans.LayoutAdapter; import com.fr.design.designer.beans.location.Direction; -import com.fr.design.designer.beans.models.AddingModel; +import com.fr.design.designer.beans.models.DraggingModel; import com.fr.design.designer.beans.models.SelectionModel; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XLayoutContainer; @@ -117,11 +116,10 @@ public class FormDesignerUI extends ComponentUI { designer.getPainter().paint(g, designer.getArea().getHorizontalValue(), designer.getArea().getVerticalValue() + designer.getParaHeight()); } - AddingModel addingModel = designer.getAddingModel(); - - if ((addingModel != null) && (addingModel.getXCreator() != null)) { + DraggingModel draggingModel = designer.getDraggingModel(); + if (draggingModel != null && draggingModel.getCreator() != null) { // 当前正在添加的组件 - paintAddingBean(g, addingModel); + paintDraggingBean(g); } designer.getSpacingLineDrawer().draw(g); @@ -196,26 +194,24 @@ public class FormDesignerUI extends ComponentUI { } /** - * 渲染当前正在添加的组件,采用Renderer原理 + * 渲染当前正在拖拽的组件,采用Renderer原理 */ - private void paintAddingBean(Graphics g, final AddingModel addingModel) { - if (!addingModel.need2paint()) { - return; - } - XCreator bean = addingModel.getXCreator(); - int x = addingModel.getCurrentX(); - int y = addingModel.getCurrentY() ; - - int width = bean.initEditorSize().width; - int height = bean.initEditorSize().height; + private void paintDraggingBean(Graphics g) { + DraggingModel model = designer.getDraggingModel(); + XCreator bean = model.getCreator(); + int x = model.getCreatorLeftTopX(); + int y = model.getCreatorLeftTopY(); + + XLayoutContainer container = designer.getDraggingHotspotLayout(); + LayoutAdapter adapter = container.getLayoutAdapter(); + int width = adapter.getDragSize(bean).width; + int height = adapter.getDragSize(bean).height; Graphics clipg = g.create(x, y, width, height); ArrayList dbcomponents = new ArrayList(); // 禁止双缓冲行为 ComponentUtils.disableBuffer(bean, dbcomponents); - ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, bean); - // 调用ComponentAdapter的paintComponentMascot方法渲染该组件添加提示 - adapter.paintComponentMascot(clipg); + adapter.paintComponentMascot(clipg, bean); clipg.dispose(); // 恢复双缓冲 ComponentUtils.resetBuffer(dbcomponents); 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 8d2748eb39..ec3852437b 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 if (xCreator == null) { return; } - WidgetToolBarPane.getTarget().startDraggingBean(xCreator); + WidgetToolBarPane.getTarget().startDraggingNewWidget(xCreator, lastPressEvent, e); lastPressEvent = null; this.setBorder(null); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java index 38bcd99826..7b0bf57080 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/block/OnlineWidgetBlock.java @@ -13,21 +13,21 @@ import com.fr.design.login.DesignerLoginHelper; import com.fr.design.login.DesignerLoginSource; import com.fr.design.mainframe.WidgetToolBarPane; import com.fr.design.mainframe.share.collect.ComponentCollector; +import com.fr.design.mainframe.share.ui.local.LocalWidgetRepoPane; import com.fr.design.mainframe.share.ui.online.AbstractOnlineWidgetSelectPane; import com.fr.design.mainframe.share.ui.online.CarouselStateManger; -import com.fr.form.share.DefaultSharableWidget; -import com.fr.form.share.group.DefaultShareGroup; -import com.fr.design.mainframe.share.ui.local.LocalWidgetRepoPane; import com.fr.design.mainframe.share.ui.online.OnlineWidgetRepoPane; import com.fr.design.mainframe.share.util.DownloadUtils; import com.fr.design.mainframe.share.util.ShareComponentUtils; import com.fr.design.mainframe.share.util.ShareUIUtils; import com.fr.design.ui.util.UIUtil; +import com.fr.form.share.DefaultSharableWidget; +import com.fr.form.share.Group; import com.fr.form.share.SharableWidgetProvider; import com.fr.form.share.bean.OnlineShareWidget; import com.fr.form.share.constants.ShareComponentConstants; +import com.fr.form.share.group.DefaultShareGroup; import com.fr.form.share.group.DefaultShareGroupManager; -import com.fr.form.share.Group; import com.fr.form.share.utils.ShareUtils; import com.fr.form.ui.AbstractBorderStyleWidget; import com.fr.form.ui.Widget; @@ -163,6 +163,11 @@ public class OnlineWidgetBlock extends AbstractOnlineWidgetBlock { } } + @Override + public void mouseReleased(MouseEvent e) { + super.mouseReleased(e); + } + @Override public void mouseDragged(MouseEvent e) { if (!getWidget().isCompatibleWithCurrentEnv()) { @@ -200,7 +205,7 @@ public class OnlineWidgetBlock extends AbstractOnlineWidgetBlock { } else { xCreator = ShareComponentUtils.createXCreator(creatorSource, shareId, bindInfo); } - WidgetToolBarPane.getTarget().startDraggingBean(xCreator); + WidgetToolBarPane.getTarget().startDraggingNewWidget(xCreator, lastPressEvent, e); lastPressEvent = null; this.setBorder(null); } 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 b48b74e67d..52ea26bc26 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); } 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 782538f63a..69e514b408 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(); } diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteBodyLayoutDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteBodyLayoutDefinePane.java index 7998c1d0c3..5ebd84d07f 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteBodyLayoutDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteBodyLayoutDefinePane.java @@ -7,54 +7,36 @@ import com.fr.base.theme.TemplateTheme; import com.fr.design.data.DataCreatorUI; import com.fr.design.designer.IntervalConstants; import com.fr.design.designer.creator.XCreator; -import com.fr.design.designer.creator.XWFitLayout; -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.fit.common.TemplateTool; import com.fr.design.foldablepane.UIExpandablePane; -import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UIAutoChangeLineLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.style.FollowingThemePane; import com.fr.design.gui.xpane.LayoutStylePane; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.WidgetPropertyPane; import com.fr.design.mainframe.widget.accessibles.AccessibleBodyWatermarkEditor; -import com.fr.design.widget.FRWidgetFactory; -import com.fr.design.widget.ui.designer.component.WidgetBoundPane; import com.fr.form.ui.LayoutBorderStyle; 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.general.act.BorderPacker; import com.fr.report.core.ReportUtils; import javax.swing.BorderFactory; -import javax.swing.DefaultComboBoxModel; import javax.swing.JPanel; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; -import static javax.swing.JOptionPane.OK_CANCEL_OPTION; -import static javax.swing.JOptionPane.OK_OPTION; -import static javax.swing.JOptionPane.WARNING_MESSAGE; /** * Created by ibm on 2017/8/2. */ public class FRAbsoluteBodyLayoutDefinePane extends FRAbsoluteLayoutDefinePane { - private static final int MAX_LABEL_WIDTH = 80; protected FollowingThemePane themePane; private LayoutStylePane stylePane; private AccessibleBodyWatermarkEditor watermarkEditor; - private WidgetBoundPane boundPane; - - private UIComboBox layoutCombox; - private WBodyLayoutType layoutType = WBodyLayoutType.ABSOLUTE; public FRAbsoluteBodyLayoutDefinePane(XCreator xCreator) { super(xCreator); @@ -62,22 +44,9 @@ public class FRAbsoluteBodyLayoutDefinePane extends FRAbsoluteLayoutDefinePane { public void initComponent() { - initUIComboBox(); this.setLayout(FRGUIPaneFactory.createBorderLayout()); - boundPane = new WidgetBoundPane(creator); - if (!TemplateTool.isCurrentEditingNewJForm()){ - this.add(boundPane, BorderLayout.NORTH); - } JPanel panel1 = FRGUIPaneFactory.createBorderLayout_S_Pane(); this.add(panel1, BorderLayout.CENTER); - - UIExpandablePane scalePane = new UIExpandablePane( - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Area_Scaling"), - 280, 20, - createAreaScalePane() - ); - panel1.add(scalePane, BorderLayout.NORTH); - UIExpandablePane advancedPane = new UIExpandablePane( com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Advanced"), 280, 20, @@ -115,41 +84,15 @@ public class FRAbsoluteBodyLayoutDefinePane extends FRAbsoluteLayoutDefinePane { }, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W3, IntervalConstants.INTERVAL_L1); watermarkPane.setBorder(BorderFactory.createEmptyBorder(IntervalConstants.INTERVAL_L1, 0, IntervalConstants.INTERVAL_L1, 0)); advancedContentPane.add(watermarkPane, BorderLayout.CENTER); - + UIAutoChangeLineLabel tip = new UIAutoChangeLineLabel(Toolkit.i18nText("Fine-Design_Form_Body_Layout_Setting_Tip"), 216); + tip.setForeground(Color.lightGray); + advancedContentPane.add(tip, BorderLayout.SOUTH); return advancedContentPane; } - public 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_Widget_Scaling_Mode")); - Component[][] components = TemplateTool.isCurrentEditingNewJForm() ? new Component[][]{ - {layoutTypeLabel, layoutCombox} - } : new Component[][]{ - {layoutTypeLabel, layoutCombox}, - {scaleModeLabel, comboBox} - }; - JPanel contentPane = TableLayoutHelper.createGapTableLayoutPane(components, - TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, IntervalConstants.INTERVAL_L1); - - contentPane.setBorder(BorderFactory.createEmptyBorder(IntervalConstants.INTERVAL_L1, 0, IntervalConstants.INTERVAL_L1, 0)); - - JPanel containerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - containerPane.add(contentPane, BorderLayout.CENTER); - containerPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); - - return containerPane; - } - - public void initLayoutComboBox() { - Item[] items = FRLayoutTypeItems.ITEMS; - DefaultComboBoxModel model = new DefaultComboBoxModel(); - for (Item item : items) { - model.addElement(item); - } - layoutCombox = new UIComboBox(model); - layoutCombox.setSelectedIndex(1); + @Override + public void doLayout() { + super.doLayout(); } @Override @@ -158,51 +101,14 @@ public class FRAbsoluteBodyLayoutDefinePane extends FRAbsoluteLayoutDefinePane { } public void populateSubPane(WAbsoluteLayout ob) { - layoutCombox.setSelectedIndex(1); themePane.supportFollowingTheme(ob.supportThemed()); themePane.setFollowingTheme(ob.isBorderStyleFollowingTheme()); stylePane.populateBean((LayoutBorderStyle) ob.getBorderStyle()); - boundPane.populate(); watermarkEditor.setValue(ReportUtils.getWatermarkAttrFromTemplate(getCurrentIOFile())); } public WAbsoluteBodyLayout updateSubPane() { WAbsoluteBodyLayout layout = (WAbsoluteBodyLayout) creator.toData(); - boundPane.update(); - Item item = (Item) layoutCombox.getSelectedItem(); - Object value = item.getValue(); - int state = 0; - if (value instanceof Integer) { - state = (Integer) value; - } - - if (layoutType == WBodyLayoutType.ABSOLUTE) { - ((XWFitLayout) creator.getBackupParent()).toData().resetStyle(); - if (state == WBodyLayoutType.FIT.getTypeValue()) { - XWFitLayout xwFitLayout = ((XWFitLayout)creator.getBackupParent()); - int selVal = FineJOptionPane.showConfirmDialog( - DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design_Form_Layout_Switch_Tip"), - Toolkit.i18nText("Fine-Design_Basic_Alert"), - OK_CANCEL_OPTION, - WARNING_MESSAGE - ); - if(OK_OPTION == selVal){ - xwFitLayout.switch2FitBodyLayout(creator); - WFitLayout wFitLayout = xwFitLayout.toData(); - // 切换布局类型时,保留body背景样式 - if (wFitLayout != null) { - wFitLayout.setBorderStyleFollowingTheme(layout.isBorderStyleFollowingTheme()); - wFitLayout.setBorderStyle(layout.getBorderStyle()); - } - copyLayoutAttr(layout, xwFitLayout.toData()); - }else { - this.layoutCombox.setSelectedIndex(1); - } - copyLayoutAttr(layout, xwFitLayout.toData()); - xwFitLayout.refreshStylePreviewEffect(); - } - } layout.setBorderStyleFollowingTheme(themePane.isFollowingTheme()); layout.setBorderStyle(stylePane.updateBean()); updateWatermark(); diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteLayoutDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteLayoutDefinePane.java index 5f2db52272..d1755dc830 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteLayoutDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/layout/FRAbsoluteLayoutDefinePane.java @@ -1,30 +1,15 @@ package com.fr.design.widget.ui.designer.layout; import com.fr.design.data.DataCreatorUI; -import com.fr.design.designer.IntervalConstants; import com.fr.design.designer.creator.XCreator; -import com.fr.design.designer.properties.items.FRAbsoluteConstraintsItems; -import com.fr.design.designer.properties.items.Item; -import com.fr.design.fit.common.TemplateTool; -import com.fr.design.foldablepane.UIExpandablePane; -import com.fr.design.gui.icombobox.UIComboBox; -import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayout; -import com.fr.design.layout.TableLayoutHelper; import com.fr.form.ui.container.WAbsoluteLayout; -import javax.swing.BorderFactory; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Component; /** * Created by ibm on 2017/8/2. */ public class FRAbsoluteLayoutDefinePane extends AbstractFRLayoutDefinePane { - 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 { 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(); 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 8a3b2ded4d..dd7d3608c8 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 cd454660df..9549a3a7e8 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/mainframe/cell/settingpane/CellStylePane.java b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellStylePane.java index ec3c1bd05c..3bdd034c68 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellStylePane.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellStylePane.java @@ -11,7 +11,6 @@ import com.fr.design.mainframe.theme.utils.DefaultThemedTemplateCellElementCase; import com.fr.design.style.BorderUtils; import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.report.cell.DefaultTemplateCellElement; import com.fr.report.cell.TemplateCellElement; import com.fr.report.elementcase.TemplateElementCase; @@ -20,7 +19,7 @@ import javax.swing.JPanel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.BorderLayout; -import java.awt.Rectangle; +import java.text.Format; /** * @author zhou @@ -118,7 +117,10 @@ public class CellStylePane extends AbstractCellAttrPane { AdjustWorkBookDefaultStyleUtils.adjustCellElement(cellElement); elementCase.addCellElement(cellElement); } + Format format = cellElement.getStyle().getFormat(); Style style = stylePane.updateBean(); + // 格式不能通过样式面板中的配置项修改,因此需要保留 + style = style.deriveFormat(format); cellElement.setStyle(style); } }); diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java index 39c6b55742..bb21208740 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/GuideCreateUtils.java @@ -1,6 +1,5 @@ package com.fr.design.mainframe.guide.creator; -import com.fr.design.designer.beans.models.AddingModel; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.dialog.FineJOptionPane; @@ -10,7 +9,6 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.login.DesignerLoginHelper; import com.fr.design.login.DesignerLoginSource; import com.fr.design.mainframe.DesignerContext; -import com.fr.design.mainframe.FormCreatorDropTarget; import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.JForm; import com.fr.design.mainframe.guide.base.GuideManager; @@ -127,24 +125,17 @@ public class GuideCreateUtils { return null; } - public static void addXCreatorToXLayoutContainer(XCreator xCreator, XLayoutContainer xLayoutContainer, boolean isDragComponent) { + public static void addXCreatorToXLayoutContainer(XCreator xCreator, XLayoutContainer xLayoutContainer, boolean dragNewComponent) { if (xCreator == null) { return; } FormDesigner designer = GuideCreateUtils.getFormDesigner(); designer.getSelectionModel().selectACreator(xLayoutContainer); - - if (isDragComponent) { - designer.setAddingModel(new AddingModel(xCreator, 0,0)); - designer.setDropTarget(new FormCreatorDropTarget(designer)); - designer.repaint(); + if (dragNewComponent) { + designer.addNewWidget(xCreator, xLayoutContainer.getX(), xLayoutContainer.getY()); } else { - designer.startDraggingBean(xCreator); + designer.changeWidgetPlace(xCreator, xLayoutContainer.getX(), xLayoutContainer.getY()); } - - FormCreatorDropTarget dropTarget = (FormCreatorDropTarget) designer.getDropTarget(); - dropTarget.adding(xLayoutContainer.getX(), xLayoutContainer.getY()); - designer.getSelectionModel().selectACreator(xCreator); } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/ChangeLayoutComponentGuide.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/ChangeLayoutComponentGuide.java index ae7fb81387..331841fc92 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/ChangeLayoutComponentGuide.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/ChangeLayoutComponentGuide.java @@ -136,8 +136,8 @@ public class ChangeLayoutComponentGuide { formDesigner.getSelectionModel().removeCreator(from, from.getWidth(), from.getHeight()); formDesigner.getSelectionModel().removeCreator(to, to.getWidth(),to.getHeight()); - GuideCreateUtils.addXCreatorToXLayoutContainer(from, (XLayoutContainer) GuideCreateUtils.getXCreatorFormDesigner("box1"), true); - GuideCreateUtils.addXCreatorToXLayoutContainer(to, (XLayoutContainer) GuideCreateUtils.getXCreatorFormDesigner("box0"), true); + GuideCreateUtils.addXCreatorToXLayoutContainer(from, (XLayoutContainer) GuideCreateUtils.getXCreatorFormDesigner("box1"), false); + GuideCreateUtils.addXCreatorToXLayoutContainer(to, (XLayoutContainer) GuideCreateUtils.getXCreatorFormDesigner("box0"), false); return true; } }); diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java index b4f5647c66..38539b54d2 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java @@ -246,7 +246,7 @@ public class UseLayoutAndComponentGuide { LocalWidgetBlock block = getLocalWidgetBlock(shareID); XCreator xCreator = block.transformXCreator(block); XOccupiedLayout xOccupiedLayout = getXOccupiedLayout(name); - GuideCreateUtils.addXCreatorToXLayoutContainer(xCreator, xOccupiedLayout, false); + GuideCreateUtils.addXCreatorToXLayoutContainer(xCreator, xOccupiedLayout, true); return true; } }); 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 0000000000..788f1a57cb --- /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 0000000000..0c202fe0e2 --- /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 0000000000..b5175e7fa9 --- /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 0000000000..62cb37e91f --- /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 0000000000..4b14dc6929 --- /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 0000000000..5bfc20eeae --- /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 0000000000..db6f574bd6 --- /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 0000000000..a5fec3f473 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/common/AbstractSortItemPane.java @@ -0,0 +1,157 @@ +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); + } + triggerItemChanged(sortBasisUiComboBox.getSelectedIndex()); + } + } + }); + 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); + } + } + + void triggerItemChanged(Integer index) { + currentSortExpressionPane = sortExpressionPanes.get(index); + refreshCurrentSortExpressionPane(); + } + + 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 0000000000..6491d04a8e --- /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 0000000000..653ce86c8c --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/common/SortColumnRowPane.java @@ -0,0 +1,279 @@ +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); + if (headerTemplateCellElement != null) { + 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 0000000000..6de6636f4c --- /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 0000000000..1381b92cf2 --- /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 0000000000..c65657836b --- /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 0000000000..3a5b9641fb --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/expressionpane/CustomSequencePane.java @@ -0,0 +1,70 @@ +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(); + triggerOk(CustomSequenceSortExpression.customSequenceToString(customSequence, ","), + CustomSequenceSortExpression.isReferenceCustomSequence(customSequence)); + } + }, new Dimension(700, 400)).setVisible(true); + } + }; + button.addMouseListener(mouseAdapter); + textField.addMouseListener(mouseAdapter); + this.add(textField); + this.add(button); + } + + private void triggerOk(String customSequence, Boolean referenceCustomSequence) { + textField.setText(customSequence); + } + + 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 0000000000..69dac2a2ab --- /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 0000000000..3785a7e973 --- /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 0000000000..69af8464cb --- /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 0000000000..4f4617053b --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java @@ -0,0 +1,263 @@ +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 showHeaderArea; + + 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 ((showHeaderArea ? 1 : 0) != uiComboBox.getSelectedIndex()) { + triggerItemChanged(uiComboBox.getSelectedIndex()); + } + } + }); + uiComboBox.setEnabled(false); + } + + void triggerItemChanged(Integer index) { + setSortColumnRowPaneShow(index == 1); + if (index == 1) { + ColumnRow columnRow = columnRowPane.updateBean(); + if (cellSelectionManager.isNotSelectables(columnRow)) { + columnRowPane.setColumnRow(ColumnRow.ERROR); + } else { + cellSelectionManager.addNotSelectables(columnRow); + } + } else { + cellSelectionManager.removeNotSelectables(columnRowPane.updateBean()); + } + } + + void setSortColumnRowPaneShow(boolean show) { + if (show) { + jLayeredPane.setLayer(columnRowPane, JLayeredPane.POPUP_LAYER); + jLayeredPane.setLayer(uiComboBox, JLayeredPane.MODAL_LAYER); + } else { + jLayeredPane.setLayer(uiComboBox, JLayeredPane.POPUP_LAYER); + jLayeredPane.setLayer(columnRowPane, JLayeredPane.MODAL_LAYER); + } + showHeaderArea = show; + 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) { + cellSelectionManager.build(); + columnRowPane.populateBean(columnRow, enabled, cellSelectionManager); + setSortColumnRowPaneShow(showHeaderArea); + uiComboBox.setSelectedIndex(showHeaderArea ? 1 : 0); + uiComboBox.setEnabled(enabled); + } + + 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 0000000000..f31c409290 --- /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 0000000000..172db28aec --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderSortRulePane.java @@ -0,0 +1,250 @@ +package com.fr.design.sort.header; + +import com.fr.base.FineColor; +import com.fr.base.svg.SVGIcon; +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.gui.ipoppane.PopupHider; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.style.color.ColorControlWindow; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.report.core.sort.header.HeaderIconBuilder; +import com.fr.report.core.sort.header.SortHeader; +import com.fr.report.core.sort.common.SortRule; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.util.ArrayList; + +public class HeaderSortRulePane extends JPanel { + IconButton ascIconButton; + IconButton desIconButton; + IconButton nosortIconButton; + UICheckBox ascUICheckBox; + UICheckBox desUICheckBox; + UICheckBox nosortUICheckBox; + Color defaultColor = new Color(33, 33, 34); + + 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(SortRule.ASC)}, + new Component[]{desUICheckBox = new UICheckBox(SortRule.DES.getDescription()), desIconButton = new IconButton(SortRule.DES)}, + new Component[]{nosortUICheckBox = new UICheckBox(SortRule.NO_SORT.getDescription()), nosortIconButton = new IconButton(SortRule.NO_SORT)}, + }; + double[] rowSize = {HeaderIconBuilder.ICON_LENGTH + 10, HeaderIconBuilder.ICON_LENGTH + 10, HeaderIconBuilder.ICON_LENGTH + 10}; + double[] columnSize = {80, HeaderIconBuilder.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 FineColor(defaultColor)); + desIconButton.refreshIconLabelColor(new FineColor(defaultColor)); + nosortIconButton.refreshIconLabelColor(new FineColor(defaultColor)); + } + + class IconButton extends JPanel implements UIObserver, PopupHider { + SortRule sortRule; + JLayeredPane jLayeredPane; + UILabel iconLabel; + FineColor fineColor = new FineColor(defaultColor); + UIObserverListener uiObserverListener; + boolean activeState; + UILabel borderUiLabel; + private ColorControlWindow colorSelector; + + IconButton(SortRule sortRule) { + this.sortRule = sortRule; + initComponents(); + } + + public boolean isActiveState() { + return activeState; + } + + public void setActiveState(boolean activeState) { + if (activeState) { + borderUiLabel.setBorder(BorderFactory.createLineBorder(Color.gray, 1)); + } else { + borderUiLabel.setBorder(null); + } + this.activeState = activeState; + } + + void initComponents() { + jLayeredPane = new JLayeredPane(); + iconLabel = getIconLabel(); + borderUiLabel = new UILabel(); + borderUiLabel.setSize(HeaderIconBuilder.ICON_LENGTH, HeaderIconBuilder.ICON_LENGTH); + borderUiLabel.setOpaque(true); + borderUiLabel.setBackground(Color.WHITE); + iconLabel.setSize(HeaderIconBuilder.ICON_LENGTH, HeaderIconBuilder.ICON_LENGTH); + iconLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (activeState) { + showPopupMenu(); + } + } + }); + jLayeredPane.setPreferredSize(new Dimension(HeaderIconBuilder.ICON_LENGTH, HeaderIconBuilder.ICON_LENGTH)); + jLayeredPane.add(iconLabel, JLayeredPane.POPUP_LAYER); + jLayeredPane.add(borderUiLabel, JLayeredPane.MODAL_LAYER); + this.add(jLayeredPane); + } + + void refreshIconLabelColor(FineColor fineColor) { + Icon icon = getIcon(fineColor); + refreshIconLabel(icon); + } + + Icon getIcon(FineColor fineColor) { + BufferedImage bufferedImage = HeaderIconBuilder.getIcon(sortRule, fineColor); + Icon icon = new ImageIcon(bufferedImage); + return icon; + } + + void refreshIconLabel(BufferedImage bufferedImage) { + if (bufferedImage != null) { + Icon icon = new SVGIcon(bufferedImage); + refreshIconLabel(icon); + } + } + + void refreshIconLabel(Icon icon) { + if (icon != null) { + iconLabel.removeAll(); + iconLabel.setIcon(icon); + iconLabel.repaint(); + } + } + + UILabel getIconLabel() { + return getIconLabel(new FineColor(defaultColor)); + } + + UILabel getIconLabel(FineColor fineColor) { + Icon svgIcon = getIcon(fineColor); + return new UILabel(svgIcon); + } + + private void showPopupMenu() { + hidePopupMenu(); + colorSelector = this.getColorSelector(); + GUICoreUtils.showPopupMenu(colorSelector, this, 0, this.getSize().height); + } + + @Override + public void hidePopupMenu() { + if (colorSelector != null) { + colorSelector.setVisible(false); + } + colorSelector = null; + } + + private ColorControlWindow getColorSelector() { + return new ColorControlWindow(false, IconButton.this) { + @Override + protected void colorChanged() { + Color color = this.getColor(); + if (color instanceof FineColor) { + fineColor = (FineColor) color; + } else { + fineColor = new FineColor(color); + } + refreshIconLabelColor(fineColor); + hidePopupMenu(); + uiObserverListener.doChange(); + } + }; + } + + + @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.fineColor)); + } + if (desUICheckBox.isSelected()) { + items.add(new SortHeader.SortItem(SortRule.DES, desIconButton.fineColor)); + } + if (nosortUICheckBox.isSelected()) { + items.add(new SortHeader.SortItem(SortRule.NO_SORT, nosortIconButton.fineColor)); + } + 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 0000000000..a68d0eebe6 --- /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/design/webattr/PageToolBarPane.java b/designer-realize/src/main/java/com/fr/design/webattr/PageToolBarPane.java index 48fb0c8ddb..783bc0e6a3 100644 --- a/designer-realize/src/main/java/com/fr/design/webattr/PageToolBarPane.java +++ b/designer-realize/src/main/java/com/fr/design/webattr/PageToolBarPane.java @@ -60,7 +60,7 @@ public class PageToolBarPane extends AbstractEditToolBarPane { private UICheckBox isPageFixedRowBox; private UITextField pageFixedRowCountTextField; private static final Color TIPS_FONT_COLOR = new Color(0x8f8f92); - private static final Pattern ROW_COUNT = Pattern.compile("^[1-9][\\d]{0,2}$"); + private static final Pattern ROW_COUNT = Pattern.compile("^[1-9][\\d]*$|^0"); //固定行数分页,每页最多500行,最少1行数据 private static final int MAX_ROW_COUNT = 500; @@ -275,18 +275,21 @@ public class PageToolBarPane extends AbstractEditToolBarPane { @Override public void keyReleased(KeyEvent e) { String rowCount = pageFixedRowCountTextField.getText(); - if (!isRowCountValid(rowCount)) { - pageFixedRowCountTextField.setText(StringUtils.EMPTY); - } + pageFixedRowCountTextField.setText(convert2ValidRowCount(rowCount)); } }; - private boolean isRowCountValid(String rowCount) { + private String convert2ValidRowCount(String rowCount) { Matcher matcher = ROW_COUNT.matcher(rowCount); if (matcher.find()) { int count = Integer.parseInt(matcher.group()); - return count >= MIN_ROW_COUNT && count <= MAX_ROW_COUNT; + if (count > MAX_ROW_COUNT) { + count = MAX_ROW_COUNT; + } else if (count < MIN_ROW_COUNT) { + count = MIN_ROW_COUNT; + } + return String.valueOf(count); } - return false; + return StringUtils.EMPTY; } } diff --git a/designer-realize/src/main/java/com/fr/design/webattr/PageWebSettingPane.java b/designer-realize/src/main/java/com/fr/design/webattr/PageWebSettingPane.java index 98890f6d8c..1a3d323e9f 100644 --- a/designer-realize/src/main/java/com/fr/design/webattr/PageWebSettingPane.java +++ b/designer-realize/src/main/java/com/fr/design/webattr/PageWebSettingPane.java @@ -41,7 +41,7 @@ public class PageWebSettingPane extends WebSettingPane { private UICheckBox isPageFixedRowBox; private UITextField pageFixedRowCountTextField; private static final Color TIPS_FONT_COLOR = new Color(0x8f8f92); - private static final Pattern ROW_COUNT = Pattern.compile("^[1-9][\\d]{0,2}$"); + private static final Pattern ROW_COUNT = Pattern.compile("^[1-9][\\d]*$|^0"); private static final String DEFAULT_ROW_COUNT = "30"; //固定行数分页,每页最多500行,最少1行数据 @@ -82,9 +82,7 @@ public class PageWebSettingPane extends WebSettingPane { @Override public void keyReleased(KeyEvent e) { String rowCount = pageFixedRowCountTextField.getText(); - if (!isRowCountValid(rowCount)) { - pageFixedRowCountTextField.setText(StringUtils.EMPTY); - } + pageFixedRowCountTextField.setText(convert2ValidRowCount(rowCount)); } }); pageFixedRowCountTextField.addInputMethodListener(new InputMethodListener() { @@ -207,12 +205,17 @@ public class PageWebSettingPane extends WebSettingPane { reportWebAttr.setWebPage(webContent); } - private boolean isRowCountValid(String rowCount) { + private String convert2ValidRowCount(String rowCount) { Matcher matcher = ROW_COUNT.matcher(rowCount); if (matcher.find()) { int count = Integer.parseInt(matcher.group()); - return count >= MIN_ROW_COUNT && count <= MAX_ROW_COUNT; + if (count > MAX_ROW_COUNT) { + count = MAX_ROW_COUNT; + } else if (count < MIN_ROW_COUNT) { + count = MIN_ROW_COUNT; + } + return String.valueOf(count); } - return false; + return StringUtils.EMPTY; } } 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 0ede5114ff..2a4852ee88 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); - } - } - /** * 单元格元素>数据集>高级设置>结果集筛选设置面板 * 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 56b5785784..eea3360bae 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 @@ -10,6 +10,7 @@ import com.fr.base.theme.migrator.FormThemeConfigMigrator; import com.fr.base.theme.migrator.ReportThemeConfigMigrator; 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; @@ -187,6 +188,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() {